基于PaddleDetection的疲劳驾驶检测系统


c++kquote>该项目针对疲劳驾驶问题,利用移动端摄像头实时监测司机状态。通过PaddleDetection等技术部署,推断驾驶员疲劳状态,本地语音提醒并同步报警给管理人员。介绍了数据集处理、模型训练导出,以及在树莓派和Windows系统的部署,还包含信息记录至数据库、可视化界面等功能实现。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

基于paddledetection的疲劳驾驶检测系统 -

项目简介

每一年,中国都因交通事故而造成数万人的死亡,造成了严重的损失。而其中司机疲劳驾驶,是导致事故发生的重要原因之一。但是当司机们陷入疲劳驾驶状态时,往往司机本人对此状态并不在意,甚至会陷入睡眠状态!整治疲劳驾驶行为成为了交通运输行业的首要任务。随着信息技术的日新月异,如今,我们有机会使用信息技术,消除疲劳驾驶的隐患。利用移动端设备的摄像头,我们可以实现实时的监测司机的状态。使用PaddleDetection+PaddleLite部署及Paddle2onnx转IR的OpenVINO部署,实现了通过驾驶员的眼部、嘴部动作实时推断疲劳状态,使得驾驶员能及时的被本地语音方式提醒,避免疲劳驾驶,同时后台管理人员能接收到司机疲劳报警信息。

下载完整代码在本地运行

GitHub链接: FatigueDriving

数据预处理-调整数据集

数据来源:AIStudio公开数据集:疲劳驾驶行为数据集

公开数据集为VOC格式,并划分训练集:验证集:测试集=7:2:1

  • 数据示例:

基于PaddleDetection的疲劳驾驶检测系统 -

In [ ]
# 解压数据集!unzip /home/aistudio/data/data106856/fatigue.zip
In [ ]
# 调整数据集的反斜杠问题f = open('/home/aistudio/fatigue/val_list.txt')
data = f.read()
data2 = data.replace('\', '/')
In [ ]
f1 = open('/home/aistudio/fatigue/val_list.txt','w')
f1.write(data2)
In [1]
# 解压PaddleDetection!unzip /home/aistudio/data/data122193/PaddleDetection.zip
In [1]
# 安装PaddleDetection依赖环境!pip install -r PaddleDetection/requirements.txt

平台1:使用PaddleLite部署至树莓派---模型训练及导出(PaddleLite)

ARM下部署选用了ssd算法,转为nb模型后使用PaddleLite做部署

In [ ]
# 模型训练# 修改ssdlite_mobilenet_v3_small_320_coco.yml中数据集格式为'../datasets/voc.yml', 并将'../datasets/voc.yml'里的数据路径改为当前数据集目录,以适配疲劳驾驶数据集!python PaddleDetection/tools/train.py -c PaddleDetection/configs/ssd/ssdlite_mobilenet_v3_small_320_coco.yml --use_vdl=True --eval
In [ ]
!python PaddleDetection/tools/infer.py -c PaddleDetection/configs/ssd/ssdlite_mobilenet_v3_small_320_coco.yml   
                        -o weights=output/ssdlite_mobilenet_v3_small_320_coco/best_model.pdparams 
                        --infer_img= ./0.jpg #(需要检测的图片)
In [ ]
# 导出ssd模型python PaddleDetection/tools/export_model.py -c PaddleDetection/configs/ssd/ssdlite_mobilenet_v3_small_320_coco.yml 
                            --output_dir=./ssd_inference_model 
                            -o weights=output/ssdlite_mobilenet_v3_small_320_coco/best_models.pdparams
In [2]
# 安装PaddleLite!pip install paddlelite
In [3]
# 转换为PaddleLite部署需要的nb模型!paddle_lite_opt 
    --model_file=ssd_inference_model/ssdlite_mobilenet_v3_small_320_coco/model.pdmodel 
    --param_file=ssd_inference_model/ssdlite_mobilenet_v3_small_320_coco/model.pdiparams 
    --optimize_out=ssd_inference_model/ssdlite_mobilenet_v3_small_320_coco/model 
    --optimize_out_type=naive_buffer 
    --valid_targets=arm

PaddleLite推理部分代码

// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////     http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.#include "paddle_api.h"#include <arm_neon.h>#include <opencv2/opencv.hpp>#include <opencv2/highgui.hpp>#include <opencv2/core/core.hpp>#include <stdio.h>#include <sys/time.h>#include <unistd.h>#include <vector>#include <limits>#include <fstream>//#include <wiringPi.h>int WARMUP_COUNT = 0;int REPEAT_COUNT = 1;const int CPU_THREAD_NUM = 2;const paddle::lite_api::PowerMode CPU_POWER_MODE =
    paddle::lite_api::PowerMode::LITE_POWER_HIGH;const std::vector<int64_t> INPUT_SHAPE = {1, 3, 320, 320}; //输入形状const std::vector<float> INPUT_MEAN = {0.5f, 0.5f, 0.5f};  //输入平均值const std::vector<float> INPUT_STD = {0.5f, 0.5f, 0.5f};   //输入标准const float SCORE_THRESHOLD = 0.5f;                        //分数阈值const std::string file_number = "434343434343";            //用户编号struct RESULT {
  std::string class_name;  float score;  float left;  float top;  float right;  float bottom;
};// 获取时间inline int64_t get_current_us() {  struct timeval time;
  gettimeofday(&time, NULL);  return 1000000LL * (int64_t)time.tv_sec + (int64_t)time.tv_usec;
}// 年月日时分秒static std::string getCurrentTimeStr(){	time_t t = time(NULL);	char ch[64] = {0};	strftime(ch, sizeof(ch) - 1, "%Y%m%d%H%M", localtime(&t));     //年-月-日-时-分
	return ch;
}// 加载标签std::vector<std::string> load_labels(const std::string &path) {
  std::ifstream file;
  std::vector<std::string> labels;
  file.open(path);  while (file) {
    std::string line;
    std::getline(file, line);
    labels.push_back(line);
  }
  file.clear();
  file.close();  return labels;
}// 预处理void preprocess(cv::Mat &input_image, const std::vector<float> &input_mean,                const std::vector<float> &input_std, int input_width,                int input_height, float *input_data) {
  cv::Mat resize_image;
  cv::resize(input_image, resize_image, cv::Size(input_width, input_height), 0, 0);  if (resize_image.channels() == 4) {
    cv::cvtColor(resize_image, resize_image, 3);
  }
  cv::Mat norm_image;
  resize_image.convertTo(norm_image, CV_32FC3, 1 / 255.f);  // NHWC->NCHW
  int image_size = input_height * input_width;  const float *image_data = reinterpret_cast<const float *>(norm_image.data);  float32x4_t vmean0 = vdupq_n_f32(input_mean[0]);  float32x4_t vmean1 = vdupq_n_f32(input_mean[1]);  float32x4_t vmean2 = vdupq_n_f32(input_mean[2]);  float32x4_t vscale0 = vdupq_n_f32(1.0f / input_std[0]);  float32x4_t vscale1 = vdupq_n_f32(1.0f / input_std[1]);  float32x4_t vscale2 = vdupq_n_f32(1.0f / input_std[2]);  float *input_data_c0 = input_data;  float *input_data_c1 = input_data + image_size;  float *input_data_c2 = input_data + image_size * 2;  int i = 0;  for (; i < image_size - 3; i += 4) {    float32x4x3_t vin3 = vld3q_f32(image_data);    float32x4_t vsub0 = vsubq_f32(vin3.val[0], vmean0);    float32x4_t vsub1 = vsubq_f32(vin3.val[1], vmean1);    float32x4_t vsub2 = vsubq_f32(vin3.val[2], vmean2);    float32x4_t vs0 = vmulq_f32(vsub0, vscale0);    float32x4_t vs1 = vmulq_f32(vsub1, vscale1);    float32x4_t vs2 = vmulq_f32(vsub2, vscale2);    vst1q_f32(input_data_c0, vs0);    vst1q_f32(input_data_c1, vs1);    vst1q_f32(input_data_c2, vs2);
    image_data += 12;
    input_data_c0 += 4;
    input_data_c1 += 4;
    input_data_c2 += 4;
  }  for (; i < image_size; i++) {
    *(input_data_c0++) = (*(image_data++) - input_mean[0]) / input_std[0];
    *(input_data_c0++) = (*(image_data++) - input_mean[1]) / input_std[1];
    *(input_data_c0++) = (*(image_data++) - input_mean[2]) / input_std[2];
  }
}// 后处理std::vector<RESULT> postprocess(const float *output_data, int64_t output_size,                                const std::vector<std::string> &word_labels,                                const float score_threshold,
                                cv::Mat &output_image, double time) {
  std::vector<RESULT> results;
  std::vector<cv::Scalar> colors = {
      cv::Scalar(237, 189, 101), cv::Scalar(0, 0, 255), cv::Scalar(102, 153, 153),
      cv::Scalar(255, 0, 0), cv::Scalar(9, 255, 0), cv::Scalar(0, 0, 0),
      cv::Scalar(51, 153, 51)};  for (int64_t i = 0; i < output_size; i += 6) {    if (output_data[i + 1] < score_threshold) {      continue;
    }    int class_id = static_cast<int>(output_data[i]);    float score = output_data[i + 1];
    RESULT result;
    std::string class_name = "Unknown";    if (word_labels.size() > 0 && class_id >= 0 && 
        class_id < word_labels.size()) {
      class_name = word_labels[class_id];
    }
    result.class_name = class_name;
    result.score = score;
    result.left = output_data[i + 2];
    result.top = output_data[i + 3];
    result.right = output_data[i + 4];
    result.bottom = output_data[i + 5];    int lx = static_cast<int>(result.left * output_image.cols);    int ly = static_cast<int>(result.top * output_image.rows);    int w = static_cast<int>(result.right * output_image.cols) - lx;    int h = static_cast<int>(result.bottom * output_image.rows) - ly;
    cv::Rect bounding_box = cv::Rect(lx, ly, w, h) &
        cv::Rect(0, 0, output_image.cols, output_image.rows);    if (w > 0 && h > 0 && score <= 1) {
      cv::Scalar color = colors[results.size() % colors.size()];
      cv::rectangle(output_image, bounding_box, color);
      cv::rectangle(output_image, cv::Point2d(lx, ly), cv::Point2d(lx + w, ly - 10),
                    color, -1);
      cv::putText(output_image,
                  std::to_string(results.size()) + "." + class_name + ":" +
                      std::to_string(score),
                  cv::Point2d(lx, ly), cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(255, 255, 255));
      results.push_back(result);
    }
  }  return results;
}//识别处理cv::Mat process(cv::Mat &input_image,
                std::vector<std::string> &word_labels,
                std::shared_ptr<paddle::lite_api::PaddlePredictor> &predictor) {  // 对图像进行预处理,填充输入张量数据
  std::unique_ptr<paddle::lite_api::Tensor> input_tensor(
      std::move(predictor->GetInput(0)));
  input_tensor->Resize(INPUT_SHAPE);  int input_width = INPUT_SHAPE[3];  int input_height = INPUT_SHAPE[2];  auto *input_data = input_tensor->mutable_data<float>();  double preprocess_start_time = get_current_us();  preprocess(input_image, INPUT_MEAN, INPUT_STD, input_width, input_height,
             input_data);  double preprocess_end_time = get_current_us();  double preprocess_time = (preprocess_end_time - preprocess_start_time) / 1000.0f;  double prediction_time;  // 运行预测
  for (int i = 0; i < WARMUP_COUNT; i++) {
    predictor->Run();
  }  double max_time_cost = 0.0f;  double min_time_cost = std::numeric_limits<float>::max();  double total_time_cost = 0.0f;  for (int i = 0; i < REPEAT_COUNT; i++) {    auto start = get_current_us();
    predictor->Run();    auto end = get_current_us();    double cur_time_cost = (end - start) / 1000.0f;    if (cur_time_cost > max_time_cost) {
      max_time_cost = cur_time_cost;
    }    if (cur_time_cost < min_time_cost) {
      min_time_cost = cur_time_cost;
    }
    total_time_cost += cur_time_cost;
    prediction_time = total_time_cost / REPEAT_COUNT;    printf("iter %d cost: %f ms
", i, cur_time_cost);
  }  printf("warmup: %d repeat: %d, *erage: %f ms, max: %f ms, min: %f ms
",
         WARMUP_COUNT, REPEAT_COUNT, prediction_time,
         max_time_cost, min_time_cost);  // 获取输出张量数据,进行后处理,输出检测对象
  std::unique_ptr<const paddle::lite_api::Tensor> output_tensor(
      std::move(predictor->GetOutput(0)));  const float *output_data = output_tensor->mutable_data<float>();  int64_t output_size = 1;  for (auto dim : output_tensor->shape()) {
    output_size *= dim;
  }
  cv::Mat output_image = input_image.clone();  double postprocess_start_time = get_current_us();
  std::vector<RESULT> results = postprocess(
      output_data, output_size, word_labels, SCORE_THRESHOLD, output_image, prediction_time);  double postprocess_end_time = get_current_us();  double postprocess_time = (postprocess_end_time - postprocess_start_time) / 1000.0f;  
  // wiringPi 
  //wiringPiSetup();
  std::string warning_content_0 = "closed_eye";
  std::string warning_content_1 = "open_mouth";
  std::string time_ymdhms = getCurrentTimeStr();  
  // 结果输出
  printf("results: %d
", results.size());  for (int i = 0; i < results.size(); i++) {  // GPIO 0 高电平输出触发蜂鸣器
  // pinMode(0,OUTPUT);
	// 存储图像
    if (results[i].class_name.c_str()==warning_content_0)
    {
      std::string output_path = "./fatigueDriving/screenshots/Q" + file_number + time_ymdhms + warning_content_0 + ".jpg";
      cv::imwrite(output_path,output_image);
    }    if (results[i].class_name.c_str()==warning_content_1){
      std::string output_path = "./fatigueDriving/screenshots/Q" + file_number + time_ymdhms + warning_content_1 + ".jpg";
      cv::imwrite(output_path,output_image);
    }    // if (results[i].class_name.c_str()==warning_content){digitalWrite(0,HIGH);delay(20);digitalWrite(0,LOW);delay(1);cv::imwrite(output_path,output_image);delay(1);}
    // else{digitalWrite(0,LOW);delay(1);}
    printf("[%d] %s - %f %f,%f,%f,%f
", i, results[i].class_name.c_str(),
           results[i].score, results[i].left, results[i].top, results[i].right,
           results[i].bottom);
  }  printf("Preprocess time: %f ms
", preprocess_time);  printf("Prediction time: %f ms
", prediction_time);  printf("Postprocess time: %f ms

", postprocess_time);  return output_image;
}int main(int argc, char **argv) {  // 加载模型地址
  std::string model_path = argv[1];  // 加载标签地址
  std::string label_path = argv[2];  // 加载标签
  std::vector<std::string> word_labels = load_labels(label_path);  // 加载模型
  paddle::lite_api::MobileConfig config;
  config.set_model_from_file(model_path);
  config.set_threads(CPU_THREAD_NUM);
  config.set_power_mode(CPU_POWER_MODE);

  std::shared_ptr<paddle::lite_api::PaddlePredictor> predictor =
      paddle::lite_api::CreatePaddlePredictor<paddle::lite_api::MobileConfig>(config);  // 视频流预测
  cv::VideoCapture cap(-1);
  cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);
  cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);  // 判断是否开启摄像头
  if (!cap.isOpened()) {    return -1;
  }  // 执行
  while (1) {
    cv::Mat input_image;
    cap >> input_image;
    cv::Mat output_image = process(input_image, word_labels, predictor);
    cv::imshow("Real-Time", output_image);    if (cv::waitKey(1) == char('q')) {      break;
    }
  }
  cap.release();
  cv::destroyAllWindows();  return 0;
}

平台2:使用OpenVINO部署至Windows系统---模型训练及模型导出

IntelCPU下部署选用了yolov3算法,转为IR模型后使用OpenVINO做部署,可使用核显加速

In [ ]
# 模型训练!python PaddleDetection/tools/train.py -c PaddleDetection/configs/yolov3/yolov3_mobilenet_v3_large_270e_voc.yml --use_vdl=True --eval
In [ ]
!python PaddleDetection/tools/infer.py -c PaddleDetection/configs/yolov3/yolov3_mobilenet_v3_large_270e_voc.yml   
                        -o weights=output/yolov3_mobilenet_v3_large_270e_voc/best_model.pdparams 
                        --infer_img= ./0.jpg #(需要检测的图片)
In [ ]
# 安装paddle2onnx%cd /home/aistudio/# !git clone https://github.com/PaddlePaddle/Paddle2ONNX.git!unzip Paddle2ONNX-develop.zip%cd Paddle2ONNX-develop# !git checkout release/0.9!python setup.py install

%cd experimental
In [2]
!pip install onnx
In [8]
import paddle2onnximport paddlefrom openvino_ppdet import nms_mapper# 通过上面的`nms_mapper`的import来启用插件,替换了paddle2onnx原始的nms_mappermodel_prefix = "/home/aistudio/yolov3-output/yolov3_mobilenet_v3_large_270e_voc/" # 一直写到模型文件名model = paddle.jit.load(model_prefix)
input_shape_dict = {    "image": [1, 3, 608, 608],    "scale_factor": [1, 2],    "im_shape": [1, 2]
    }
onnx_model = paddle2onnx.run_convert(model, input_shape_dict=input_shape_dict, opset_version=11)with open("./yolov3.onnx", "wb") as f:
    f.write(onnx_model.SerializeToString())

到此步骤后我们可以得到XXX.onnx模型文件,再使用OpenVINO的mo命令转换为IR模型文件。具体操作请参照OpenVINO使用文档

简小派 简小派

简小派是一款AI原生求职工具,通过简历优化、岗位匹配、项目生成、模拟面试与智能投递,全链路提升求职成功率,帮助普通人更快拿到更好的 offer。

简小派 123 查看详情 简小派

OpenVINO推理部分代码

#include "fatigueDriving.h"fatigueDriving::fatigueDriving() {};
fatigueDriving::~fatigueDriving() {};int fatigueDriving::Init(std::string modelPath, bool useIntelgpu){
	std::string xmlPath, binPath;	// 加载模型
	std::cout << "Loading model ... " << std::endl;
	xmlPath = modelPath + "/yolov3.xml";
	binPath = modelPath + "/yolov3.bin";

	network = ie.ReadNetwork(xmlPath, binPath);	// 载至cpu/gpu
	try {
		executableNetwork = ie.LoadNetwork(network, useIntelgpu ? "GPU" : "CPU");
		std::cout << "Loading model succeeded!" << std::endl;
	}	catch (...) {		return -2;
	}	// 构建预测
	inferRequest = executableNetwork.CreateInferRequest();	// 获取输入输出的Blob
	inputImage = inferRequest.GetBlob("image");
	inputImShape = inferRequest.GetBlob("im_shape");
	inputScaleFactor = inferRequest.GetBlob("scale_factor");
	outputInfo = inferRequest.GetBlob("translated_layer/scale_0.tmp_0");	// 输入尺寸
	inputChannelsNumber = inputImage->getTensorDesc().getDims()[1];
	inputHeight = inputImage->getTensorDesc().getDims()[2];
	inputWidth = inputImage->getTensorDesc().getDims()[3];	// 输出尺寸
	outputBboxesNumber = outputInfo->getTensorDesc().getDims()[0];
	outputSingleInfo = outputInfo->getTensorDesc().getDims()[1];	return 1;
}int fatigueDriving::Process(const cv::Mat img, std::vector<std::vector<float>> &outputs, float scoreThreshold){	if (!img.data)return -1;//判断是否有数据
	std::vector<float> mean;
	mean.push_back(0.485f);
	mean.push_back(0.456f);
	mean.push_back(0.406f);
	std::vector<float> std;
	std.push_back(0.229f);
	std.push_back(0.224f);
	std.push_back(0.225f);
	cv::Mat image;
	cv::cvtColor(img, image, cv::COLOR_BGR2RGB);
	cv::resize(image, image, cv::Size(inputWidth, inputHeight));	// HWC =》NCHW
	float* data = static_cast<float*>(inputImage->buffer());	size_t image_size = inputHeight * inputWidth;	for (size_t row = 0; row < inputHeight; ++row) {		for (size_t col = 0; col < inputWidth; ++col) {			for (size_t ch = 0; ch < inputChannelsNumber; ++ch) {
				data[image_size * ch + row * inputWidth + col] = ((image.at<cv::Vec3b>(row, col)[ch]) / 255.0f) - float(mean[ch]) / std[ch];
			}
		}
	}    // 输入尺寸
	float* im_shape = static_cast<float*>(inputImShape->buffer());
	im_shape[0] = image.rows;
	im_shape[1] = image.cols;	// 缩放因子
	float* scale_factor = static_cast<float*>(inputScaleFactor->buffer());
	scale_factor[0] = inputHeight / float(img.rows);
	scale_factor[1] = inputWidth / float(img.cols);	// 预测
	clock_t time_start = clock();
	inferRequest.Infer();	clock_t time_temp = clock();	// 获取输出
	std::vector<float> output;	auto output_data = outputInfo->buffer().as<InferenceEngine::PrecisionTrait<InferenceEngine::Precision::FP32>::value_type*>();	for (int i = 0; i < outputBboxesNumber; i++) {		for (int j = 0; j < outputSingleInfo; j++) {
			output.push_back(output_data[i * outputSingleInfo + j]);
		}		if (output[1] > scoreThreshold) {
			outputs.push_back(output);
		}
		output.clear();
	}	return 1;
}

c++版OpenVINO部署转python接口

#include <pybind11/stl.h>#include <pybind11/cast.h>#include <pybind11/stl_bind.h>#include <pybind11/numpy.h>#include "fatigueDriving.h"namespace py = pybind11;py::array ConvertMatToNDArray(cv::Mat& m);

PYBIND11_MODULE(pyFatigueDriving, m)
{

	m.attr("__doc__") = "paddle interface";
	m.attr("__version__") = "v0.1.0";
	m.def("ConvertNDArrayToMat", [](py::array_t<uchar>& input_data)
		{			cv::Mat dst = ConvertNDArrayToMat(input_data);
			return dst;
		}, py::arg("input_data"));	py::class_<cv::Mat>(m, "cvMat");	py::class_<fatigueDriving>(m, "fatigueDriving")
		.def(py::init<>())
		.def("Init", &fatigueDriving::Init)
		.def("Process", [](fatigueDriving& vc, const cv::Mat& img, float scoreThreshold)
			{				std::vector<std::vector<float>> outputs;
				int ret = vc.Process(img, outputs, scoreThreshold);
				return py::make_tuple(ret, outputs);
			}, py::arg("img"), py::arg("scoreThreshold"));
}

实时检测驾驶员:违规时,信息写入数据库+语音提示

通过检测部分的存储违规图像动作,触发语音提示及信息记录功能

PC端 - main.py

In [ ]
import osimport _threadimport sysimport timeimport threadingimport cv2import numpy as npimport pygamefrom PyQt5 import QtWidgetsfrom PyQt5.QtWidgets import QApplication, QDialog, QMainWindowfrom watchdog.events import *from watchdog.observers import Observerfrom MySQL_Connect import MySQL_Connect# 加载openvino部署封装的dll及pydos.add_dll_directory(os.path.join(os.getcwd(), "./OpenVINO/dlls/"))
sys.path.append(os.path.join(os.getcwd(), "./OpenVINO/libs/"))import pyFatigueDriving# 播放警示音频class Play_Audio():
    def __init__(self, audio):
        self.audio = audio    def run(self):
        pygame.mixer.init()
        pygame.mixer.music.load(self.audio)  # './audio/warning.mp3'
        pygame.mixer.music.play()
        time.sleep(7)
        pygame.mixer.music.stop()class MyDirEventHandler(FileSystemEventHandler):

    def __init__(self):
        FileSystemEventHandler.__init__(self)
        self.audio = './audio/warning.mp3'
        self.warning = Play_Audio(self.audio)    def on_created(self, event):
        
        print("file created:{0}".format(event.src_path))
        a = str(event.src_path)
        self.warning.run()# 转换为可存储到数据库的格式def s*e_received_info(user_info, iolations_time, new_filename):
    user_all_info = {}
    user_all_info['编号'] = user_info[0]
    user_all_info['姓名'] = user_info[1]
    user_all_info['性别'] = user_info[2]
    user_all_info['年龄'] = user_info[3]
    user_all_info['身份证号'] = user_info[4]
    user_all_info['联系电话'] = user_info[5]
    user_all_info['省份'] = user_info[6]
    user_all_info['城市'] = user_info[7]
    user_all_info['区/县'] = user_info[8]
    user_all_info['车型'] = user_info[9]
    user_all_info['行驶证编号'] = user_info[10]
    user_all_info['车牌号'] = user_info[11]
    user_all_info['违规时间'] = iolations_time
    user_all_info['违规证据图像位置'] = new_filename    print(user_all_info)    return user_all_info# 信息记录至SQLdef ToSQL(a, module_name):
    # 初始化SQL
    MySQL = MySQL_Connect()    # 拉取用户数据
    number = module_name[1:13]
    iolations_time = module_name[13:17]+'-'+module_name[17:19] +         '-'+module_name[19:21]+' '+module_name[21:23]+':'+module_name[23:25]
    user_info = MySQL.MC_SELECT_User_Info(local_info=number)[0]    # 生成数据列表
    user_list_violation_info = s*e_received_info(
        user_info, iolations_time, a)
    MySQL.MC_S*e_Violation_Info(user_list_violation_info)# 执行预测def run_detection_win_py(s*epath):
    file_number = "434343434343"
    cap =cv2.VideoCapture(0)    while(True):
        nowtime = time.strftime("%Y%m%d%H%M%S")
        ret , frame =cap.read()
        ret, output = fd.Process(pyFatigueDriving.ConvertNDArrayToMat(frame), 0.1)        for single_info in output:
            cv2.rectangle(frame, (int(single_info[2]), int(single_info[3])), (int(single_info[4]), int(single_info[5])), (0, 0, 255), 1, 4)
            label = str(int(single_info[0])) + ': ' + str(single_info[1])
            cv2.putText(frame, label, (int(single_info[2]), int(single_info[3])), cv2.FONT_HERSHEY_COMPLEX, 2, (0, 0, 255), 1, 4)            if int(single_info[0]) == 0:
                module_name = 'Q' + file_number + nowtime + str(single_info[0]) + '.jpg'
                s*efile = s*epath + module_name
                cv2.imwrite(s*efile, frame)
                ToSQL(s*efile, module_name)                break
            if int(single_info[0]) == 3:                if ((single_info[5]-single_info[3])/(single_info[4]-single_info[2])>=0.9):
                    module_name = 'Q' + file_number + nowtime + str(single_info[0]) + '.jpg'
                    s*efile = s*epath + module_name
                    cv2.imwrite(s*efile, frame)
                    ToSQL(s*efile, module_name)                    break
        cv2.imshow("real-time", frame)        if cv2.waitKey(1) & 0xFF == ord('q'):            break
    cap.release()
    cv2.destroyAllWindows()# 监控文件的变化def run_scan_file(file_name):
    # 创建观察者对象
    observer = Observer()    # 创建事件处理对象
    fileHandler = MyDirEventHandler()    # 为观察者设置观察对象与处理事件对象
    observer.schedule(
        fileHandler, file_name, True)
    observer.start()    try:        while True:
            time.sleep(2)    except KeyboardInterrupt:
        observer.stop()
    observer.join()if __name__ == '__main__':
    fd = pyFatigueDriving.fatigueDriving()
    modelPath = "./models/yolov3_ir"
    useIntelGPU = False
    ret = fd.Init(modelPath, useIntelGPU)    try:        # 识别线程
        s*epath="./screenshots/"
        getDetect = threading.Thread(target=run_detection_win_py, args=(s*epath, ))
        getDetect.start()        # 警示线程
        file_name="C:/project/FatigueDriving/screenshots"
        getWarning = threading.Thread(target=run_scan_file, args=(file_name, ))
        getWarning.start()    except Exception as e:        print("多线程异常,异常信息:{}".format(e))

移动端 - arm_main.py

In [ ]
import osimport _threadimport sysimport timeimport threadingimport cv2import numpy as npimport pygamefrom PyQt5 import QtWidgetsfrom PyQt5.QtWidgets import QApplication, QDialog, QMainWindowfrom watchdog.events import *from watchdog.observers import Observerfrom MySQL_Connect import MySQL_Connect# 执行预测-raspi端def run_detection_raspi(sh_name):
    subprocess.run(sh_name, shell=True)# 转换为可存储到数据库的格式def s*e_received_info(user_info, iolations_time, new_filename):
    user_all_info = {}
    user_all_info['编号'] = user_info[0]
    user_all_info['姓名'] = user_info[1]
    user_all_info['性别'] = user_info[2]
    user_all_info['年龄'] = user_info[3]
    user_all_info['身份证号'] = user_info[4]
    user_all_info['联系电话'] = user_info[5]
    user_all_info['省份'] = user_info[6]
    user_all_info['城市'] = user_info[7]
    user_all_info['区/县'] = user_info[8]
    user_all_info['车型'] = user_info[9]
    user_all_info['行驶证编号'] = user_info[10]
    user_all_info['车牌号'] = user_info[11]
    user_all_info['违规时间'] = iolations_time
    user_all_info['违规证据图像位置'] = new_filename    print(user_all_info)    return user_all_info# 信息记录至SQLdef ToSQL(a, module_name):
    # 初始化SQL
    MySQL = MySQL_Connect()    # 拉取用户数据
    number = module_name[1:13]
    iolations_time = module_name[13:17]+'-'+module_name[17:19] +         '-'+module_name[19:21]+' '+module_name[21:23]+':'+module_name[23:25]
    user_info = MySQL.MC_SELECT_User_Info(local_info=number)[0]    # 生成数据列表
    user_list_violation_info = s*e_received_info(
        user_info, iolations_time, a)

    MySQL.MC_S*e_Violation_Info(user_list_violation_info)# 播放警示音频class Play_Audio():
    def __init__(self, audio):
        self.audio = audio    def run(self):
        pygame.mixer.init()
        pygame.mixer.music.load(self.audio)  # './audio/warning.mp3'
        pygame.mixer.music.play()
        time.sleep(3)
        pygame.mixer.music.stop()class MyDirEventHandler(FileSystemEventHandler):

    def __init__(self):
        FileSystemEventHandler.__init__(self)
        self.audio = './audio/warning.mp3'
        self.warning = Play_Audio(self.audio)    def on_created(self, event):

        print("file created:{0}".format(event.src_path))
        a = str(event.src_path)        #
        self.warning.run(self.audio)

        directory, module_name = os.path.split(a)
        module_name = os.path.splitext(module_name)[0]

        ToSQL(a, module_name)# 监控文件的变化def run_scan_file(file_name):
    # 创建观察者对象
    observer = Observer()    # 创建事件处理对象
    fileHandler = MyDirEventHandler()    # 为观察者设置观察对象与处理事件对象
    observer.schedule(
        fileHandler, file_name, True)
    observer.start()    try:        while True:
            time.sleep(2)    except KeyboardInterrupt:
        observer.stop()
    observer.join()"""
多线程
run_detection 执行预测程序
run_scan_file 监控文件的变化
"""if __name__ == '__main__':    try:        # 识别线程
        command='./real_time.sh'
        getDetect = threading.Thread(target=run_detection_raspi, args=(command, ))
        getDetect.start()        # 警示线程
        file_name="C:/project/FatigueDriving/screenshots"
        getWarning = threading.Thread(target=run_scan_file, args=(file_name, ))
        getWarning.start()    except Exception as e:        print("多线程异常,异常信息:{}".format(e))

数据库接入 - MySQL_Connect.py

In [ ]
class MySQL_Connect():
    def __init__(self):
        self.write_jud_user_info = 1
        self.write_user_info = "insert into `user_info` values("
        self.write_jud_violation_info = 1
        self.write_violation_info = "insert into `violation_info` values("

        # 加载数据库
        try:
            self._con = sql.Connect(
                host="localhost",
                user="root",
                password="yours",
                database="yours",
                port=<yoursport>,
                charset='utf8'
                )        except Exception as e:            print("ERROR: " + e)
            self._con.close()            #pass

    # 编号判断
    def MC_Number_Judge(self, number):
        if len(number) != 12:            return False
        else:            return True

    # 性别判断
    def MC_Sex_Judge(self, sex):
        if sex != '男' and sex != '女':            return False
        else:            return True

    # 身份证判断
    def MC_Id_Card_Judge(self, id):
        if len(id) != 18:            return False
        else:            return True

    # 电话号判断
    def MC_Phone_Judge(self, tel):
        if len(tel) != 11:            return False
        else:            return True

    # 行驶证编号判断
    def MC_Driver_Licenise_Number_Judge(self, num):
        if len(num) != 12:            return False
        else:            return True

    # 车牌号判断
    def MC_Licenise_Number_Judge(self, num):
        if len(num) != 7:            return False
        else:            return True


    '''----------------------- 用户信息 -----------------------'''
    # 写入用户信息
    def MC_S*e_User_Info(self, list_user_info):
        self.list_user_info = list_user_info
        cursor = self._con.cursor()        if self.MC_Number_Judge(self.list_user_info['编号']):
            self.MC_Insert_User_Info(self.list_user_info['编号'])
        self.MC_Insert_User_Info(self.list_user_info['姓名'])        if self.MC_Sex_Judge(self.list_user_info['性别']):
            self.MC_Insert_User_Info(self.list_user_info['性别'])
        self.MC_Insert_User_Info(self.list_user_info['年龄'])        if self.MC_Id_Card_Judge(self.list_user_info['身份证号']):
            self.MC_Insert_User_Info(self.list_user_info['身份证号'])        if self.MC_Phone_Judge(self.list_user_info['联系电话']):
            self.MC_Insert_User_Info(self.list_user_info['联系电话'])
        self.MC_Insert_User_Info(self.list_user_info['省份'])
        self.MC_Insert_User_Info(self.list_user_info['城市'])
        self.MC_Insert_User_Info(self.list_user_info['区/县'])
        self.MC_Insert_User_Info(self.list_user_info['车型'])        if self.MC_Driver_Licenise_Number_Judge(self.list_user_info['行驶证编号']):
            self.MC_Insert_User_Info(self.list_user_info['行驶证编号'])        if self.MC_Licenise_Number_Judge(self.list_user_info['车牌号']):
            self.MC_Insert_User_Info(self.list_user_info['车牌号'])

        self.write_user_info += ")"
        print(self.write_user_info)
        cursor.execute(self.write_user_info)
        self._con.commit()
        cursor.close()
        self.list_user_info.clear()    # 读取数据库信息
    def MC_Read_User_Info(self):
        try:            # 创建游标对象
            cursor = self._con.cursor()

            sql = 'SELECT * FROM `user_info`'
            cursor.execute(sql)
            result = cursor.fetchall()
            cursor.close()        except Exception as e:            print("ERROR: " + e)
            self._con.rollback()
            cursor.close()        return result    # 数据库语言 数据插入
    def MC_Insert_User_Info(self, new):
        if self.write_jud_user_info != 1:
            self.write_user_info += ", "
        self.write_user_info += "'" + new + "'"
        self.write_jud_user_info += 1
    
    # 根据单个变量查询
    def MC_SELECT_User_Info(self, local_info):
        #self.local_info = '434343434343'
        self.local_info = local_info        try:            # 创建游标对象
            cursor = self._con.cursor()

            sql = "SELECT * FROM `user_info` WHERE number=%s" % self.local_info
            cursor.execute(sql)
            result = cursor.fetchall()
            cursor.close()        except Exception as e:            print("ERROR: " + e)
            self._con.rollback()
            cursor.close()        return result    '''----------------------- 违规记录 -----------------------'''
    # 写入违规记录
    def MC_S*e_Violation_Info(self, list_violation_info):
        self.list_violation_info = list_violation_info
        cursor = self._con.cursor()        if self.MC_Number_Judge(self.list_violation_info['编号']):
            self.MC_Insert_Violation_Info(self.list_violation_info['编号'])
        self.MC_Insert_Violation_Info(self.list_violation_info['姓名'])        if self.MC_Sex_Judge(self.list_violation_info['性别']):
            self.MC_Insert_Violation_Info(self.list_violation_info['性别'])
        self.MC_Insert_Violation_Info(self.list_violation_info['年龄'])        if self.MC_Id_Card_Judge(self.list_violation_info['身份证号']):
            self.MC_Insert_Violation_Info(self.list_violation_info['身份证号'])        if self.MC_Phone_Judge(self.list_violation_info['联系电话']):
            self.MC_Insert_Violation_Info(self.list_violation_info['联系电话'])
        self.MC_Insert_Violation_Info(self.list_violation_info['省份'])
        self.MC_Insert_Violation_Info(self.list_violation_info['城市'])
        self.MC_Insert_Violation_Info(self.list_violation_info['区/县'])
        self.MC_Insert_Violation_Info(self.list_violation_info['车型'])        if self.MC_Driver_Licenise_Number_Judge(self.list_violation_info['行驶证编号']):
            self.MC_Insert_Violation_Info(self.list_violation_info['行驶证编号'])        if self.MC_Licenise_Number_Judge(self.list_violation_info['车牌号']):
            self.MC_Insert_Violation_Info(self.list_violation_info['车牌号'])
        self.MC_Insert_Violation_Info(self.list_violation_info['违规时间'])
        self.MC_Insert_Violation_Info(self.list_violation_info['违规证据图像位置'])

        self.write_violation_info += ")"
        print(self.write_violation_info)
        cursor.execute(self.write_violation_info)
        self._con.commit()
        cursor.close()
        self.list_violation_info.clear()    # 读取数据库信息
    def MC_Read_Violation_Info(self):
        try:            # 创建游标对象
            cursor = self._con.cursor()

            sql = 'SELECT * FROM `violation_info`'
            cursor.execute(sql)
            result = cursor.fetchall()
            cursor.close()        except Exception as e:            print("ERROR: " + e)
            self._con.rollback()
            cursor.close()        return result    # 数据库语言 信息插入
    def MC_Insert_Violation_Info(self, new):
        if self.write_jud_violation_info != 1:
            self.write_violation_info += ", "
        self.write_violation_info += "'" + new + "'"
        self.write_jud_violation_info += 1

可视化界面(GUI)

违规信息查询主界面 - Server_MainGUI.py

In [ ]
# 子窗口 -- 信息录入class Ui_Info_Entry_Child(Ui_Info_Entry):
    """docstring for Ui_Info_Entry_Child"""
    def __init__(self):
        super(Ui_Info_Entry_Child, self).__init__()
        self.setupUi(self)# 子窗口 -- 违规信息可视化class Ui_EvidenceIm_Child(Ui_EvidenceIm):
    """docstring for Ui_EvidenceIm_Child"""

    def __init__(self, impath, oneinfo):
        super(Ui_EvidenceIm_Child, self).__init__(impath,oneinfo)
        self.setupUi(self)
        self.impath = impath
        self.oneinfo = oneinfo# 主窗口 -- 数据库信息可视化class Ui_MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()        #self.line = 5
        self.row_num = 1
        self.MainWindow = QtWidgets.QMainWindow()
        self.Info_Entry_Windows = Ui_Info_Entry_Child()
        self.setupUi(self.MainWindow)    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1455, 969)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")        # 省份
        self.server_label_province = QtWidgets.QLabel(self.centralwidget)
        self.server_label_province.setGeometry(QtCore.QRect(0, 10, 51, 21))
        self.server_label_province.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.server_label_province.setObjectName("server_label_province")
        self.server_province = QtWidgets.QComboBox(self.centralwidget)
        self.server_province.setGeometry(QtCore.QRect(60, 10, 111, 22))
        self.server_province.setObjectName("server_province")        # 市/州
        self.server_label_city = QtWidgets.QLabel(self.centralwidget)
        self.server_label_city.setGeometry(QtCore.QRect(190, 10, 51, 21))
        self.server_label_city.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.server_label_city.setObjectName("server_label_city")
        self.server_city = QtWidgets.QComboBox(self.centralwidget)
        self.server_city.setGeometry(QtCore.QRect(250, 10, 111, 22))
        self.server_city.setObjectName("server_city")        # 区县
        self.server_label_borough = QtWidgets.QLabel(self.centralwidget)
        self.server_label_borough.setGeometry(QtCore.QRect(380, 10, 51, 21))
        self.server_label_borough.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.server_label_borough.setObjectName("server_label_borough")
        self.server_borough = QtWidgets.QComboBox(self.centralwidget)
        self.server_borough.setGeometry(QtCore.QRect(440, 10, 111, 22))
        self.server_borough.setObjectName("server_borough")        # 导入
        self.pushButton_import = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_import.setGeometry(QtCore.QRect(590, 10, 111, 23))
        self.pushButton_import.setObjectName("pushButton_import")        # 更新
        self.pushButton_update = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_update.setGeometry(QtCore.QRect(740, 10, 111, 23))
        self.pushButton_update.setObjectName("pushButton_update")        # 信息录入
        self.pushButton_info_entry = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_info_entry.setGeometry(QtCore.QRect(1300, 10, 111, 23))
        self.pushButton_info_entry.setObjectName("pushButton_info_entry")        # 数据表格
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setEditTriggers(
            QtWidgets.QAbstractItemView.NoEditTriggers)        # self.tableWidget.setSelectionBeh*ior(
        #     QtWidgets.QAbstractItemView.SelectRows)
        self.tableWidget.setGeometry(QtCore.QRect(10, 50, 1435, 901))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(14)
        self.tableWidget.setRowCount(self.row_num)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(4, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(5, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(6, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(7, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(8, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(9, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(10, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(11, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(12, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(13, item)

        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)        # 初始化省份数据
        self.server_province.clear()
        self.server_province.addItem('请选择')        for key, value in dictPorovince.items():
            self.server_province.addItem(value, QVariant(key))        # 按扭框被点击事件信号
        self.server_province.activated.connect(self.add_city)
        self.server_city.activated.connect(self.add_borough)
        self.server_borough.activated.connect(self.just_btn_enable)
        self.pushButton_import.clicked.connect(self.import_ok)
        self.pushButton_update.clicked.connect(self.import_ok)
        self.pushButton_info_entry.clicked.connect(self.show_info_entry_windows)        
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "疲劳驾驶监测数据终端平台"))
        self.server_label_province.setText(_translate("MainWindow", "省份"))
        self.server_label_city.setText(_translate("MainWindow", "市/州"))
        self.server_label_borough.setText(_translate("MainWindow", "区/县"))
        self.pushButton_import.setText(_translate("MainWindow", "导出"))
        self.pushButton_update.setText(_translate("MainWindow", "刷新"))
        self.pushButton_info_entry.setText(_translate("MainWindow", "信息录入"))
        item = self.tableWidget.verticalHeaderItem(0)
        item.setText(_translate("MainWindow", "1"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "编号"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "姓名"))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "性别"))
        item = self.tableWidget.horizontalHeaderItem(3)
        item.setText(_translate("MainWindow", "年龄"))
        item = self.tableWidget.horizontalHeaderItem(4)
        item.setText(_translate("MainWindow", "身份证号"))
        item = self.tableWidget.horizontalHeaderItem(5)
        item.setText(_translate("MainWindow", "联系电话"))
        item = self.tableWidget.horizontalHeaderItem(6)
        item.setText(_translate("MainWindow", "省份"))
        item = self.tableWidget.horizontalHeaderItem(7)
        item.setText(_translate("MainWindow", "市/州"))
        item = self.tableWidget.horizontalHeaderItem(8)
        item.setText(_translate("MainWindow", "区/县"))
        item = self.tableWidget.horizontalHeaderItem(9)
        item.setText(_translate("MainWindow", "车型"))
        item = self.tableWidget.horizontalHeaderItem(10)
        item.setText(_translate("MainWindow", "行驶证编号"))
        item = self.tableWidget.horizontalHeaderItem(11)
        item.setText(_translate("MainWindow", "车牌号"))
        item = self.tableWidget.horizontalHeaderItem(12)
        item.setText(_translate("MainWindow", "违规时间"))
        item = self.tableWidget.horizontalHeaderItem(13)
        item.setText(_translate("MainWindow", "操作"))    # 当省份按钮被选择后添加对应的城市数据
    def add_city(self, index):
        pro_code = self.server_province.itemData(index)
        city_data = dictCity.get(pro_code, dict())
        self.server_city.clear()
        self.server_city.addItem('请选择')
        self.server_borough.clear()
        self.server_borough.addItem('请选择')        if self.server_province.currentText() != '请选择':            for key, value in city_data.items():
                self.server_city.addItem(value, QVariant(key))
        self.pushButton_import.setDisabled(True)    # 当城市按钮被选择后添加对应的区县数据
    def add_borough(self, index):
        city_code = self.server_city.itemData(index)
        borough_data = dicBorough.get(city_code, dict())
        self.server_borough.clear()
        self.server_borough.addItem('请选择')        if self.server_city.currentText() != '请选择':            for key, value in borough_data.items():
                self.server_borough.addItem(value, QVariant(key))
        self.pushButton_import.setDisabled(True)    # 导出按钮是否可用
    def just_btn_enable(self, txt):
        if self.server_borough.currentText() != '请选择':
            self.pushButton_import.setDisabled(False)        else:
            self.pushButton_import.setDisabled(True)    # 根据省市县筛选信息导出
    def import_ok(self):
        if self.server_province.currentText() == '请选择':
            QtWidgets.QMessageBox.warning(self, "警告", "请选择省/市/县信息", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)        else:
            self.MySQL_Read = MySQL_Connect()
            self.info_all = self.MySQL_Read.MC_Read_Violation_Info()            # 根据省市县筛选得到的信息存放
            self.info_realdata = []            # 提取筛选后的各数据对应图片地址
            self.info_realimpath = []            # 按钮名称
            self.btn_realname = []            # 遍历提取相应数据
            for i in range(len(self.info_all)):                if self.info_all[i][6] == self.server_province.currentText() and self.info_all[i][7] == self.server_city.currentText() and self.info_all[i][8] == self.server_borough.currentText():
                    self.info_realdata.append(list(self.info_all[i]))
                    self.info_realimpath.append(str(self.info_all[i][-1]))
                    self.btn_realname.append(str('详情:'+self.info_all[i][1]+' - '+self.info_all[i][-2]))
            self.pushbutton_list()            for m in range(len(self.info_realdata)):  # m行 n列
                for n in range(14):
                    item = QtWidgets.QTableWidgetItem(str(self.info_realdata[m][n]))
                    self.tableWidget.setItem(m, n, item)    # 创建详情按钮
    def pushbutton_list(self):
        self.tableWidget.setRowCount(len(self.info_realdata))        for n in range(len(self.info_realdata)):
            self.btn = QtWidgets.QPushButton()
            self.btn.setDown(True)
            self.btn.setStyleSheet('QPushButton{margin:3px}'
                                   'QPushButton{padding:1px 1px}')
            self.tableWidget.setCellWidget(n, 13, self.btn)            #此处将字传入按钮
            self.btn.setText(self.btn_realname[n])            #传达参数,这里sender将接收你点击的字并传入函数
            self.btn.clicked.connect(                lambda: self.btn_clicked(self.btn_realname.index(self.sender().text())))    # 显示子页面 -- 信息录入
    def show_info_entry_windows(self):
        self.Info_Entry_Windows.show()    # 显示子页面 -- 证据图像
    def btn_clicked(self,n):
        #self.nn = list.index(self.line[self.n])
        self.impath = self.info_realimpath[n]
        self.oneinfo = self.btn_realname[n]
        self.EvidenceIm_Windows = Ui_EvidenceIm_Child(
            self.impath, self.oneinfo)
        self.EvidenceIm_Windows.show()# 重写QtWidgets.QMainWindow类关闭事件class MainWindow(QtWidgets.QMainWindow):
    def closeEvent(self, event):  # 关闭窗口触发以下事件
        reply = QtWidgets.QMessageBox.question(
            self, '本程序', '你确定要退出吗?', QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)        if reply == QtWidgets.QMessageBox.Yes:
            event.accept()  # 接受关闭事件
        else:
            event.ignore()  # 忽略关闭事件

信息录入界面 - Input_Info_GUI.py

In [ ]
class Ui_Info_Entry(QtWidgets.QMainWindow):

    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(432, 532)
        Form.setFixedSize(432, 532)        # 分隔线0
        self.line_0 = QtWidgets.QLabel(Form)
        self.line_0.setGeometry(QtCore.QRect(30, 40, 371, 16))
        self.line_0.setObjectName("line_0")        # 分隔线1
        self.line_1 = QtWidgets.QLabel(Form)
        self.line_1.setGeometry(QtCore.QRect(30, 210, 371, 16))
        self.line_1.setObjectName("line_1")        # 分隔线2
        self.line_2 = QtWidgets.QLabel(Form)
        self.line_2.setGeometry(QtCore.QRect(30, 340, 371, 16))
        self.line_2.setObjectName("line_2")        # 基本信息
        self.essential_information = QtWidgets.QLabel(Form)
        self.essential_information.setGeometry(QtCore.QRect(30, 20, 61, 16))
        self.essential_information.setObjectName("essential_information")        # 地址信息
        self.address_information = QtWidgets.QLabel(Form)
        self.address_information.setGeometry(QtCore.QRect(30, 190, 54, 12))
        self.address_information.setObjectName("address_information")        # 车辆信息
        self.vehicle_information = QtWidgets.QLabel(Form)
        self.vehicle_information.setGeometry(QtCore.QRect(30, 320, 54, 12))
        self.vehicle_information.setObjectName("vehicle_information")        # 省份
        self.label_province = QtWidgets.QLabel(Form)
        self.label_province.setGeometry(QtCore.QRect(40, 230, 51, 21))
        self.label_province.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.label_province.setObjectName("label_province")
        self.province = QtWidgets.QComboBox(Form)
        self.province.setGeometry(QtCore.QRect(90, 230, 111, 22))
        self.province.setObjectName("province")
        self.province.addItem("")        # 市/州
        self.label_city = QtWidgets.QLabel(Form)
        self.label_city.setGeometry(QtCore.QRect(230, 230, 51, 21))
        self.label_city.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.label_city.setObjectName("label_city")
        self.city = QtWidgets.QComboBox(Form)
        self.city.setGeometry(QtCore.QRect(280, 230, 111, 22))
        self.city.setObjectName("city")
        self.city.addItem("")        # 区/县
        self.label_borough = QtWidgets.QLabel(Form)
        self.label_borough.setGeometry(QtCore.QRect(40, 280, 51, 21))
        self.label_borough.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.label_borough.setObjectName("label_borough")
        self.borough = QtWidgets.QComboBox(Form)
        self.borough.setGeometry(QtCore.QRect(90, 280, 111, 22))
        self.borough.setObjectName("borough")
        self.borough.addItem("")        # 编号
        self.number = QtWidgets.QLabel(Form)
        self.number.setGeometry(QtCore.QRect(40, 60, 51, 21))
        self.number.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.number.setObjectName("number")
        self.lineEdit_00 = QtWidgets.QLineEdit(Form)
        self.lineEdit_00.setGeometry(QtCore.QRect(90, 60, 111, 20))
        self.lineEdit_00.setText("")
        self.lineEdit_00.setObjectName("lineEdit_00")        # 姓名
        self.name = QtWidgets.QLabel(Form)
        self.name.setGeometry(QtCore.QRect(230, 60, 51, 21))
        self.name.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.name.setObjectName("name")
        self.lineEdit_01 = QtWidgets.QLineEdit(Form)
        self.lineEdit_01.setGeometry(QtCore.QRect(280, 60, 111, 20))
        self.lineEdit_01.setText("")
        self.lineEdit_01.setObjectName("lineEdit_01")        # 性别
        self.sex = QtWidgets.QLabel(Form)
        self.sex.setGeometry(QtCore.QRect(40, 110, 51, 21))
        self.sex.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.sex.setObjectName("sex")
        self.lineEdit_10 = QtWidgets.QLineEdit(Form)
        self.lineEdit_10.setGeometry(QtCore.QRect(90, 110, 111, 20))
        self.lineEdit_10.setText("")
        self.lineEdit_10.setObjectName("lineEdit_10")        # 年龄
        self.age = QtWidgets.QLabel(Form)
        self.age.setGeometry(QtCore.QRect(230, 110, 51, 21))
        self.age.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.age.setObjectName("age")
        self.lineEdit_11 = QtWidgets.QLineEdit(Form)
        self.lineEdit_11.setGeometry(QtCore.QRect(280, 110, 111, 20))
        self.lineEdit_11.setText("")
        self.lineEdit_11.setObjectName("lineEdit_11")        # 身份证号
        self.id_number = QtWidgets.QLabel(Form)
        self.id_number.setGeometry(QtCore.QRect(30, 150, 61, 21))
        self.id_number.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.id_number.setObjectName("id_number")
        self.lineEdit_20 = QtWidgets.QLineEdit(Form)
        self.lineEdit_20.setGeometry(QtCore.QRect(90, 150, 111, 20))
        self.lineEdit_20.setText("")
        self.lineEdit_20.setObjectName("lineEdit_20")        # 联系电话
        self.contact_number = QtWidgets.QLabel(Form)
        self.contact_number.setGeometry(QtCore.QRect(220, 150, 61, 21))
        self.contact_number.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.contact_number.setObjectName("contact_number")
        self.lineEdit_21 = QtWidgets.QLineEdit(Form)
        self.lineEdit_21.setGeometry(QtCore.QRect(280, 150, 111, 20))
        self.lineEdit_21.setText("")
        self.lineEdit_21.setObjectName("lineEdit_21")        # 车型
        self.model = QtWidgets.QLabel(Form)
        self.model.setGeometry(QtCore.QRect(40, 360, 51, 21))
        self.model.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.model.setObjectName("model")
        self.lineEdit_30 = QtWidgets.QLineEdit(Form)
        self.lineEdit_30.setGeometry(QtCore.QRect(90, 360, 111, 20))
        self.lineEdit_30.setText("")
        self.lineEdit_30.setObjectName("lineEdit_30")        # 驾驶证编号
        self.driver_license_number = QtWidgets.QLabel(Form)
        self.driver_license_number.setGeometry(QtCore.QRect(200, 360, 81, 21))
        self.driver_license_number.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.driver_license_number.setObjectName("driver_license_number")
        self.lineEdit_31 = QtWidgets.QLineEdit(Form)
        self.lineEdit_31.setGeometry(QtCore.QRect(280, 360, 111, 20))
        self.lineEdit_31.setText("")
        self.lineEdit_31.setObjectName("lineEdit_31")        # 车牌号
        self.license_number = QtWidgets.QLabel(Form)
        self.license_number.setGeometry(QtCore.QRect(40, 400, 51, 21))
        self.license_number.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.license_number.setObjectName("license_number")
        self.lineEdit_40 = QtWidgets.QLineEdit(Form)
        self.lineEdit_40.setGeometry(QtCore.QRect(90, 400, 111, 20))
        self.lineEdit_40.setText("")
        self.lineEdit_40.setObjectName("lineEdit_40")        # 保存
        self.info_entry = QtWidgets.QPushButton(Form)
        self.info_entry.setGeometry(QtCore.QRect(90, 450, 75, 23))
        self.info_entry.setObjectName("info_entry")        # 取消
        self.cancel = QtWidgets.QPushButton(Form)
        self.cancel.setGeometry(QtCore.QRect(260, 450, 75, 23))
        self.cancel.setObjectName("cancel")        # 中心窗口
        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)        # 初始化省份数据
        self.province.clear()
        self.province.addItem('请选择')        for key, value in dictPorovince.items():
            self.province.addItem(value, QVariant(key))        # 按扭框被点击事件信号
        self.province.activated.connect(self.add_city)
        self.city.activated.connect(self.add_borough)
        self.borough.activated.connect(self.just_btn_enable)
        self.info_entry.clicked.connect(self.s*e_sql_ok)
        self.cancel.clicked.connect(self.close)    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "个人信息登记"))        # 基本信息
        self.essential_information.setText(_translate("Form", "<html><head/><body><p>基本信息<span style=" color:#ff0000;">*</span></p></body></html>"))
        self.line_0.setText(_translate("Form", "--------------------------------------------------------------------"))
        self.number.setText(_translate("Form", "编号:"))
        self.name.setText(_translate("Form", "姓名:"))
        self.sex.setText(_translate("Form", "性别:"))
        self.age.setText(_translate("Form", "年龄:"))
        self.id_number.setText(_translate("Form", "身份证号:"))
        self.contact_number.setText(_translate("Form", "联系电话:"))        # 地址信息
        self.address_information.setText(_translate("Form", "<html><head/><body><p>地址信息<span style=" color:#ff0000;">*</span></p></body></html>"))
        self.line_1.setText(_translate("Form", "--------------------------------------------------------------------"))
        self.label_province.setText(_translate("Form", "省份:"))
        self.province.setItemText(0, _translate("Form", "请选择"))
        self.label_city.setText(_translate("Form", "城市:"))
        self.city.setItemText(0, _translate("Form", "请选择"))
        self.label_borough.setText(_translate("Form", "区/县:"))
        self.borough.setItemText(0, _translate("Form", "请选择"))        # 车辆信息
        self.vehicle_information.setText(_translate("Form", "<html><head/><body><p>车辆信息<span style=" color:#ff0000;">*</span></p></body></html>"))
        self.line_2.setText(_translate("Form", "--------------------------------------------------------------------"))
        self.model.setText(_translate("Form", "车型:"))
        self.driver_license_number.setText(_translate("Form", "行驶证编号:"))
        self.license_number.setText(_translate("Form", "车牌号:"))        # 按钮
        self.cancel.setText(_translate("Form", "取消"))
        self.info_entry.setText(_translate("Form", "录入"))    # 当省份按钮被选择后添加对应的城市数据
    def add_city(self, index):
        pro_code = self.province.itemData(index)
        city_data = dictCity.get(pro_code, dict())
        self.city.clear()
        self.city.addItem('请选择')
        self.borough.clear()
        self.borough.addItem('请选择')        if self.province.currentText() != '请选择':            for key, value in city_data.items():
                self.city.addItem(value, QVariant(key))
        self.info_entry.setDisabled(True)    # 当城市按钮被选择后添加对应的区县数据
    def add_borough(self, index):
        city_code = self.city.itemData(index)
        borough_data = dicBorough.get(city_code, dict())
        self.borough.clear()
        self.borough.addItem('请选择')        if self.city.currentText() != '请选择':            for key, value in borough_data.items():
                self.borough.addItem(value, QVariant(key))
        self.info_entry.setDisabled(True)    # 导出按钮是否可用
    def just_btn_enable(self, txt):
        if self.borough.currentText() != '请选择':
            self.info_entry.setDisabled(False)        else:
            self.info_entry.setDisabled(True)    # 清空信息
    def clear(self):
        self.lineEdit_00.clear()
        self.lineEdit_01.clear()
        self.lineEdit_10.clear()
        self.lineEdit_11.clear()
        self.lineEdit_20.clear()
        self.lineEdit_21.clear()
        self.province.clear()
        self.province.addItem('请选择')
        self.city.clear()
        self.city.addItem('请选择')
        self.borough.clear()
        self.borough.addItem('请选择')
        self.lineEdit_30.clear()
        self.lineEdit_31.clear()
        self.lineEdit_40.clear()        # 初始化省按钮信息
        for key, value in dictPorovince.items():
            self.province.addItem(value, QVariant(key))    # 点击保存后,信息确认
    def s*e_sql_ok(self):
        self.all_info = {}
        self.all_info['编号'] = self.lineEdit_00.text()
        self.all_info['姓名'] = self.lineEdit_01.text()
        self.all_info['性别'] = self.lineEdit_10.text()
        self.all_info['年龄'] = self.lineEdit_11.text()
        self.all_info['身份证号'] = self.lineEdit_20.text()
        self.all_info['联系电话'] = self.lineEdit_21.text()
        self.all_info['省份'] = self.province.currentText()
        self.all_info['城市'] = self.city.currentText()
        self.all_info['区/县'] = self.borough.currentText()
        self.all_info['车型'] = self.lineEdit_30.text()
        self.all_info['行驶证编号'] = self.lineEdit_31.text()
        self.all_info['车牌号'] = self.lineEdit_40.text()        print(self.all_info)

        self.MySQL_S*e = MySQL_Connect()
        self.MySQL_S*e.MC_S*e_User_Info(list_user_info=self.all_info)
        QMessageBox.information(self,                                "请确认信息",                                '''您的编号:{}
姓名:{}
性别:{}
年龄:{}
身份证号:{}
联系电话:{}
省份:{}
城市:{} 
区县:{}
车型:{}
行驶证编号:{}
车牌号:{}'''.format(self.lineEdit_00.text(),
                    self.lineEdit_01.text(),
                    self.lineEdit_10.text(),
                    self.lineEdit_11.text(),
                    self.lineEdit_20.text(),
                    self.lineEdit_21.text(),
                    self.province.currentText(),
                    self.city.currentText(),
                    self.borough.currentText(),
                    self.lineEdit_30.text(),
                    self.lineEdit_31.text(),
                    self.lineEdit_40.text()),
                                QMessageBox.Yes | QMessageBox.No)
        self.clear()

违规图像查看页面 - EvidenceIm_GUI.py

In [ ]
class Ui_EvidenceIm(QtWidgets.QMainWindow):
    def __init__(self,impath,oneinfo):
        super(Ui_EvidenceIm, self).__init__()
        self.impath = impath
        self.oneinfo = oneinfo    def setupUi(self, Form):
        Form.setObjectName(self.oneinfo)
        Form.resize(979, 584)
        Form.setFixedSize(979, 584)
        self.evidence_im_view = GraphicsView(Form)
        self.evidence_im_view.setGeometry(QtCore.QRect(10, 40, 960, 540))
        self.evidence_im_view.setObjectName("evidence_im_view")
        self.evidence_im_label = QtWidgets.QLabel(Form)
        self.evidence_im_label.setGeometry(QtCore.QRect(10, 10, 971, 21))
        self.evidence_im_label.setObjectName("evidence_im_label")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)        try:            # 显示图片
            #img = cv_imread()
            img = cv2.imdecode(np.fromfile(self.impath, dtype=np.uint8), -1)
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB, img)
            x = img.shape[1]  # 获取图像宽度
            y = img.shape[0]  # 获取图像高度
            frame = QtGui.QImage(img.data, x, y, x*3, QtGui.QImage.Format_RGB888)

            pix = QtGui.QPixmap.fromImage(frame)
            self.item = QtWidgets.QGraphicsPixmapItem(pix)  # 创建像素图元
            self.scene = QtWidgets.QGraphicsScene()  # 创建场景
            self.scene.clear()
            self.scene.addItem(self.item)
            self.scene.update()
            self.evidence_im_view.setScene(self.scene)  # 将场景添加至视图
        except:            pass

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", self.oneinfo))
        self.evidence_im_label.setText(_translate(            "Form", "<html><head/><body><p>-------------------------------------------------- <span style=" font-size:12pt; font-weight:600; color:#000000;">图像证据</span> --------------------------------------------------</p></body></html>"))# 重写GraphicsView类 可拖动、放大、缩小图像class GraphicsView(QGraphicsView):
    # 背景区域颜色
    backgroundColor = QColor(255, 255, 255)    def __init__(self, *args, **kwargs):
        super(GraphicsView, self).__init__(*args, **kwargs)
        self.resize(800, 600)        # 设置背景颜色
        self.setBackgroundBrush(self.backgroundColor)
        self.setCacheMode(self.CacheBackground)
        self.setDragMode(self.ScrollHandDrag)
        self.setOptimizationFlag(self.DontS*ePainterState)
        self.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing |
                            QPainter.SmoothPixmapTransform)        if QGLFormat.hasOpenGL():
            self.setRenderHint(QPainter.HighQualityAntialiasing)
        self.setResizeAnchor(self.AnchorUnderMouse)
        self.setRubberBandSelectionMode(Qt.IntersectsItemShape)
        self.setTransformationAnchor(self.AnchorUnderMouse)
        self.setViewportUpdateMode(self.SmartViewportUpdate)        # 设置场景(显示在屏幕中间)
        self._scene = QGraphicsScene(-180, -90, 360, 180, self)
        self.setScene(self._scene)    def wheelEvent(self, event):
        # 滑轮事件
        if event.modifiers() & Qt.ControlModifier:
            self.scaleView(math.pow(2.0, -event.angleDelta().y() / 240.0))            return event.accept()        super(GraphicsView, self).wheelEvent(event)    def scaleView(self, scaleFactor):
        factor = self.transform().scale(
            scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width()        if factor < 0.07 or factor > 100:            return
        self.scale(scaleFactor, scaleFactor)

以上就是基于PaddleDetection的疲劳驾驶检测系统的详细内容,更多请关注其它相关文章!


# 中文网  # 徐州创新网站推广多少钱  # 长清seo平台  # 怎样做好谷歌网站推广服务  # 太原网站关键词推广  # 宿州医院网站建设公示  # 宝鸡网站建设开发外包  # 明星关键词排名  # 音响关键词排名  # 网站品牌推广咨询热线  # 快餐小吃营销推广方案  # 信息技术  # 帮我  # 第一个  # 多线程  # 检测系统  # css  # 转换为  # 表单  # 加载  # 请选择  # cos  # python接口  # 点击事件  # c++  # ai  # apache  # windows  # git  # python  # mysql 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 优化J*a与MySQL合作:分享批处理操作的技巧  AYANEO 安卓掌机 Pocket AIR 配置公布:天玑 1200 + 5.5 英寸屏  广州团建公司方案 | 绝密飞行 → X-PLANE无人机团建主题团建  华为HarmonyOS 4将集|成人|工智能大型模型  新华全媒+|AI:当心,我可能欺骗了你!  AI技术改变*,新骗局来袭,*成功率接近100%  周星驰支持的人工智能与 Web3 初创公司 Moonbox 完成 100 万美元融资  从GOXR到PartyOn,XRSPACE致力打造多元共赢的元宇宙世界  物联网“僵尸网络DDos攻击”增长惊人,威胁全球电信网络  抛媚眼给瞎子看?微软、谷歌的AI广告被广告主抵制  AI教父Bengio:我感到迷失,对AI担忧已成「精神内耗」!  月薪6万,哪些AI岗位在抢人?  科技赋能司法执行 阿里资产免费为全国法院升级VR新服务  IBM CEO克里希纳:人工智能潜在创新无法被监管  懒人必备的家居清洁好物,石头自清洁扫拖机器人G20  李开复官宣新公司「零一万物」,进军 AI 2.0  映宇宙数字人“映映”亮相ChinaJoy,展示AI黑科技实现用户互动  当TS遇上AI,会发生什么?  人工智能和你聊天 成本有多高  Meta发布音频AI模型,仅需2秒片段模拟真人语音  美版贴吧8000小组自爆停摆!拒绝数据被谷歌OpenAI白嫖,CEO被网友骂翻:背刺第三方应用  Meta发布语音AI模型 Voicebox 助虚拟助手与NPC对话  苹果AI战略与微软谷歌大相径庭,到底是领先还是落后?  美踏控股推出创新人工智能大数据模型“心乐舞河”:虚拟人音舞社交的新体验  两小时就能超过人类!DeepMind最新AI速通26款雅达利游戏  OpenAI高管:AI能创造新的就业机会 但也会淘汰一些  学界业界大咖探讨:AI对数字艺术创新的推动力  Win11 的画图应用将包含 Windows Copilot 的 AI 工具整合  英国前首相:AI可能被用来制造“生物恐怖武器”  Meta 发布 Voicebox AI 模型:可生成音频信息,用于 NPC 对话等  ChatGPT大更新!OpenAI奉上程序员大礼包:API新增杀手级能力还降价,新模型、四倍上下文都来了  V社回应拒绝上架含 AI 生成内容的游戏:审核政策正在调整中  速途网络成立“人工智能专家委员会”5位中美博士加盟  AI数字人业务频频获点赞,谦寻积极引领示范作用  Xbox游戏工作室负责人:VR/AR领域的用户规模还不足够  定义人工智能的十个关键术语  “木头姐”:特斯拉的人工智能训练——“赢家通吃”的机会  这效果能打几分?AI真人化《名侦探柯南》  阿里达摩院向公众免费开放100项AI专利许可  当一切设备都受到人工智能的控制  美图设计室2.0新增哪些功能  引领AI变革,九章云极DataCanvas公司重磅发布AIFS+DataPilot  微软必应聊天现已在Chrome和Safari浏览器上可用,但仍有许多限制存在  轻量级的深度学习框架Tinygrad  「电子果蝇」惊动马斯克!背后是13万神经元全脑图谱,可在电脑上运行  Meta推出VR订阅服务Quest +:每月免费玩两款游戏,7.99美元/月  携程发布旅游行业垂直大模型 梁建章:AI策略是做可靠的内容 放心的推荐  华为推出全新操作系统HarmonyOS 4,AI和新引擎完美融合  让AI助手带您轻松愉快地享受写作之旅  央广车联网亮相2025世界人工智能大会 

 2025-07-21

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.