赞
踩
每一年,中国都因交通事故而造成数万人的死亡,造成了严重的损失。而其中司机疲劳驾驶,是导致事故发生的重要原因之一。但是当司机们陷入疲劳驾驶状态时,往往司机本人对此状态并不在意,甚至会陷入睡眠状态!整治疲劳驾驶行为成为了交通运输行业的首要任务。随着信息技术的日新月异,如今,我们有机会使用信息技术,消除疲劳驾驶的隐患。利用移动端设备的摄像头,我们可以实现实时的监测司机的状态。使用PaddleDetection+PaddleLite部署及Paddle2onnx转IR的OpenVINO部署,实现了通过驾驶员的眼部、嘴部动作实时推断疲劳状态,使得驾驶员能及时的被本地语音方式提醒,避免疲劳驾驶,同时后台管理人员能接收到司机疲劳报警信息。
GitHub链接: FatigueDriving
公开数据集为VOC格式,并划分训练集:验证集:测试集=7:2:1
# 解压数据集
!unzip /home/aistudio/data/data106856/fatigue.zip
# 调整数据集的反斜杠问题
f = open('/home/aistudio/fatigue/val_list.txt')
data = f.read()
data2 = data.replace('\\', '/')
f1 = open('/home/aistudio/fatigue/val_list.txt','w')
f1.write(data2)
# 解压PaddleDetection
!unzip /home/aistudio/data/data122193/PaddleDetection.zip
# 安装PaddleDetection依赖环境
!pip install -r PaddleDetection/requirements.txt
# 模型训练
# 修改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
!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 #(需要检测的图片)
# 导出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
# 安装PaddleLite
!pip install paddlelite
# 转换为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
// 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\n", i, cur_time_cost); } printf("warmup: %d repeat: %d, average: %f ms, max: %f ms, min: %f ms\n", 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\n", 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\n", 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\n", preprocess_time); printf("Prediction time: %f ms\n", prediction_time); printf("Postprocess time: %f ms\n\n", 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; }
# 模型训练
!python PaddleDetection/tools/train.py -c PaddleDetection/configs/yolov3/yolov3_mobilenet_v3_large_270e_voc.yml --use_vdl=True --eval
!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 #(需要检测的图片)
# 安装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
!pip install onnx
import paddle2onnx import paddle from openvino_ppdet import nms_mapper # 通过上面的`nms_mapper`的import来启用插件,替换了paddle2onnx原始的nms_mapper model_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使用文档
#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; }
#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")); }
通过检测部分的存储违规图像动作,触发语音提示及信息记录功能
import os import _thread import sys import time import threading import cv2 import numpy as np import pygame from PyQt5 import QtWidgets from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow from watchdog.events import * from watchdog.observers import Observer from MySQL_Connect import MySQL_Connect # 加载openvino部署封装的dll及pyd os.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 # 信息记录至SQL def 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]) + '.jpg' 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]) + '.jpg' 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))
import os import _thread import sys import time import threading import cv2 import numpy as np import pygame from PyQt5 import QtWidgets from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow from watchdog.events import * from watchdog.observers import Observer from 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 # 信息记录至SQL def 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))
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_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
# 子窗口 -- 信息录入 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() # 忽略关闭事件
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", "<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 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()
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.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 elf.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)
本次项目目前实现了实时检测能力,对于疲劳的判定标准为闭眼及张嘴的幅度,驾驶员出现疲劳反应后触发语音提示功能并留存凭证写入数据库,并搭配了数据库信息可视化的GUI界面,并已在做耗时优化。
由于开发时间紧张,项目比较粗糙,没有打磨精细,下面是即将优化的几个部分,也欢迎小伙伴们向我们提出建议:
70+
ms)Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。