首页 游戏 软件 资讯 排行榜 专题
首页
AI
基于PaddleDetection的疲劳驾驶检测系统

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

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

基于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.webp #(需要检测的图片)
登录后复制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////     https://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 #include #include #include #include #include #include #include #include #include //#include 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 INPUT_SHAPE = {1, 3, 320, 320}; //输入形状const std::vector INPUT_MEAN = {0.5f, 0.5f, 0.5f};  //输入平均值const std::vector 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 load_labels(const std::string &path) {  std::ifstream file;  std::vector 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 &input_mean,                const std::vector &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(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 postprocess(const float *output_data, int64_t output_size,                                const std::vector &word_labels,                                const float score_threshold,                                cv::Mat &output_image, double time) {  std::vector results;  std::vector 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(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(result.left * output_image.cols);    int ly = static_cast(result.top * output_image.rows);    int w = static_cast(result.right * output_image.cols) - lx;    int h = static_cast(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 &word_labels,                std::shared_ptr &predictor) {  // 对图像进行预处理,填充输入张量数据  std::unique_ptr 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();  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::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, average: %f ms, max: %f ms, min: %f ms",         WARMUP_COUNT, REPEAT_COUNT, prediction_time,         max_time_cost, min_time_cost);  // 获取输出张量数据,进行后处理,输出检测对象  std::unique_ptr output_tensor(      std::move(predictor->GetOutput(0)));  const float *output_data = output_tensor->mutable_data();  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 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 + ".webp";      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 + ".webp";      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 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 predictor =      paddle::lite_api::CreatePaddlePredictor(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.webp #(需要检测的图片)
登录后复制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使用文档

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/gputry {executableNetwork = ie.LoadNetwork(network, useIntelgpu ? "GPU" : "CPU");std::cout << "Loading model succeeded!" << std::endl;}catch (...) {return -2;}// 构建预测inferRequest = executableNetwork.CreateInferRequest();// 获取输入输出的BlobinputImage = 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> &outputs, float scoreThreshold){if (!img.data)return -1;//判断是否有数据std::vector mean;mean.push_back(0.485f);mean.push_back(0.456f);mean.push_back(0.406f);std::vector 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 =》NCHWfloat* data = static_cast(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(row, col)[ch]) / 255.0f) - float(mean[ch]) / std[ch];}}}    // 输入尺寸float* im_shape = static_cast(inputImShape->buffer());im_shape[0] = image.rows;im_shape[1] = image.cols;// 缩放因子float* scale_factor = static_cast(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 output;auto output_data = outputInfo->buffer().as::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 #include #include #include #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& input_data){cv::Mat dst = ConvertNDArrayToMat(input_data);return dst;}, py::arg("input_data"));py::class_(m, "cvMat");py::class_(m, "fatigueDriving").def(py::init<>()).def("Init", &fatigueDriving::Init).def("Process", [](fatigueDriving& vc, const cv::Mat& img, float scoreThreshold){std::vector> 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 save_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 = save_received_info(        user_info, iolations_time, a)    MySQL.MC_Save_Violation_Info(user_list_violation_info)# 执行预测def run_detection_win_py(savepath):    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]) + '.webp'                savefile = savepath + module_name                cv2.imwrite(savefile, frame)                ToSQL(savefile, 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]) + '.webp'                    savefile = savepath + module_name                    cv2.imwrite(savefile, frame)                    ToSQL(savefile, 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:        # 识别线程        savepath="./screenshots/"        getDetect = threading.Thread(target=run_detection_win_py, args=(savepath, ))        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 save_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 = save_received_info(        user_info, iolations_time, a)    MySQL.MC_Save_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=,                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_Save_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_Save_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.setSelectionBehavior(        #     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.save_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", "

基本信息*

")) 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", "

地址信息*

")) 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", "

车辆信息*

")) 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 save_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_Save = MySQL_Connect() self.MySQL_Save.MC_Save_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", "

-------------------------------------------------- 图像证据 --------------------------------------------------

"))# 重写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.DontSavePainterState) 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)
登录后复制
来源:https://www.php.cn/faq/1420621.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

CSS模拟x86 CPU:大神实现浏览器直接运行机器码
电脑教程
CSS模拟x86 CPU:大神实现浏览器直接运行机器码

2月26日消息,开发者Lyra Rebane近日完成了一项足以颠覆认知的壮举,仅用CSS,不借助一行JavaScript代码,成功打造出一个可运行的8086 CPU模拟器。用户甚至可以用C语言编写程

热心网友
02.27
CSS原生支持SQL查询:前端直接操作数据库新方法
科技数码
CSS原生支持SQL查询:前端直接操作数据库新方法

TailwindSQL能让你用Tailwind风格的类名编写SQL查询语句,直接在React服务端组件中通过className属性就能直连数据库执行查询! 这个东西最近爆火!!!

热心网友
02.04
人工智能如何重塑写作:语法无误是AI的挑战还是机遇
科技数码
人工智能如何重塑写作:语法无误是AI的挑战还是机遇

一、“AI起号速成班”AI拥有近乎零门槛的强大文本生成能力,正被无数用户用于互联网的各个角落,制造并散播着海量的“内容垃圾”。互联网这片曾经最美好的创意沃土与数字原野,如今俨然已有变成AI内容垃圾场

热心网友
01.25
GPT-5.2连肝7天,30万行代码打造Chrome级浏览器
AI
GPT-5.2连肝7天,30万行代码打造Chrome级浏览器

新智元报道编辑:定慧 艾伦【新智元导读】一个大模型持续写代码,能写多久?一小时?一天?还是像大部分AI编程工具那样,完成一个任务就结束对话?Cursor的CEO MichaelTruell决定搞一次

热心网友
01.15
AI框架陷绝境:创始人深夜痛呼裁员75%,仅剩6个月
AI
AI框架陷绝境:创始人深夜痛呼裁员75%,仅剩6个月

新智元报道编辑:Aeneas【新智元导读】一则消息震惊了整个开发者社区:开发了前端基础设施的Tailwind因为做AI做得太好,反而收入暴降80%,裁掉四分之三的员工!CEO绝望录制了一段播客,好在

热心网友
01.12

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

比特币重探7万美元,市场已全面消化美伊战争风险?
web3.0
比特币重探7万美元,市场已全面消化美伊战争风险?

清明节假期期间,A 股和港股休市,但比特币行情永不停歇。 4月6日,当多数市场还在假期中沉睡时,比特币已经悄然启动。价格从亚洲早盘的低点67400美元出发,一路向上试探,盘中最高涨破70300美元,不仅刷新了3月26日以来的高位,较日内低点的涨幅也超过了4%。以太坊的表现同样不俗,从2050美元附近

热心网友
04.07
魏思琪换上新机!REDMI K90至尊版来了 小米首款风冷旗舰
网络安全
魏思琪换上新机!REDMI K90至尊版来了 小米首款风冷旗舰

4月5日消息,日前,REDMI K90至尊版通过3C认证,预计将于本月发布。今日,小米中国区市场部总经理魏思琪用小米新机发布微博,不出意外,这正是即将登场的REDMI K90至尊版,这将是小米首款配

热心网友
04.07
WPS动态交互图表制作指南:让数据变化直观呈现
电脑教程
WPS动态交互图表制作指南:让数据变化直观呈现

WPS演示中图表不随数据更新时,可通过四种方法实现自动同步:一、用OFFSET+COUNTA定义动态名称绑定图表;二、用组合框控件联动VLOOKUP提取数据;三、用数据透视图配合切

热心网友
04.07
“链接未来·智汇静安”区块链创新应用优秀场景分享(四)| 信医基于区块链与隐私计算的真实世界研究数据产品
科技数码
“链接未来·智汇静安”区块链创新应用优秀场景分享(四)| 信医基于区块链与隐私计算的真实世界研究数据产品

聚焦数字技术,释放创新动能。为集中展示静安区区块链技术从“实验室”走向“应用场”的丰硕成果,挖掘一批可复制、可推广的行业解决方案,加速构建区块链产业生态闭环,静安区数据局特推出“静安区区块链创新应用

热心网友
04.07
天上的马桶与地上的火药桶,都在让美国出糗
科技数码
天上的马桶与地上的火药桶,都在让美国出糗

太空中的马桶堵了,边飞边修还能勉强用。但中东被点燃的火药桶,美国怎么来扑灭?靠一再延期的“最后通牒”?还是靠无底线的轰炸?2300万美元的马桶美国航空航天局4名宇航员1日搭乘“猎户座”飞船升空,执行

热心网友
04.07