├── README.md
├── form
└── res.qrc
├── images
├── 1.jpg
├── 1.mp4
├── 1_2.jpg
├── 1_3.jpg
├── 2.jpg
├── 2.mp4
├── 3.mp4
├── 4.mp4
├── 5.mp4
├── a1.jpg
├── a2.jpg
├── a3.jpg
├── a3_1.jpg
├── a4.jpg
├── bus.1.jpg
├── bus.jpg
├── mask.jpg
├── s.jpg
├── selfie.jpg
├── test.mp4
├── test1.mp4
└── zidane.jpg
├── include
├── detector.h
├── mainwindow.h
├── outputimagedialog.h
├── outputvediodialog.h
├── setdialog.h
└── utils.h
├── introduce
├── image1.jpg
├── image2.jpg
├── image3.jpg
├── image4.jpg
└── image5.jpg
├── res
├── background.png
├── mainwindow.jpg
├── state_green_48.png
├── state_red_48.png
└── title.png
├── src
├── appendMsg.cpp
├── changeState.cpp
├── closeCamera.cpp
├── detector.cpp
├── judgeFlaw.cpp
├── main.cpp
├── mainwindow.cpp
├── onStateChanged.cpp
├── on_closeButton_clicked.cpp
├── on_connectPLC_clicked.cpp
├── on_imageDetection_clicked.cpp
├── on_labelChoose_clicked.cpp
├── on_objectDetection_clicked.cpp
├── on_setupdialog_clicked.cpp
├── on_startButton_clicked.cpp
├── on_weightChoose_clicked.cpp
├── openCamera.cpp
├── openni.cpp
├── outputimagedialog.cpp
├── outputvediodialog.cpp
├── readCoils.cpp
├── readReady_coils.cpp
├── receiveData.cpp
├── save.cpp
├── saveDataFile.cpp
├── setdialog.cpp
├── utils.cpp
└── writeRequst.cpp
└── weights1
├── best.onnx
├── best1_smi.onnx
├── class2.names
├── mainwindow.ui
├── outputimagedialog.ui
├── outputvediodialog.ui
├── setdialog.ui
└── unchange_best.onnx
/README.md:
--------------------------------------------------------------------------------
1 | # Defect-detection
2 | 基于QT的缺陷检测系统,包括图像检测以及目标检测两个部分。
3 | 图像检测包括二值化和边缘检测以及图像矩运算,目标检测使用ONNXRuntime推理yolov5s训练模型,支持GPU加速。
4 | 支持奥比中光工业相机检测、视频检测以及图片检测。
5 |
6 | 
7 |
8 | 
9 |
10 | 
11 |
12 | 
13 |
14 | 
15 |
--------------------------------------------------------------------------------
/form/res.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | res/background.png
4 | res/mainwindow.jpg
5 | res/state_green_48.png
6 | res/state_red_48.png
7 | res/title.png
8 |
9 |
10 |
--------------------------------------------------------------------------------
/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/1.jpg
--------------------------------------------------------------------------------
/images/1.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/1.mp4
--------------------------------------------------------------------------------
/images/1_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/1_2.jpg
--------------------------------------------------------------------------------
/images/1_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/1_3.jpg
--------------------------------------------------------------------------------
/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/2.jpg
--------------------------------------------------------------------------------
/images/2.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/2.mp4
--------------------------------------------------------------------------------
/images/3.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/3.mp4
--------------------------------------------------------------------------------
/images/4.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/4.mp4
--------------------------------------------------------------------------------
/images/5.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/5.mp4
--------------------------------------------------------------------------------
/images/a1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/a1.jpg
--------------------------------------------------------------------------------
/images/a2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/a2.jpg
--------------------------------------------------------------------------------
/images/a3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/a3.jpg
--------------------------------------------------------------------------------
/images/a3_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/a3_1.jpg
--------------------------------------------------------------------------------
/images/a4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/a4.jpg
--------------------------------------------------------------------------------
/images/bus.1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/bus.1.jpg
--------------------------------------------------------------------------------
/images/bus.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/bus.jpg
--------------------------------------------------------------------------------
/images/mask.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/mask.jpg
--------------------------------------------------------------------------------
/images/s.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/s.jpg
--------------------------------------------------------------------------------
/images/selfie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/selfie.jpg
--------------------------------------------------------------------------------
/images/test.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/test.mp4
--------------------------------------------------------------------------------
/images/test1.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/test1.mp4
--------------------------------------------------------------------------------
/images/zidane.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/images/zidane.jpg
--------------------------------------------------------------------------------
/include/detector.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "utils.h"
7 |
8 |
9 | class YOLODetector
10 | {
11 | public:
12 | explicit YOLODetector(std::nullptr_t) {};//构造函数 explicit关键字用来修饰类的构造函数,不能发生相应的隐式类型转换
13 | YOLODetector(const std::string& modelPath,
14 | const bool& isGPU,
15 | const cv::Size& inputSize);//构造函数
16 |
17 | std::vector detect(cv::Mat &image, const float& confThreshold, const float& iouThreshold);//推理
18 |
19 | private:
20 | Ort::Env env{nullptr};
21 | Ort::SessionOptions sessionOptions{nullptr};
22 | Ort::Session session{nullptr};
23 |
24 | void preprocessing(cv::Mat &image, float*& blob, std::vector& inputTensorShape);//标准化处理 归一化
25 | std::vector postprocessing(const cv::Size& resizedImageShape,
26 | const cv::Size& originalImageShape,
27 | std::vector& outputTensors,
28 | const float& confThreshold, const float& iouThreshold);//后处理
29 |
30 | static void getBestClassInfo(std::vector::iterator it, const int& numClasses,
31 | float& bestConf, int& bestClassId);//找到最佳类别的信息
32 |
33 | std::vector inputNames;
34 | std::vector outputNames;
35 | bool isDynamicInputShape{};
36 | cv::Size2f inputImageShape;
37 |
38 | };
--------------------------------------------------------------------------------
/include/mainwindow.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma execution_character_set("utf-8")
3 | #include
4 | #include "ui_mainwindow.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include"detector.h"
15 | #include"utils.h"
16 | #include"setdialog.h"
17 | #include"outputimagedialog.h"
18 | #include"outputvediodialog.h"
19 | #include< QFileDialog>
20 | #include
21 |
22 | using namespace openni;
23 | using namespace cv;
24 | using namespace std;
25 |
26 |
27 | class MainWindow : public QMainWindow
28 | {
29 | Q_OBJECT
30 |
31 | public:
32 | MainWindow(QWidget *parent = Q_NULLPTR);
33 |
34 | QModbusClient* modbusDevice = NULL;//创建一个发送请求的对象
35 | QTimer* visualTime = NULL;//QTimer构造
36 | Status status= STATUS_ERROR;//状态(类似于int类型)
37 | Array deviceInfoList;//存储设备信息的array
38 | Device device;//创建设备 Device可以访问流(Streams)
39 | VideoStream colorStream;//创建色彩流
40 | VideoMode colorMode;//设置彩色流的模式
41 | VideoFrameRef frame;//创建一个Ref类型的变量,用以存储帧数据
42 | VideoStream** pStreams = NULL;//创建VideoStream类型的指针,指向已创建的深度流和色彩流的地址(同时获取多个流数据)
43 | RGB888Pixel* pColor = NULL;//用于存储获得的彩色数据
44 | Mat frame1;
45 |
46 | QString timeStr;//时间字符串
47 | QString savePath= "E:/programs data/QT/Defect detection/detection_data/";//保存路径
48 | int g_imagecount = 1;//计数,创建文件的名字
49 |
50 |
51 |
52 | //创建目标检测对象
53 |
54 | //视频推理
55 | bool isGPU;//设置是否使用GPU
56 | bool initGPU;
57 | std::string classNamesPath;
58 | std::vector classNames;//加载类型文件,转换为标签字符串数组
59 | std::string modelPath;//模型地址
60 |
61 |
62 | //检测对象选择
63 | VideoCapture vid_capture;//创建一个视频捕捉对象
64 | bool isCamera=true;//摄像头检测
65 | bool isVideo = false;//视频检测
66 | bool isImage = false;//图片检测
67 | std::string vedioPath;//视频路径
68 | std::string imagePath;//图片路径
69 | bool isResolvingPower = true;//分辨率 640x480
70 |
71 | //图片保存设置
72 | bool isSaveImage1 = true;
73 | bool isSaveImage2 = true;
74 | bool isSaveImage3 = true;
75 | QString imageSavePath = "E:/programs data/QT/Defect detection/detection_data/imageSave";
76 | Mat Image1;
77 | Mat Image2;
78 | Mat Image3;
79 | //视频保存设置
80 | bool isSaveVedioLeft = true;
81 | bool isSaveVedioRight = true;
82 | QString videoSavePath= "E:/programs data/QT/Defect detection/detection_data/vedioSave/test.mp4";
83 | VideoWriter outputVideo;
84 | bool isSaveVedio = false;
85 |
86 |
87 | //创建检测对象
88 | YOLODetector detector{ nullptr };
89 | std::vector result;
90 |
91 |
92 | void appendMsg(QString str);//提示框
93 |
94 |
95 | private:
96 | Ui::MainWindowClass ui;
97 | setDialog* pDlg;//检测对话框指针
98 | outputImageDialog* pDlg1;//图片保存对话框
99 | outputVedioDialog* pDlg2;//视频保存对话框
100 |
101 |
102 | bool isCameraOpen = false;//摄像头连接判断
103 | bool isConnected = true;//PLC连接判断
104 | bool isHaveFlaw = false;//缺陷判断
105 | bool isHandled = false;
106 | cv::Mat image;
107 | cv::Mat rawMat;
108 | cv::Mat colorMat;//RGB图
109 | cv::Mat tailorMat;//裁剪图
110 | cv::Mat gray_src;//灰度图
111 | cv::Mat binaryMat;//二值图
112 | QImage ImgR;//RGB图Qimage绘图设备 可以对像素进行访问
113 | QImage ImgB;//二值图Qimage绘图设备 可以对像素进行访问
114 |
115 |
116 |
117 | void openCamera();//打开相机函数
118 | void closeCamera();//关闭相机函数
119 | void receiveData();//显示图片
120 | void judgeFlaw();//判断缺陷
121 |
122 |
123 | public slots:
124 | void onStateChanged(int state);//连接状态发生改变时处理函数(connect or discennect)
125 | void on_connectPLC_clicked();//连接PLC
126 | void on_startButton_clicked();//打开相机
127 | void on_closeButton_clicked();//关闭相机
128 | void saveDataFile();//保存文件
129 | void changeState();//改变指示灯的状态(发现缺陷 和处理过缺陷)
130 | void writeRequst();//给PLC写数据
131 | void readReady_coils();//接收到读取请求后执行的槽函数
132 | bool readCoils();//读取写的内容
133 | void on_weightChoose_clicked();//选择权重
134 | void on_labelChoose_clicked();//选择文件标签
135 | void on_setupdialog_clicked();//设置对话框
136 | void on_objectDetection_clicked();//目标检测被点击
137 | void on_imageDetection_clicked();//图像检测被点击
138 |
139 | //保存设置
140 | void on_imageSaveSet_clicked();
141 | void on_vedioSaveSet_clicked();
142 | void on_imageSave_clicked();
143 | void on_vedioSave_clicked();
144 |
145 |
146 | signals:
147 | void signalOpen();
148 | void signalJudge();
149 | void signalFlaw();
150 | void signalSaveData();
151 | void signalWrite();
152 | void signalRead();
153 | void signalHandled();
154 | };
155 |
156 |
157 |
--------------------------------------------------------------------------------
/include/outputimagedialog.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "ui_outputimagedialog.h"
5 | #include< QFileDialog>
6 | #include
7 | #include
8 | class outputImageDialog : public QDialog
9 | {
10 | Q_OBJECT
11 |
12 | public:
13 | outputImageDialog(QWidget *parent = Q_NULLPTR);
14 | ~outputImageDialog();
15 |
16 | private:
17 | Ui::outputImageDialog ui;
18 |
19 | public slots:
20 | void on_acceptButton_clicked();
21 | void on_rejectButton_clicked();
22 | void on_choseButton_clicked();
23 | void getMessage(bool& isSaveImage1, bool& isSaveImage2, bool& isSaveImage3, QString& imageSavePath);
24 | };
25 |
--------------------------------------------------------------------------------
/include/outputvediodialog.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "ui_outputvediodialog.h"
5 | #include< QFileDialog>
6 | #include
7 | #include
8 | class outputVedioDialog : public QDialog
9 | {
10 | Q_OBJECT
11 |
12 | public:
13 | outputVedioDialog(QWidget *parent = Q_NULLPTR);
14 | ~outputVedioDialog();
15 |
16 | private:
17 | Ui::outputVedioDialog ui;
18 |
19 | public slots:
20 | void on_acceptButton_clicked();
21 | void on_rejectButton_clicked();
22 | void on_choseButton_clicked();
23 | void getMessage(bool& saveVedioLeft, bool& saveVedioRight, QString& videoSaveChose);
24 | };
25 |
--------------------------------------------------------------------------------
/include/setdialog.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "ui_setdialog.h"
5 | #include< QFileDialog>
6 | #include
7 | #include
8 | class setDialog : public QDialog
9 | {
10 | Q_OBJECT
11 | private:
12 | Ui::setDialog ui;
13 |
14 | public:
15 | setDialog(QWidget *parent = Q_NULLPTR);
16 | ~setDialog();
17 |
18 | public slots:
19 | void on_acceptButton_clicked();
20 | void on_rejectButton_clicked();
21 | void on_cameraRadioButton_clicked();
22 | void on_videoRadioButton_clicked();
23 | void on_pictureRadioButton_clicked();
24 | void getMessage(bool& isCamera, bool& isVedio, bool& isImage,bool& isResolvingPower,std::string& vedioStr, std::string& imageStr);
25 |
26 |
27 | };
28 |
--------------------------------------------------------------------------------
/include/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 |
7 | struct Detection
8 | {
9 | cv::Rect box;//矩形框
10 | float conf{};//置信度
11 | int classId{};//类别
12 | };
13 |
14 | namespace utilss
15 | {
16 | size_t vectorProduct(const std::vector& vector);
17 | std::wstring charToWstring(const char* str);//字符转字符串
18 | std::vector loadNames(const std::string& path);//加载className
19 | void visualizeDetection(cv::Mat& image, std::vector& detections,
20 | const std::vector& classNames);//画目标框
21 |
22 | //将原图变成预定大小的图片 640X640 方便模型进行预测
23 | void letterbox(const cv::Mat& image, cv::Mat& outImage,
24 | const cv::Size& newShape,
25 | const cv::Scalar& color,
26 | bool auto_,
27 | bool scaleFill,
28 | bool scaleUp,
29 | int stride);
30 |
31 | void scaleCoords(const cv::Size& imageShape, cv::Rect& box, const cv::Size& imageOriginalShape); //缩放坐标
32 |
33 | template
34 | T clip(const T& n, const T& lower, const T& upper);
35 | }
36 |
--------------------------------------------------------------------------------
/introduce/image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/introduce/image1.jpg
--------------------------------------------------------------------------------
/introduce/image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/introduce/image2.jpg
--------------------------------------------------------------------------------
/introduce/image3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/introduce/image3.jpg
--------------------------------------------------------------------------------
/introduce/image4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/introduce/image4.jpg
--------------------------------------------------------------------------------
/introduce/image5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/introduce/image5.jpg
--------------------------------------------------------------------------------
/res/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/res/background.png
--------------------------------------------------------------------------------
/res/mainwindow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/res/mainwindow.jpg
--------------------------------------------------------------------------------
/res/state_green_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/res/state_green_48.png
--------------------------------------------------------------------------------
/res/state_red_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/res/state_red_48.png
--------------------------------------------------------------------------------
/res/title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/res/title.png
--------------------------------------------------------------------------------
/src/appendMsg.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | //消息框
3 | void MainWindow::appendMsg(QString str)
4 | {
5 | QDateTime dateTime(QDateTime::currentDateTime());//获取当前时间
6 | QString qStr = dateTime.toString("yy/MM/dd hh:mm:ss");//转字符串
7 | ui.textEdit->append(qStr + ": " + str);
8 | }
--------------------------------------------------------------------------------
/src/changeState.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //改变指示灯的状态
4 | void MainWindow::changeState()
5 | {
6 | QString lightPath = NULL;
7 | //有缺陷提示
8 | if (this->isHaveFlaw == true)
9 | {
10 | lightPath = ":/res/state_red_48.png";
11 | }
12 | //处理过缺陷恢复原来状态
13 | if (this->isHandled == true)
14 | {
15 | lightPath = ":/res/state_green_48.png";
16 | }
17 | QPixmap light = QPixmap(lightPath);
18 | ui.lightlabel->setPixmap(light);
19 | }
--------------------------------------------------------------------------------
/src/closeCamera.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | //关闭相机函数
3 | void MainWindow::closeCamera()//关闭相机函数
4 | {
5 | if (isCameraOpen)
6 | {
7 | delete[] pStreams;
8 |
9 | //停止彩色流
10 | colorStream.stop();
11 |
12 | //销毁彩色流
13 | colorStream.destroy();
14 |
15 | //关闭设备
16 | device.close();
17 |
18 | //释放OpenNI资源
19 | OpenNI::shutdown();//关闭所有驱动并且正确地清除所有
20 |
21 | appendMsg("------相机关闭------");
22 |
23 | isCameraOpen = false;
24 | //设置开始按钮不可点击
25 | ui.startButton->setEnabled(true);
26 | ui.closeButton->setEnabled(false);
27 |
28 | }
29 | return;
30 | }
--------------------------------------------------------------------------------
/src/detector.cpp:
--------------------------------------------------------------------------------
1 | #include "detector.h"
2 | #include"mainwindow.h"
3 |
4 | YOLODetector::YOLODetector(const std::string& modelPath,
5 | const bool& isGPU = true,
6 | const cv::Size& inputSize = cv::Size(640, 640))
7 | {
8 |
9 | //初始化环境,每个进程一个环境
10 | //环境保留了线程池和其他状态信息
11 | env = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_WARNING, "ONNX_DETECTION");
12 | //初始化Session选项
13 | sessionOptions = Ort::SessionOptions();
14 | //sessionOptions.SetIntraOpNumThreads(5);//设置线程数
15 | std::vector availableProviders = Ort::GetAvailableProviders();//找到可用的显卡设备
16 | auto cudaAvailable = std::find(availableProviders.begin(), availableProviders.end(), "CUDAExecutionProvider");//遍历设备
17 | //OrtCUDAProviderOptions cudaOption;
18 |
19 |
20 |
21 | Ort::Env env = Ort::Env{ ORT_LOGGING_LEVEL_VERBOSE, "Default" };//设置为VERBOSE,方便控制台输出时看到是使用了cpu还是gpu执行
22 |
23 | if (isGPU && (cudaAvailable == availableProviders.end()))//使用GPU但是找不到可使用的显卡
24 | {
25 | std::cout << "GPU is not supported by your ONNXRuntime build. Fallback to CPU." << std::endl;
26 | std::cout << "Inference device: CPU" << std::endl;
27 | }
28 | else if (isGPU && (cudaAvailable != availableProviders.end()))//使用GPU找到了可使用的显卡
29 | {
30 | std::cout << "Inference device: GPU" << std::endl;
31 | //sessionOptions.AppendExecutionProvider_CUDA(cudaOption);
32 |
33 | // 第二个参数代表GPU device_id = 0,注释这行就是cpu执行
34 | Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0));
35 | }
36 | else//使用CPU
37 | {
38 | std::cout << "Inference device: CPU" << std::endl;
39 | }
40 |
41 | #ifdef _WIN32
42 | std::wstring w_modelPath = utilss::charToWstring(modelPath.c_str());//wstring是宽字符,占用2个字节的大小,针对UNICODE编码格式
43 | session = Ort::Session(env, w_modelPath.c_str(), sessionOptions);//把模型加载到内存中
44 | #else
45 | session = Ort::Session(env, modelPath.c_str(), sessionOptions);
46 | #endif
47 |
48 |
49 | //打印模型的输入层(node names, types, shape etc.)
50 | Ort::AllocatorWithDefaultOptions allocator;
51 |
52 | // 输出输入节点的类型 维度
53 | Ort::TypeInfo inputTypeInfo = session.GetInputTypeInfo(0);
54 | std::vector inputTensorShape = inputTypeInfo.GetTensorTypeAndShapeInfo().GetShape();
55 |
56 | // checking if width and height are dynamic 检查宽度和高度是否是动态的
57 | this->isDynamicInputShape = false;
58 | if (inputTensorShape[2] == -1 && inputTensorShape[3] == -1)
59 | {
60 | std::cout << "Dynamic input shape" << std::endl;
61 | this->isDynamicInputShape = true;
62 | }
63 |
64 |
65 | //// 打印所有输入层信息
66 | //for (auto shape : inputTensorShape)
67 | // std::cout << "Input shape: " << shape << std::endl;//(1,3,640,640)
68 |
69 |
70 | //输入输出节点名称
71 | inputNames.push_back(session.GetInputName(0, allocator));//image
72 | outputNames.push_back(session.GetOutputName(0, allocator));//output
73 |
74 | //std::cout << "Input name: " << inputNames[0] << std::endl;
75 | //std::cout << "Output name: " << outputNames[0] << std::endl;
76 |
77 | this->inputImageShape = cv::Size2f(inputSize);
78 | }
79 |
80 |
81 | //找到最佳类别的信息
82 | void YOLODetector::getBestClassInfo(std::vector::iterator it, const int& numClasses,
83 | float& bestConf, int& bestClassId)
84 | {
85 | // first 5 element are box and obj confidence 前5个要素是方框和obj置信度
86 | bestClassId = 5;
87 | bestConf = 0;
88 |
89 | for (int i = 5; i < numClasses + 5; i++)//遍历各个类别的置信度 找到置信度最大的类别
90 | {
91 | if (it[i] > bestConf)
92 | {
93 | bestConf = it[i];
94 | bestClassId = i - 5;
95 | }
96 | }
97 |
98 | }
99 |
100 | //标准化处理 归一化
101 | void YOLODetector::preprocessing(cv::Mat &image, float*& blob, std::vector& inputTensorShape)
102 | {
103 | cv::Mat resizedImage, floatImage;
104 | cv::cvtColor(image, resizedImage, cv::COLOR_BGR2RGB);//转换色彩空间 BGR to RGB
105 | utilss::letterbox(resizedImage, resizedImage, this->inputImageShape,
106 | cv::Scalar(114, 114, 114), this->isDynamicInputShape,
107 | false, true, 32);// 填充调整图片大小
108 |
109 | inputTensorShape[2] = resizedImage.rows;//高
110 | inputTensorShape[3] = resizedImage.cols;//宽
111 |
112 | resizedImage.convertTo(floatImage, CV_32FC3, 1 / 255.0);
113 | blob = new float[floatImage.cols * floatImage.rows * floatImage.channels()];//宽*高*通道
114 | cv::Size floatImageSize {floatImage.cols, floatImage.rows};//图片大小{宽,高}
115 |
116 | // hwc -> chw 高宽通道转换为通道高宽
117 | std::vector chw(floatImage.channels());
118 | for (int i = 0; i < floatImage.channels(); ++i)//遍历3通道
119 | {
120 | chw[i] = cv::Mat(floatImageSize, CV_32FC1, blob + i * floatImageSize.width * floatImageSize.height);
121 | }
122 | cv::split(floatImage, chw); //通道分离
123 | }
124 |
125 | //后处理
126 | std::vector YOLODetector::postprocessing(const cv::Size& resizedImageShape,
127 | const cv::Size& originalImageShape,
128 | std::vector& outputTensors,
129 | const float& confThreshold, const float& iouThreshold)
130 | {
131 | std::vector boxes;//目标框坐标
132 | std::vector confs;//置信度
133 | std::vector classIds;//类别ID
134 |
135 | auto* rawOutput = outputTensors[0].GetTensorData();
136 | std::vector outputShape = outputTensors[0].GetTensorTypeAndShapeInfo().GetShape();
137 | size_t count = outputTensors[0].GetTensorTypeAndShapeInfo().GetElementCount();
138 | std::vector output(rawOutput, rawOutput + count);
139 |
140 | // for (const int64_t& shape : outputShape)
141 | // std::cout << "Output Shape: " << shape << std::endl;
142 |
143 | // first 5 elements are box[4] and obj confidence 前5个要素是方框4个坐标和目标置信度
144 | int numClasses = (int)outputShape[2] - 5;
145 | int elementsInBatch = (int)(outputShape[1] * outputShape[2]);
146 |
147 | // only for batch size = 1 仅适用于批量大小=1
148 | for (auto it = output.begin(); it != output.begin() + elementsInBatch; it += outputShape[2])
149 | {
150 | float clsConf = it[4];
151 |
152 | if (clsConf > confThreshold)
153 | {
154 | int centerX = (int) (it[0]);
155 | int centerY = (int) (it[1]);
156 | int width = (int) (it[2]);
157 | int height = (int) (it[3]);
158 | int left = centerX - width / 2;
159 | int top = centerY - height / 2;
160 |
161 | float objConf;
162 | int classId;
163 | this->getBestClassInfo(it, numClasses, objConf, classId);
164 |
165 | float confidence = clsConf * objConf;
166 |
167 | boxes.emplace_back(left, top, width, height);
168 | confs.emplace_back(confidence);
169 | classIds.emplace_back(classId);
170 | }
171 | }
172 |
173 |
174 | // NMS 执行非最大抑制,以消除冗余重叠框
175 | std::vector indices;
176 | cv::dnn::NMSBoxes(boxes, confs, confThreshold, iouThreshold, indices);
177 | // std::cout << "amount of NMS indices: " << indices.size() << std::endl;
178 |
179 | std::vector detections;
180 |
181 | for (int idx : indices)
182 | {
183 | Detection det;
184 | det.box = cv::Rect(boxes[idx]);
185 | utilss::scaleCoords(resizedImageShape, det.box, originalImageShape);//缩放坐标
186 |
187 | det.conf = confs[idx];
188 | det.classId = classIds[idx];
189 | detections.emplace_back(det);
190 | }
191 |
192 | return detections;
193 | }
194 |
195 | std::vector YOLODetector::detect(cv::Mat &image, const float& confThreshold = 0.4,
196 | const float& iouThreshold = 0.45)
197 | {
198 | float *blob = nullptr;
199 | std::vector inputTensorShape {1, 3, -1, -1};
200 | this->preprocessing(image, blob, inputTensorShape);//标准化处理 归一化
201 |
202 | size_t inputTensorSize = utilss::vectorProduct(inputTensorShape);
203 |
204 | std::vector inputTensorValues(blob, blob + inputTensorSize);
205 |
206 | std::vector inputTensors;
207 |
208 |
209 | //创建输入tensor
210 | Ort::MemoryInfo memoryInfo = Ort::MemoryInfo::CreateCpu(
211 | OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
212 |
213 | inputTensors.push_back(Ort::Value::CreateTensor(
214 | memoryInfo, inputTensorValues.data(), inputTensorSize,
215 | inputTensorShape.data(), inputTensorShape.size()
216 | ));
217 |
218 |
219 | //推理(score model & input tensor, get back output tensor)
220 | std::vector outputTensors = this->session.Run(Ort::RunOptions{nullptr},
221 | inputNames.data(),
222 | inputTensors.data(),
223 | 1,
224 | outputNames.data(),
225 | 1);
226 |
227 | cv::Size resizedShape = cv::Size((int)inputTensorShape[3], (int)inputTensorShape[2]);
228 | std::vector result = this->postprocessing(resizedShape,
229 | image.size(),
230 | outputTensors,
231 | confThreshold, iouThreshold);//后处理
232 |
233 | delete[] blob;
234 |
235 | return result;
236 | }
237 |
--------------------------------------------------------------------------------
/src/judgeFlaw.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //判断缺陷
4 | void MainWindow::judgeFlaw() {
5 | std::thread t([=]() {
6 | //判断每一个像素点的灰度值是否在阈值
7 | int height = binaryMat.rows;
8 | int width = binaryMat.cols;
9 | int channels = binaryMat.channels();
10 | int numberOfBlack = 0;
11 |
12 | for (int i = 0; i < height; i++)
13 | {
14 | uchar* data = binaryMat.ptr(i);//data指向图像中第i+1行的第一个元素
15 | for (int j = 0; j < width; j++)
16 | {
17 | if (data[j] == 0) //二值图中黑色的部分
18 | {
19 | numberOfBlack++;//黑色的元素的个数
20 | }
21 | }
22 | }
23 | if (numberOfBlack > ui.numBox->value())
24 | {
25 | appendMsg("有漏洞缺陷");
26 | //改变指示灯颜色为红色
27 | this->isHaveFlaw = true;
28 | //g_imagecount++;
29 | //保存缺陷数据
30 | emit signalFlaw();
31 | //发送信号
32 | if (isConnected == true)
33 | {
34 | //emit signalRead();
35 | emit signalWrite();
36 | }
37 | }
38 | });
39 | t.join();
40 | }
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include
3 |
4 | int main(int argc, char* argv[])
5 | {
6 |
7 | QApplication a(argc, argv);
8 | MainWindow w;
9 | w.show();
10 | return a.exec();
11 | }
12 |
--------------------------------------------------------------------------------
/src/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | MainWindow::MainWindow(QWidget *parent)
4 | : QMainWindow(parent)
5 | {
6 | ui.setupUi(this);
7 | pDlg = new setDialog(this);//初始化对话窗口
8 | pDlg1 = new outputImageDialog(this);
9 | pDlg2 = new outputVedioDialog(this);
10 | outputVideo = VideoWriter();//视频录制
11 | ////////////////////////////////主界面设置//////////////////////////////////////
12 |
13 | this->setFixedSize(1205, 747);
14 | this->setWindowIcon(QIcon(":/res/title.png"));
15 | this->setWindowTitle("缺陷检测系统");
16 |
17 |
18 | //设置参数默认值
19 | ui.grayBox->setValue(85.00);
20 | ui.numBox->setValue(20);
21 | ui.portBoxOUT->setValue(0);
22 | ui.portBoxIN->setValue(0);
23 | ui.IP->setText("192.168.1.2");
24 | ui.Port->setText("502");
25 | ui.Point1_X->setValue(30);
26 | ui.Point1_Y->setValue(30);
27 | ui.Point2_X->setValue(620);
28 | ui.Point2_Y->setValue(450);
29 | ui.threshold_value->setValue(80);
30 | ui.wideBox->setValue(1070);
31 | ui.weightChose_2->setText("weights1/unchange_best.onnx");
32 | ui.labelChose_2->setText("class2.names");
33 |
34 | ui.confThreshold->setValue(0.25);
35 | ui.iouThreshold->setValue(0.45);
36 | //设置参数控件的上限值
37 | ui.grayBox->setMaximum(255.00);//灰度值 Spin Box
38 | ui.numBox->setMaximum(768000);
39 |
40 |
41 | ui.wideBox->setSuffix("mm");
42 | //设置状态指示灯为绿色
43 | //QPixmap light = QPixmap(":/res/state_red_48.png");
44 | //ui.lightlabel->setPixmap(light);
45 |
46 |
47 |
48 |
49 |
50 | //ui.widgetTitle->setProperty("form", "title");
51 | ////ui.widgetTop->setProperty("nav", "top");
52 | //ui.labTitle->setText("智能访客管理平台");
53 | //ui.labTitle->setFont(QFont("Microsoft Yahei", 20));
54 | //this->setWindowTitle(ui.labTitle->text());
55 |
56 |
57 | visualTime = new QTimer(this);//创建定时器
58 | modbusDevice = new QModbusTcpClient(this);//创建QModbusDevice对象
59 | connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
60 | appendMsg("ERROR: "+ modbusDevice->errorString());
61 | //qDebug() << "new Error: " << modbusDevice->errorString();
62 | });//错误提示
63 |
64 | connect(modbusDevice, &QModbusClient::stateChanged,this, &MainWindow::onStateChanged);//状态转变
65 |
66 | //connect(modbusDevice, &QModbusClient::stateChanged,this, &MainWindow::onStateChanged);
67 | //connect(myClient, &QModbusClient::stateChanged, this,&MainWindow::onStateChanged);//连接状态发生改变时处理函数
68 | //connect(ui.connectButton, &QPushButton::clicked, [=]() {
69 | // this->connectPLC();
70 | // });
71 |
72 | connect(this, &MainWindow::signalOpen, this, [=]() {
73 |
74 | initGPU = ui.GPU->isChecked();//初始化是否使用GPU
75 | //创建目标检测对象
76 | classNamesPath = ui.labelChose_2->text().toLocal8Bit();
77 | classNames = utilss::loadNames(classNamesPath);
78 | modelPath = ui.weightChose_2->text().toLocal8Bit();
79 | detector = YOLODetector(modelPath, ui.GPU->isChecked(), cv::Size(640, 640));
80 | visualTime->start(40);
81 | });//打开相机signalOpen 开启定时器
82 | connect(visualTime, &QTimer::timeout, this, &MainWindow::receiveData);//显示图片
83 | //connect(this, &MainWindow::signalJudge, this, &MainWindow::judgeFlaw);//判断缺陷
84 | //connect(this, &MainWindow::signalFlaw, this, &MainWindow::saveDataFile);//保存问题图片
85 | //connect(this, &MainWindow::signalFlaw, this, &MainWindow::changeState);//有缺陷状态提示
86 | //connect(this, &MainWindow::signalHandled, this, &MainWindow::changeState);//处理过问题提示
87 |
88 | connect(this, &MainWindow::signalWrite, this, &MainWindow::writeRequst);
89 | connect(this, &MainWindow::signalRead, this, &MainWindow::readCoils);
90 |
91 | //测试
92 | connect(ui.readButton, &QPushButton::clicked, this, &MainWindow::readCoils);
93 | connect(ui.writeButton, &QPushButton::clicked, this, &MainWindow::writeRequst);
94 | }
95 |
96 | ////消息框
97 | //void MainWindow::appendMsg(QString str)
98 | //{
99 | // QDateTime dateTime(QDateTime::currentDateTime());//获取当前时间
100 | // QString qStr = dateTime.toString("yy/MM/dd hh:mm:ss");//转字符串
101 | // ui.textEdit->append(qStr + ": " + str);
102 | //}
103 |
104 |
105 | ////连接状态发生改变时处理函数(connect or discennect)
106 | //void MainWindow::onStateChanged()
107 | //{
108 | // if (myClient->state() == QModbusDevice::UnconnectedState)
109 | // {
110 | // isConnected = false;
111 | // appendMsg("连接失败");
112 | // //emit updateCount("0,0");
113 | //
114 | // }
115 | // else if (myClient->state() == QModbusDevice::ConnectedState)
116 | // {
117 | // isConnected = true;
118 | // appendMsg("连接成功");
119 | // }
120 | // //appendMsg(QString::number(myClient->state()));//2表示连接成功
121 | //}
122 | //连接硬件PLC
123 | //void MainWindow::on_connectPLC_clicked()
124 | //{
125 | // QString IP = ui.IP->text();//获取IP地址
126 | // QString Port = ui.Port->text();//获取端口
127 | // std::thread t([=]() {
128 | // if (!myClient)//当没有创建连接对象时
129 | // {
130 | // appendMsg("Modbus模块建立出错");
131 | // return;
132 | // }
133 | // if (myClient->state() == QModbusDevice::UnconnectedState)//没有连接设备时进行连接
134 | // {
135 | // appendMsg("开始连接");
136 | // //const QUrl url = QUrl::fromUserInput("192.168.1.1:502"); //;//获取IP和端口号
137 | // myClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, IP);
138 | // myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, Port);
139 | //
140 | // myClient->setTimeout(500);//超时时间内没有相应,则设置TimeoutError
141 | // myClient->setNumberOfRetries(3);//请求失败前客户端执行重试的次数
142 | // if (!myClient->connectDevice())//连接设备
143 | // {
144 | // appendMsg("设置连接失败");
145 | // }
146 | // else
147 | // {
148 | // appendMsg("设置连接成功");
149 | // }
150 | // }
151 | // if (myClient->state() == QModbusDevice::ConnectedState)
152 | // {
153 | // isConnected = false;
154 | // myClient->disconnectDevice();//断开连接
155 | //
156 | // }
157 | // appendMsg(QString::number(myClient->state()));//2表示连接成功
158 | //});
159 | //t.join();
160 | //}
161 |
162 | ////打开相机
163 | //void MainWindow::on_startButton_clicked()//打开相机
164 | //{
165 | // if (this->isConnected == false)
166 | // {
167 | // QMessageBox::critical(this, "错误提示框", "请先进行硬件连接\n");
168 | // }
169 | // else
170 | // {
171 | // this->openCamera();
172 | // //设置开始按钮不可点击
173 | // ui.startButton->setEnabled(false);
174 | // ui.closeButton->setEnabled(true);
175 | // }
176 | //}
177 |
178 | ////关闭相机
179 | //void MainWindow::on_closeButton_clicked()//关闭相机
180 | //{
181 | // if (this->isConnected == false)
182 | // {
183 | // QMessageBox::critical(this, "错误提示框", "请先进行硬件连接\n");
184 | // }
185 | // else
186 | // {
187 | // this->closeCamera();
188 | // //设置开始按钮不可点击
189 | // ui.startButton->setEnabled(true);
190 | // ui.closeButton->setEnabled(false);
191 | // }
192 | //}
193 | //打开相机函数
194 | //void MainWindow::openCamera()//打开相机函数
195 | //{
196 | // std::thread t([=]()
197 | // {
198 | // if (!isCameraOpen)
199 | // {
200 | // //初始化OpenNI SDK
201 | // if ((status = OpenNI::initialize()) == STATUS_OK)//表示初始化成功
202 | // {
203 | // appendMsg("初始化成功");
204 | // }
205 | // else
206 | // {
207 | // appendMsg("初始化失败");
208 | // }
209 | //
210 | // //枚举设备
211 | // OpenNI::enumerateDevices(&deviceInfoList);
212 | //
213 | // //任意openni的设备,open的参数为const char*,传递设备的uri来选择特定设备
214 | // if ((status = device.open(ANY_DEVICE)) == STATUS_OK)
215 | // {
216 | // appendMsg("打开设备成功");
217 | // }
218 | // else
219 | // {
220 | // appendMsg("打开设备失败");
221 | // }
222 | // //创建色彩流
223 | // colorStream.create(device, SENSOR_COLOR);
224 | //
225 | // //设置彩色流的模式
226 | // colorMode.setPixelFormat(PIXEL_FORMAT_RGB888);//彩色流的格式
227 | // colorMode.setResolution(640, 480);//设置分辨率,越小所占内存越小
228 | // colorMode.setFps(30);//一秒拍摄15帧
229 | // colorStream.setVideoMode(colorMode);
230 | //
231 | // //打开彩色流
232 | // colorStream.start();
233 | // appendMsg("相机开启");
234 | //
235 | // isCameraOpen = true;
236 | // emit signalOpen();
237 | // }
238 | // });
239 | // t.join();
240 | // return;
241 | //}
242 | //关闭相机函数
243 | //void MainWindow::closeCamera()//关闭相机函数
244 | //{
245 | // if (isCameraOpen)
246 | // {
247 | // delete[] pStreams;
248 | //
249 | // //停止彩色流
250 | // colorStream.stop();
251 | //
252 | // //销毁彩色流
253 | // colorStream.destroy();
254 | //
255 | // //关闭设备
256 | // device.close();
257 | //
258 | // //释放OpenNI资源
259 | // OpenNI::shutdown();//关闭所有驱动并且正确地清除所有
260 | //
261 | // appendMsg("------相机关闭------");
262 | //
263 | // isCameraOpen = false;
264 | // //设置开始按钮不可点击
265 | // ui.startButton->setEnabled(true);
266 | // ui.closeButton->setEnabled(false);
267 | // }
268 | // return;
269 | //}
270 | ////显示图片
271 | //void MainWindow::receiveData() {
272 | // if (isCameraOpen)//传感器打开的话
273 | // {
274 | // std::thread t([=]()
275 | // {
276 | // pStreams = new VideoStream * [1]{ &colorStream };//[1]表示创建的是一个指针形的数组,数组的长度为1,{}大括号括出数据的成员
277 | //
278 | // //根据时间信号读取数据
279 | // int changedStreamDummy;
280 | //
281 | // //等待一帧,返回设备状态
282 | // Status rc = OpenNI::waitForAnyStream(pStreams, 1, &changedStreamDummy, 100);
283 | // if (rc != STATUS_OK)//等待不成功时持续等待
284 | // {
285 | // appendMsg("等待中接收数据");
286 | // }
287 | //
288 | // //读取彩色帧
289 | // rc = colorStream.readFrame(&frame);//rc为读取的成功与否的状态,fream为存储彩色帧的变量
290 | // if (rc == STATUS_OK)//读取帧成功时
291 | // {
292 | // //获取彩色数据
293 | // pColor = (RGB888Pixel*)frame.getData();
294 | // auto colorWidth = frame.getWidth();
295 | // auto colorHeight = frame.getHeight();
296 | //
297 | // cv::Mat rawMat(colorHeight, colorWidth, CV_8UC3, (void*)pColor);//彩色数据按BGR存储
298 | // cv::flip(rawMat, rawMat, 1);//水平反转
299 | // cv::cvtColor(rawMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
300 | //
301 | // //图像处理区域
302 | // Rect rect = Rect(Point2i(ui.Point1_X->value(), ui.Point1_Y->value()), Point2i(ui.Point2_X->value(), ui.Point2_Y->value()));
303 | // cv::rectangle(colorMat, rect,Scalar(255, 0, 0), 2);//画矩形
304 | // cv::cvtColor(colorMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
305 | //
306 | // Mat gray_src1;
307 | // cv::cvtColor(colorMat, gray_src1, cv::COLOR_BGR2GRAY);//bgr转灰度图
308 | //
309 | // rawMat.copyTo(tailorMat);
310 | // tailorMat=tailorMat(rect);//裁剪出矩形区域
311 | // cv::cvtColor(tailorMat, tailorMat, cv::COLOR_BGR2RGB);//bgr转rgb
312 | //
313 | //
314 | // cv::cvtColor(tailorMat, gray_src, cv::COLOR_BGR2GRAY);//bgr转灰度图
315 | // cv::threshold(gray_src, binaryMat, ui.grayBox->value(), 255, 0);//60为阈值,255为最大值,0:超过60改为255.
316 | //
317 | // Mat imageROI = gray_src1(rect);
318 | // binaryMat.copyTo(imageROI);
319 | //
320 | //
321 | // Mat canny_output;
322 | // vector> contours;//建立二维点元素数组 全部发现的轮廓对象
323 | // vector hierachy;//层次数组
324 | //
325 | // Canny(gray_src, canny_output, ui.threshold_value->value(), ui.threshold_value->value() * 2, 3, false);//边缘提取
326 | // findContours(canny_output, contours, hierachy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));//发现轮廓
327 | //
328 | // vector contours_moments(contours.size());//矩数组
329 | // vector ccs(contours.size());//中心点坐标数组 x y
330 | // for (size_t i = 0; i < contours.size(); i++) {
331 | // contours_moments[i] = moments(contours[i]);//求矩
332 | // ccs[i] = Point(static_cast(contours_moments[i].m10 / contours_moments[i].m00), static_cast(contours_moments[i].m01 / contours_moments[i].m00));//求中心坐标 static_cast处理范围
333 | // }
334 | //
335 | // Mat drawImg;// = Mat::zeros(src.size(), CV_8UC3);
336 | // colorMat.copyTo(drawImg);
337 | // RNG rng(12345);//随机数
338 | // int P1P2_wide=(ui.Point2_X->value() - ui.Point1_X->value());//像素宽度
339 | // double centerPointRatio = ui.wideBox->value() / P1P2_wide;//比例
340 | // for (size_t i = 0; i < contours.size(); i++) {
341 | // if (contours[i].size() < 1000) {//阈值 轮廓对象小于100忽略
342 | // continue;
343 | // }
344 | // Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
345 | //
346 | //
347 | // appendMsg("area "+ QString::number(i)+":"+ QString::number(contourArea(contours[i])));
348 | // appendMsg("center point x:"+ QString::number(ccs[i].x * centerPointRatio)+" y:"+ QString::number(ccs[i].y*centerPointRatio));
349 | //
350 | // //printf("center point x : %.2f y : %.2f\n", ccs[i].x+ ui.Point1_X->value(), ccs[i].y+ ui.Point1_Y->value());//打印中点坐标
351 | // //printf("contours %d area : %.2f\n", i, contourArea(contours[i]));//打印面积
352 | //
353 | // drawContours(drawImg, contours, i, color, 2, 8, hierachy, 0, Point(ui.Point1_X->value(), ui.Point1_Y->value()));//绘画轮廓层次
354 | // circle(drawImg,Point(ccs[i].x + ui.Point1_X->value(), ccs[i].y + ui.Point1_Y->value()), 1, color, 2, 8);//绘画中点
355 | // }
356 | //
357 | // //binaryMat.convertTo(binaryMat2, CV_8UC3);
358 | //
359 | // ////【2】定义一个Mat类型并给其设定ROI区域
360 | // //Mat colorMat2;
361 | // //colorMat.copyTo(colorMat2);
362 | // //Mat imageROI = colorMat2(rect); //450,20为自定义起始点坐标
363 | // //binaryMat.copyTo(colorMat2, imageROI);
364 | //
365 | // //ImgR = QImage((const uchar*)colorMat.data, colorMat.cols, colorMat.rows, QImage::Format_RGB888);
366 | // ImgR = QImage((const uchar*)drawImg.data, drawImg.cols, drawImg.rows, QImage::Format_RGB888);
367 | // QPixmap pixmap1 = QPixmap::fromImage(ImgR);
368 | // pixmap1 = pixmap1.scaled(pixmap1.width() , pixmap1.height() );
369 | // ui.rawlabel->setPixmap(pixmap1);
370 | //
371 | // //ImgB = QImage((const uchar*)drawImg.data, drawImg.cols, drawImg.rows, QImage::QImage::Format_RGB888);
372 | // ImgB = QImage((const uchar*)gray_src1.data, gray_src1.cols, gray_src1.rows, QImage::QImage::Format_Indexed8);
373 | // QPixmap pixmap2 = QPixmap::fromImage(ImgB);
374 | // pixmap2 = pixmap2.scaled(pixmap2.width() , pixmap2.height() );
375 | // ui.fanllabel->setPixmap(pixmap2);
376 | // //ui.fanllabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
377 | // ui.rawlabel->setScaledContents(true);
378 | // ui.fanllabel->setScaledContents(true);
379 | // }
380 | // if (colorMat.empty())//灰度图为空
381 | // {
382 | // appendMsg("彩色图为空");
383 | // }
384 | // else
385 | // {
386 | // emit signalJudge();
387 | // }
388 | // });
389 | // t.join();
390 | // }
391 | //}
392 | ////判断缺陷
393 | //void MainWindow::judgeFlaw() {
394 | // std::thread t([=]() {
395 | // //判断每一个像素点的灰度值是否在阈值
396 | // int height = binaryMat.rows;
397 | // int width = binaryMat.cols;
398 | // int channels = binaryMat.channels();
399 | // int numberOfBlack = 0;
400 | //
401 | // for (int i = 0; i < height; i++)
402 | // {
403 | // uchar* data = binaryMat.ptr(i);//data指向图像中第i+1行的第一个元素
404 | // for (int j = 0; j < width; j++)
405 | // {
406 | // if (data[j] == 0) //二值图中黑色的部分
407 | // {
408 | // numberOfBlack++;//黑色的元素的个数
409 | // }
410 | // }
411 | // }
412 | // if (numberOfBlack > ui.numBox->value())
413 | // {
414 | // appendMsg("有漏洞缺陷");
415 | // //改变指示灯颜色为红色
416 | // this->isHaveFlaw = true;
417 | // g_imagecount++;
418 | // //保存缺陷数据
419 | // emit signalFlaw();
420 | // //发送信号
421 | // if (isConnected == true)
422 | // {
423 | // //emit signalRead();
424 | // emit signalWrite();
425 | // }
426 | // }
427 | // });
428 | // t.join();
429 | //}
430 | //保存缺陷图片
431 | //void MainWindow::saveDataFile()
432 | //{
433 | // std::thread t([=]() {
434 | // //选择一个路径
435 | // QDateTime dateTime(QDateTime::currentDateTime());//构造函数
436 | // QString qStr = dateTime.toString("yy-MM-dd-hh-mm-ss");
437 | // QString filePath = "C:/hole_detection/dataset/" + qStr + "_" + QString::number(g_imagecount) + ".bmp";
438 | // cv::imwrite(filePath.toStdString(), binaryMat);//将彩色图保存到本地
439 | // //qDebug() << colorMat.rows;
440 | // appendMsg("缺陷数据保存完成,查看:C:/hole_detection/dataset");
441 | // });
442 | // t.join();
443 | //}
444 | //改变指示灯的状态
445 | //void MainWindow::changeState()
446 | //{
447 | // QString lightPath = NULL;
448 | // //有缺陷提示
449 | // if (this->isHaveFlaw == true)
450 | // {
451 | // lightPath = ":/res/state_red_48.png";
452 | // }
453 | // //处理过缺陷恢复原来状态
454 | // if (this->isHandled == true)
455 | // {
456 | // lightPath = ":/res/state_green_48.png";
457 | // }
458 | // QPixmap light = QPixmap(lightPath);
459 | // ui.lightlabel->setPixmap(light);
460 | //}
461 | ////给PLC写数据s
462 | //void MainWindow::writeRequst()
463 | //{
464 | // int star_add = ui.portBoxOUT->value();//写入数据的起始地址
465 | // quint16 value = 0;//要写入的数据
466 | // quint16 number = 1;//写入数据的个数
467 | // if (!myClient)
468 | // {
469 | // appendMsg("Modbus模块建立出错");
470 | // return;
471 | // }
472 | // //quint16 number1 = static_cast(number);
473 | // QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::Coils, star_add, number);//参数:寄存器类型,数据起始地址,数据大小
474 | // //int a = writeUnit.valueCount();
475 | // //for (uint i = 0; i < writeUnit.valueCount(); i++)//循环写入
476 | // //{
477 | // //int ii = static_cast(i);//将uint类型数值静态转换为int型。
478 | // //QString st = str1.mid(ii, 1);//获取指定位置子串,参数1从哪个开始,参数2一共几位
479 | // writeUnit.setValue(0, value);//将用户输出的数据设置到写容器中
480 | // //quint16 a = writeUnit.value(0);
481 | // if (auto* reply = myClient->sendWriteRequest(writeUnit, 0xFF))//1为服务器的serveAddress
482 | // {
483 | // if (!reply->isFinished())//返回未终止时
484 | // {
485 | // connect(reply, &QModbusReply::finished, this, [=]() {
486 | // if (reply->error() == QModbusDevice::ProtocolError)
487 | // {
488 | // QString errorM1 = QString::fromLocal8Bit("Write response error: %1 (Mobus exception: 0x%2)").arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16);
489 | // appendMsg(errorM1);
490 | // }
491 | // else if (reply->error() != QModbusDevice::NoError)//错误
492 | // {
493 | // QString errorM2 = QString::fromLocal8Bit("Write response error: %1 (code: 0x%2)").arg(reply->errorString()).arg(reply->error(), -1, 16);
494 | // appendMsg(errorM2);
495 | // }
496 | // appendMsg("写入成功" + QString::number(value));
497 | // emit signalRead();
498 | // reply->deleteLater();
499 | // });
500 | // }
501 | // else
502 | // {
503 | // reply->deleteLater();// broadcast replies return immediately
504 | // }
505 | // }
506 | // else
507 | // {
508 | // QString errorM3 = ("Write error: ") + myClient->errorString();
509 | // appendMsg(errorM3);
510 | // }
511 | //}
512 | ////读取写的内容
513 | //bool MainWindow::readCoils()
514 | //{
515 | // int start_add = ui.portBoxIN->value();//待读取的线圈的地址
516 | // quint16 numbers = 1;//读一位
517 | // if (!myClient->state() == QModbusDevice::ConnectedState)
518 | // {
519 | // return false;
520 | // }
521 | //
522 | // QModbusDataUnit readUnit(QModbusDataUnit::Coils, start_add, numbers);
523 | // if (QModbusReply* reply = myClient->sendReadRequest(readUnit, 0xFF))
524 | // {
525 | // //appendMsg("serverAddress: " + QString::number(reply->serverAddress()));
526 | // //bool a = reply->isFinished();
527 | // if (!reply->isFinished())//未返回结束
528 | // {
529 | // connect(reply, &QModbusReply::finished, this, &MainWindow::readRead_coils);
530 | // return true;
531 | // }
532 | // else
533 | // {
534 | // appendMsg("应答结束");
535 | // delete reply;
536 | // return false;
537 | // }
538 | // }
539 | // else
540 | // {
541 | // appendMsg("发送读请求失败");
542 | // return false;
543 | // }
544 | // return false;
545 | //}
546 |
547 | ////接收到读取请求后执行的槽函数
548 | //void MainWindow::readRead_coils()
549 | //{
550 | // //QModbusReply这个类存储了来自client的数据,sender()返回发送信号的对象的指针
551 | // QModbusReply* reply = qobject_cast(sender());
552 | // if (!reply)
553 | // {
554 | // return;
555 | // }
556 | // if (reply->error() == QModbusDevice::NoError)
557 | // {
558 | // //处理成功返回的数据
559 | // const QModbusDataUnit unit = reply->result();
560 | // quint16 res = unit.value(0); //读取第一位的数据
561 | // if (res == 1)
562 | // {
563 | // appendMsg("读取成功" + QString::number(res));
564 | // //设置指示灯状态为绿色
565 | // this->isHandled = true;
566 | // emit this->signalHandled();
567 | // }
568 | // }
569 | // else if (reply->error() == QModbusDevice::ProtocolError)//协议错误
570 | // {
571 | // QString errorR1 = QString::fromLocal8Bit("Read response error: %1 (Mobus exception: 0x%2)").arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16);
572 | // appendMsg(errorR1);
573 | // }
574 | // else
575 | // {
576 | // QString errorM2 = QString::fromLocal8Bit("Read response error: %1 (code: 0x%2)").arg(reply->errorString()).arg(reply->error(), -1, 16);
577 | // appendMsg(errorM2);
578 | // }
579 | // reply->deleteLater();
580 | //}
--------------------------------------------------------------------------------
/src/onStateChanged.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include
3 | //连接状态发生改变时处理函数(connect or discennect)
4 | void MainWindow::onStateChanged(int state)
5 | {
6 | //判断Modbus设备连接是否处于连接状态
7 | if (state == QModbusDevice::UnconnectedState)
8 | {
9 | isConnected = false;
10 | appendMsg("已断开");
11 | //qDebug() << "TCP Client连接到Server 未连接";
12 | ui.connectPLC->setText(tr("连接PLC"));
13 |
14 | //ui.startButton->setEnabled(false);
15 | //ui.closeButton->setEnabled(false);
16 |
17 | }
18 | else if (state == QModbusDevice::ConnectingState)
19 | {
20 | isConnected = false;
21 | appendMsg("TCP Client正在连接Server");
22 | //qDebug() << "TCP Client正在连接Server";
23 | }
24 | else if (state == QModbusDevice::ConnectedState)
25 | {
26 | isConnected = true;
27 | appendMsg("TCP Client已经连接到Server");
28 | //qDebug() << "TCP Client已经连接到Server";
29 | ui.connectPLC->setText(tr("断开连接"));
30 |
31 | //ui.startButton->setEnabled(true);
32 | //ui.closeButton->setEnabled(true);
33 |
34 | }
35 | else if (state == QModbusDevice::ClosingState)
36 | {
37 | appendMsg("设备已经关闭");
38 | //qDebug() << "设备已经被关闭";
39 | }
40 |
41 | //appendMsg(QString::number(modbusDevice->state()));//2表示连接成功
42 | }
--------------------------------------------------------------------------------
/src/on_closeButton_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //关闭相机
4 | void MainWindow::on_closeButton_clicked()//关闭相机
5 | {
6 | if (this->isConnected == false)
7 | {
8 | QMessageBox::critical(this, "错误提示框", "请先进行硬件连接\n");
9 | }
10 | else
11 | {
12 | appendMsg("------检测结束------");
13 | //恢复切换切换GPU CPU
14 | ui.GPU->setCheckable(true);
15 | ui.CPU->setCheckable(true);
16 |
17 | visualTime->stop();
18 | if(isCamera)this->closeCamera();
19 | else if (isVideo) {
20 | this->vid_capture.release();
21 | isCameraOpen = false;
22 | //设置开始按钮不可点击
23 | ui.startButton->setEnabled(true);
24 | ui.closeButton->setEnabled(false);
25 | }
26 | else if (isImage) {
27 | isCameraOpen = false;
28 | //设置开始按钮不可点击
29 | ui.startButton->setEnabled(true);
30 | ui.closeButton->setEnabled(false);
31 | }
32 |
33 | ui.setupdialog->setEnabled(true);
34 | //设置开始按钮不可点击
35 | /* ui.startButton->setEnabled(true);
36 | ui.closeButton->setEnabled(false);*/
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/on_connectPLC_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | //连接硬件PLC
3 | void MainWindow::on_connectPLC_clicked()
4 | {
5 | QString IP = ui.IP->text();//获取IP地址
6 | QString Port1 = ui.Port->text();//获取端口
7 | int Port = Port1.toInt();
8 | //std::thread t([=]() {
9 | if (!modbusDevice)
10 | {
11 | appendMsg("Modbus模块建立出错");
12 | return;
13 | }
14 |
15 | if (modbusDevice->state() != QModbusDevice::ConnectedState)
16 | {
17 | appendMsg("开始连接");
18 | modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, IP);
19 | modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, Port);
20 |
21 | //设置超时时间
22 | modbusDevice->setTimeout(50); //0.05秒
23 | //设置失败重试次数
24 | modbusDevice->setNumberOfRetries(3);
25 | if (!modbusDevice->connectDevice())////连接到服务端
26 | {
27 | appendMsg("设备连接失败");
28 | //qDebug() << "modbusDevice->connectDevice failed";
29 | }
30 | else
31 | {
32 | //appendMsg("设置连接成功");
33 | }
34 | }
35 | else
36 | {
37 | //断开连接
38 | isConnected = false;
39 | modbusDevice->disconnectDevice();
40 | ui.connectPLC->setText(tr("连接PLC"));
41 |
42 | //ui.startButton->setEnabled(false);
43 | //ui.closeButton->setEnabled(false);
44 |
45 | }
46 | //appendMsg(QString::number(modbusDevice->state()));//2表示连接成功
47 |
48 |
49 |
50 | //if (!myClient)//当没有创建连接对象时
51 | //{
52 | // appendMsg("Modbus模块建立出错");
53 | // return;
54 | //}
55 | //if (myClient->state() == QModbusDevice::UnconnectedState)//没有连接设备时进行连接
56 | //{
57 | // appendMsg("开始连接");
58 | // //const QUrl url = QUrl::fromUserInput("192.168.1.1:502"); //;//获取IP和端口号
59 | // myClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, IP);
60 | // myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, Port);
61 |
62 | // myClient->setTimeout(500);//超时时间内没有相应,则设置TimeoutError
63 | // myClient->setNumberOfRetries(3);//请求失败前客户端执行重试的次数
64 | // if (!myClient->connectDevice())//连接设备
65 | // {
66 | // appendMsg("设置连接失败");
67 | // }
68 | // else
69 | // {
70 | // appendMsg("设置连接成功");
71 | // }
72 | //}
73 | //if (myClient->state() == QModbusDevice::ConnectedState)
74 | //{
75 | // isConnected = false;
76 | // myClient->disconnectDevice();//断开连接
77 | //}
78 | //appendMsg(QString::number(myClient->state()));//2表示连接成功
79 | /* });
80 | t.join();*/
81 | }
--------------------------------------------------------------------------------
/src/on_imageDetection_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | void MainWindow::on_imageDetection_clicked()//目标检测被点击
4 | {
5 | //std::thread t([=]()
6 | //{
7 | ui.GPU->setAutoExclusive(false);
8 | ui.CPU->setAutoExclusive(false);
9 | ui.GPU->setChecked(false);
10 | ui.CPU->setChecked(false);
11 | ui.GPU->setCheckable(false);
12 | ui.CPU->setCheckable(false);
13 | ui.GPU->setAutoExclusive(true);
14 | ui.CPU->setAutoExclusive(true);
15 | /*});
16 | t.join();*/
17 | }
--------------------------------------------------------------------------------
/src/on_labelChoose_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 |
4 | void MainWindow::on_labelChoose_clicked() {
5 | QString fileName = QFileDialog::getOpenFileName(this, QStringLiteral("Label"), "./", QStringLiteral("*names"));
6 | ui.labelChose_2->setText(fileName);
7 | classNamesPath = fileName.toLocal8Bit();
8 | classNames = utilss::loadNames(classNamesPath);
9 | }
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/on_objectDetection_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | void MainWindow::on_objectDetection_clicked()//目标检测被点击
4 | {
5 | ui.GPU->setAutoExclusive(false);
6 | ui.CPU->setAutoExclusive(false);
7 | ui.GPU->setCheckable(true);
8 | ui.CPU->setCheckable(true);
9 | if (visualTime->isActive()) {
10 | if (initGPU) {
11 | ui.GPU->setChecked(true);
12 | ui.CPU->setChecked(false);
13 | ui.CPU->setCheckable(false);
14 | }
15 | else {
16 | ui.GPU->setChecked(false);
17 | ui.CPU->setChecked(true);
18 | ui.GPU->setCheckable(false);
19 | }
20 | }
21 |
22 | ui.GPU->setAutoExclusive(true);
23 | ui.CPU->setAutoExclusive(true);
24 | }
--------------------------------------------------------------------------------
/src/on_setupdialog_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | void MainWindow::on_setupdialog_clicked() {
4 |
5 | //setDialog* s = new setDialog;
6 | ////setDialog s;
7 | int nResult = -1;
8 | pDlg->setWindowTitle(tr("检测对象设置"));
9 | nResult=pDlg->exec();
10 | if (nResult == setDialog::Accepted) {//确认
11 | pDlg->getMessage(isCamera, isVideo, isImage,isResolvingPower,vedioPath, imagePath);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/on_startButton_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //打开相机
4 | void MainWindow::on_startButton_clicked()//打开相机
5 | {
6 | if (this->isConnected == false)
7 | {
8 | QMessageBox::critical(this, "错误提示框", "请先连接PLC\n");
9 | }
10 | else
11 | {
12 | //开始检测不可切换GPU CPU
13 | if (ui.GPU->isChecked()) {
14 | ui.CPU->setCheckable(false);
15 | }
16 | if (ui.CPU->isChecked()) {
17 | ui.GPU->setCheckable(false);
18 | }
19 |
20 |
21 |
22 | if (isCamera) {
23 |
24 | this->openCamera();
25 |
26 |
27 | }
28 | else if (isVideo) {
29 | if (!isCameraOpen)
30 | {
31 | vid_capture= VideoCapture(vedioPath);//创建一个视频捕捉对象
32 | QString fps = QString::number(vid_capture.get(5),'f',0);//源视频帧数
33 | QString frame_count = QString::number(vid_capture.get(7),'f', 0);//统计视频帧数
34 | appendMsg("------视频检测------");
35 | appendMsg("帧数 :" + fps+" "+"总帧数 :" + frame_count);
36 | isCameraOpen = true;
37 | emit signalOpen();
38 | //设置开始按钮不可点击
39 | ui.startButton->setEnabled(false);
40 | ui.closeButton->setEnabled(true);
41 | ui.setupdialog->setEnabled(false);
42 | }
43 | }
44 | else if (isImage) {
45 | appendMsg("------图片检测------");
46 | isCameraOpen = true;
47 | emit signalOpen();
48 | //设置开始按钮不可点击
49 | ui.startButton->setEnabled(false);
50 | ui.closeButton->setEnabled(true);
51 | ui.setupdialog->setEnabled(false);
52 | }
53 | ////设置开始按钮不可点击
54 | //ui.startButton->setEnabled(false);
55 | //ui.closeButton->setEnabled(true);
56 |
57 |
58 | }
59 | }
--------------------------------------------------------------------------------
/src/on_weightChoose_clicked.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 |
4 | void MainWindow::on_weightChoose_clicked() {
5 |
6 | QString fileName = QFileDialog::getOpenFileName(this, QStringLiteral("Weight"), "./weights1", QStringLiteral("*onnx"));
7 | ui.weightChose_2->setText(fileName);
8 | modelPath = fileName.toLocal8Bit();
9 |
10 | }
--------------------------------------------------------------------------------
/src/openCamera.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | //打开相机函数
3 | void MainWindow::openCamera()//打开相机函数
4 | {
5 | //std::thread t([=]()
6 | // {
7 | if (!isCameraOpen)
8 | {
9 | //初始化OpenNI SDK
10 | if ((status = OpenNI::initialize()) == STATUS_OK)//表示初始化成功
11 | {
12 | //appendMsg("初始化成功");
13 | //枚举设备
14 | OpenNI::enumerateDevices(&deviceInfoList);
15 |
16 | //任意openni的设备,open的参数为const char*,传递设备的uri来选择特定设备
17 | if ((status = device.open(ANY_DEVICE)) == STATUS_OK)
18 | {
19 | appendMsg("打开设备成功");
20 | ui.setupdialog->setEnabled(false);
21 | ui.startButton->setEnabled(false);
22 | ui.closeButton->setEnabled(true);
23 | //创建色彩流
24 | colorStream.create(device, SENSOR_COLOR);
25 |
26 | //设置彩色流的模式
27 | colorMode.setPixelFormat(PIXEL_FORMAT_RGB888);//彩色流的格式
28 |
29 |
30 | if (isResolvingPower) {
31 | colorMode.setResolution(640, 480);//设置分辨率,越小所占内存越小
32 | }
33 | else {
34 | colorMode.setResolution(1280, 960);//设置分辨率,越小所占内存越小
35 | }
36 |
37 |
38 | colorMode.setFps(30);//一秒拍摄15帧
39 | colorStream.setVideoMode(colorMode);
40 |
41 | //打开彩色流
42 | colorStream.start();
43 | appendMsg("------相机检测------");
44 |
45 | isCameraOpen = true;
46 | emit signalOpen();
47 | }
48 | else
49 | {
50 | //appendMsg("打开设备失败,请连接相机,并重新开始!");
51 | visualTime->stop();
52 | ui.setupdialog->setEnabled(true);
53 | QMessageBox::critical(this, "错误提示框", "打开设备失败,请连接相机,并重新开始!\n");
54 |
55 | }
56 |
57 | }
58 | else
59 | {
60 | appendMsg("初始化失败");
61 | }
62 |
63 |
64 | }
65 | /* });
66 | t.join();*/
67 | return;
68 | }
--------------------------------------------------------------------------------
/src/openni.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | using namespace std;
8 |
9 | using namespace cv;
10 |
11 | int main()
12 | {
13 |
14 | cv::VideoWriter outputVideo;
15 | //cv::Size S = cv::Size((int)vid_capture.get(CAP_PROP_FRAME_WIDTH),
16 | // (int)vid_capture.get(CAP_PROP_FRAME_HEIGHT));
17 |
18 | //打开视频路径,设置基本信息 open函数中你参数跟上面给出的VideoWriter函数是一样的
19 | string str = "E:/programs data/QT/Defect detection/detection_data/1.mp4";
20 | outputVideo.open(str, VideoWriter::fourcc('H', '2', '6', '4'), 25, Size(640,480), true);
21 |
22 | //定义oni文件中视频的总帧数以及得到的图片的保存目录
23 | int total = 0;
24 | string imagefile = "E:/programs data/QT/Defect detection/detection_data";
25 |
26 | //初始化OpenNI环境
27 | openni::OpenNI::initialize();
28 |
29 | //声明设备并打开oni文件
30 | openni::Device fromonifile;
31 | fromonifile.open("E:/programs data/QT/Defect detection/detection_data/1.oni");
32 |
33 | //声明控制对象,这对视频流的控制起到了关键作用
34 | openni::PlaybackControl* pController = fromonifile.getPlaybackControl();
35 |
36 | //声明视频流对象以及帧对象
37 | openni::VideoStream streamColor;
38 | openni::VideoFrameRef frameColor;
39 |
40 | //验证是否有彩色传感器(是否有彩色视频)和建立与设备想关联的视频流
41 | if (fromonifile.hasSensor(openni::SENSOR_COLOR))
42 | {
43 | if (streamColor.create(fromonifile, openni::SENSOR_COLOR) == openni::STATUS_OK)
44 | {
45 | cout << "建立视频流成功" << endl;
46 | }
47 | else
48 | {
49 | cerr << "ERROR: 建立视频流没有成功" << endl;
50 | system("pause");
51 | return -1;
52 | }
53 | }
54 | else
55 | {
56 | cerr << "ERROR: 该设备没有彩色传感器" << endl;
57 | system("pause");
58 | return -1;
59 | }
60 |
61 | //建立显示窗口
62 | cv::namedWindow("Image");
63 |
64 | //获取总的视频帧数并将该设备的速度设为-1以便能留出足够的时间对每一帧进行处理、显示和保存
65 | total = pController->getNumberOfFrames(streamColor);
66 | pController->setSpeed(-1);
67 |
68 | //开启视频流
69 | streamColor.start();
70 | for (int i = 1; i <= total; ++i)
71 | {
72 | //读取视频流的当前帧
73 | streamColor.readFrame(&frameColor);
74 |
75 | cout << "当前正在读的帧数是:" << frameColor.getFrameIndex() << endl;
76 | cout << "当前的循环次数是: " << i << endl;
77 |
78 | //将帧保存到Mat中并且将其转换到BGR模式,因为在OpenCV中图片的模式是BGR
79 | cv::Mat rgbImg(frameColor.getHeight(), frameColor.getWidth(), CV_8UC3, (void*)frameColor.getData());
80 | cv::Mat bgrImg;
81 | cvtColor(rgbImg, bgrImg, cv::COLOR_RGB2BGR);
82 |
83 | //将每一帧按顺序帧保存到图片目录下
84 | char imagefullname[255];
85 | char imagenum[50];
86 | sprintf(imagenum, "\\%03d.png", i);
87 | strcpy(imagefullname, imagefile.data());
88 | strcat(imagefullname, imagenum);
89 | //cv::imwrite(imagefullname, bgrImg);
90 | outputVideo << rgbImg;
91 |
92 | //显示当前帧
93 | cv::imshow("Image", bgrImg);
94 | if (cv::waitKey(30) == 27)
95 | {
96 | break;
97 | }
98 | }
99 |
100 | outputVideo.release();
101 |
102 | //销毁显示窗口
103 | cv::destroyWindow("Image");
104 |
105 | //关闭视频流
106 | streamColor.destroy();
107 |
108 | //关闭设备
109 | fromonifile.close();
110 |
111 | //关闭OpenNI
112 | openni::OpenNI::shutdown();
113 |
114 | return 0;
115 | }
--------------------------------------------------------------------------------
/src/outputimagedialog.cpp:
--------------------------------------------------------------------------------
1 | #include "outputimagedialog.h"
2 |
3 | outputImageDialog::outputImageDialog(QWidget *parent)
4 | : QDialog(parent)
5 | {
6 | ui.setupUi(this);
7 | }
8 |
9 | outputImageDialog::~outputImageDialog()
10 | {
11 | }
12 | void outputImageDialog::on_acceptButton_clicked() {
13 | this->accept();
14 | }
15 | void outputImageDialog::on_rejectButton_clicked() {
16 | reject();
17 | }
18 | void outputImageDialog::on_choseButton_clicked() {
19 | QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
20 | //QString fileName = QFileDialog::getOpenFileName(NULL, QStringLiteral("选择视频"), "./images", QStringLiteral("*mp4"));
21 | ui.imageSaveChose->setText(dir);
22 | }
23 |
24 | void outputImageDialog::getMessage(bool& isSaveImage1, bool& isSaveImage2, bool& isSaveImage3, QString& imageSavePath) {
25 | isSaveImage1 = ui.saveImage_1->isChecked();
26 | isSaveImage2 = ui.saveImage_2->isChecked();
27 | isSaveImage3 = ui.saveImage_3->isChecked();
28 | imageSavePath = ui.imageSaveChose->text();
29 |
30 | }
--------------------------------------------------------------------------------
/src/outputvediodialog.cpp:
--------------------------------------------------------------------------------
1 | #include "outputvediodialog.h"
2 |
3 | outputVedioDialog::outputVedioDialog(QWidget *parent)
4 | : QDialog(parent)
5 | {
6 | ui.setupUi(this);
7 | }
8 |
9 | outputVedioDialog::~outputVedioDialog()
10 | {
11 | }
12 | void outputVedioDialog::on_acceptButton_clicked() {
13 | this->accept();
14 | }
15 | void outputVedioDialog::on_rejectButton_clicked() {
16 | reject();
17 | }
18 | void outputVedioDialog::on_choseButton_clicked() {
19 | QString dir = QFileDialog::getSaveFileName(this, "save file", "E:/programs data/QT/Defect detection/detection_data/vedioSave", "(*.mp4);");
20 | //QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
21 | //QString fileName = QFileDialog::getOpenFileName(NULL, QStringLiteral("选择视频"), "./images", QStringLiteral("*mp4"));
22 | ui.videoSaveChose->setText(dir);
23 | }
24 |
25 | void outputVedioDialog::getMessage(bool& saveVedioLeft, bool& saveVedioRight, QString& videoSaveChose) {
26 |
27 | saveVedioLeft = ui.saveVedioLeft->isChecked();
28 | saveVedioRight = ui.saveVedioRight->isChecked();
29 | videoSaveChose = ui.videoSaveChose->text();
30 | }
31 |
--------------------------------------------------------------------------------
/src/readCoils.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //读取内容
4 | bool MainWindow::readCoils()
5 | {
6 |
7 | int start_add = ui.portBoxIN->value();//待读取的线圈的地址
8 | quint16 numbers = 10;//读一位
9 |
10 | //QModbusDataUnit::Coils 从地址0开始读取10个线圈值
11 | QModbusDataUnit data(QModbusDataUnit::Coils, start_add, numbers);
12 |
13 | auto reply = modbusDevice->sendReadRequest(data, 0x1);
14 | if (nullptr == reply)
15 | {
16 | // appendMsg("发送请求数据失败: " + modbusDevice->errorString());
17 | //qDebug() << "发送请求数据失败: " << modbusDevice->errorString();
18 | return false;
19 | }
20 | else
21 | {
22 | if (!reply->isFinished())
23 | {
24 | connect(reply, &QModbusReply::finished, this, &MainWindow::readReady_coils);
25 | }
26 | else
27 | {
28 | //broadcast replies return immediately
29 | delete reply;
30 | return false;
31 | }
32 | }
33 |
34 | //int start_add = ui.portBoxIN->value();//待读取的线圈的地址
35 | //quint16 numbers = 1;//读一位
36 | ///*if (!modbusDevice->state() == QModbusDevice::ConnectedState)
37 | //{
38 | // return false;
39 | //}*/
40 |
41 | //QModbusDataUnit readUnit(QModbusDataUnit::Coils, start_add, numbers);
42 | //if (QModbusReply* reply = modbusDevice->sendReadRequest(readUnit, 0xFF))
43 | //{
44 | // //appendMsg("serverAddress: " + QString::number(reply->serverAddress()));
45 | // //bool a = reply->isFinished();
46 | // if (!reply->isFinished())//未返回结束
47 | // {
48 | // connect(reply, &QModbusReply::finished, this, &MainWindow::readReady_coils);
49 | // return true;
50 | // }
51 | // else
52 | // {
53 | // appendMsg("应答结束");
54 | // delete reply;
55 | // return false;
56 | // }
57 | //}
58 | //else
59 | //{
60 | // appendMsg("发送读请求数据失败");
61 | // return false;
62 | //}
63 | //return false;
64 | }
--------------------------------------------------------------------------------
/src/readReady_coils.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //接收到读取请求后执行的槽函数
4 | void MainWindow::readReady_coils()
5 | {
6 | //QModbusReply这个类存储了来自client的数据,sender()返回发送信号的对象的指针
7 | QModbusReply* reply = qobject_cast(sender());
8 | if (!reply)
9 | {
10 | return;
11 | }
12 | //判断是否出错
13 | if (reply->error() == QModbusDevice::NoError)
14 | {
15 | //处理成功返回的数据
16 | const QModbusDataUnit unit = reply->result();
17 | qDebug() << "读取成功,数据为:" << unit.values();
18 | quint16 res = unit.value(0); //读取第一位的数据
19 | appendMsg("读取成功,数据为:" + QString::number(res));
20 |
21 |
22 | //if (res == 1)
23 | //{
24 | // appendMsg("读取成功" + QString::number(res));
25 | // //设置指示灯状态为绿色
26 | // this->isHandled = true;
27 | // emit this->signalHandled();
28 | //}
29 | }
30 | else if (reply->error() == QModbusDevice::ProtocolError)//协议错误
31 | {
32 | //QString errorR1 = "读取响应协议错误:" + reply->errorString();
33 | //QString errorR1 =QString::fromLocal8Bit("Read response error: %1 (Mobus exception: 0x%2)").arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16);
34 | //appendMsg(errorR1);
35 | }
36 | else
37 | {
38 | //QString errorM2 = "读取响应错误:" + reply->errorString();
39 | //QString errorM2 = QString::fromLocal8Bit("Read response error: %1 (code: 0x%2)").arg(reply->errorString()).arg(reply->error(), -1, 16);
40 | //appendMsg(errorM2);
41 | }
42 | //删除reply
43 | reply->deleteLater();
44 | }
--------------------------------------------------------------------------------
/src/receiveData.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //显示图片
4 | void MainWindow::receiveData() {
5 | if (isCameraOpen)//传感器打开的话
6 | {
7 | //std::thread t([=]()
8 | //{
9 | Status isCameraSuccess= STATUS_ERROR;//读取相机帧是否成功
10 | bool isVedioSuccess = false;//读取视频帧是否成功
11 | if (isCamera) {
12 | pStreams = new VideoStream * [1]{ &colorStream };//[1]表示创建的是一个指针形的数组,数组的长度为1,{}大括号括出数据的成员
13 |
14 | //根据时间信号读取数据
15 | int changedStreamDummy;
16 |
17 |
18 | //等待一帧,返回设备状态
19 | isCameraSuccess = OpenNI::waitForAnyStream(pStreams, 1, &changedStreamDummy, 100);
20 | if (isCameraSuccess != STATUS_OK)//等待不成功时持续等待
21 | {
22 | appendMsg("等待中接收数据");
23 |
24 | }
25 |
26 | //读取彩色帧
27 | isCameraSuccess = colorStream.readFrame(&frame);//rc为读取的成功与否的状态,fream为存储彩色帧的变量
28 | }
29 | else if(isVideo){
30 |
31 | isVedioSuccess = vid_capture.read(frame1);//初始化一个布尔值来检查是否有帧
32 |
33 | }
34 | else if (isImage) {
35 | image = cv::imread(imagePath);
36 | }
37 |
38 | if (isCameraSuccess == STATUS_OK||isVedioSuccess==true||!image.empty())//读取帧成功时
39 | {
40 | if(ui.imageDetection->isChecked()){
41 |
42 | double t = (double)cv::getTickCount();//开始计时
43 |
44 | if (isCamera) {
45 | //获取彩色数据
46 | pColor = (RGB888Pixel*)frame.getData();
47 | auto colorWidth = frame.getWidth();
48 | auto colorHeight = frame.getHeight();
49 |
50 |
51 | rawMat=cv::Mat(colorHeight, colorWidth, CV_8UC3, (void*)pColor);//彩色数据按BGR存储
52 | cv::flip(rawMat, rawMat, 1);//水平反转
53 | cv::cvtColor(rawMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
54 | }
55 | else if (isVideo) {
56 | cv::resize(frame1, frame1, cv::Size(640, 480), 0, 0, cv::INTER_LINEAR);
57 | rawMat = frame1;
58 | cv::cvtColor(rawMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
59 |
60 | }
61 | else if (isImage) {
62 | cv::resize(image, image, cv::Size(640, 480), 0, 0, cv::INTER_LINEAR);
63 | rawMat = image;
64 | cv::cvtColor(rawMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
65 | }
66 |
67 |
68 | //图像处理区域
69 | Rect rect = Rect(Point2i(ui.Point1_X->value(), ui.Point1_Y->value()), Point2i(ui.Point2_X->value(), ui.Point2_Y->value()));
70 | cv::rectangle(colorMat, rect, Scalar(255, 0, 0), 2);//画矩形
71 | cv::cvtColor(colorMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
72 |
73 |
74 |
75 | Mat gray_src1;
76 | cv::cvtColor(colorMat, gray_src1, cv::COLOR_BGR2GRAY);//bgr转灰度图
77 |
78 | rawMat.copyTo(tailorMat);
79 | tailorMat = tailorMat(rect);//裁剪出矩形区域
80 | cv::cvtColor(tailorMat, tailorMat, cv::COLOR_BGR2RGB);//bgr转rgb
81 |
82 | Image1 = tailorMat;//保存图
83 |
84 | cv::cvtColor(tailorMat, gray_src, cv::COLOR_BGR2GRAY);//bgr转灰度图
85 | cv::threshold(gray_src, binaryMat, ui.grayBox->value(), 255, 0);//60为阈值,255为最大值,0:超过60改为255.
86 |
87 | Image2 = binaryMat;//保存图
88 |
89 | Mat imageROI = gray_src1(rect);
90 | binaryMat.copyTo(imageROI);
91 |
92 |
93 | Mat canny_output;
94 | vector> contours;//建立二维点元素数组 全部发现的轮廓对象
95 | vector hierachy;//层次数组
96 |
97 | Canny(gray_src, canny_output, ui.threshold_value->value(), ui.threshold_value->value() * 2, 3, false);//边缘提取
98 | findContours(canny_output, contours, hierachy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));//发现轮廓
99 |
100 |
101 |
102 | vector contours_moments(contours.size());//矩数组
103 | vector ccs(contours.size());//中心点坐标数组 x y
104 | for (size_t i = 0; i < contours.size(); i++) {
105 | contours_moments[i] = moments(contours[i]);//求矩
106 | ccs[i] = Point(static_cast(contours_moments[i].m10 / contours_moments[i].m00), static_cast(contours_moments[i].m01 / contours_moments[i].m00));//求中心坐标 static_cast处理范围
107 | }
108 |
109 | Mat drawImg;// = Mat::zeros(src.size(), CV_8UC3);
110 | colorMat.copyTo(drawImg);
111 | RNG rng(12345);//随机数
112 | int P1P2_wide = (ui.Point2_X->value() - ui.Point1_X->value());//像素宽度
113 | double centerPointRatio = ui.wideBox->value() / P1P2_wide;//比例
114 | for (size_t i = 0; i < contours.size(); i++) {
115 | if (contours[i].size() < ui.sizeBoxMin->value() || contours[i].size() > ui.sizeBoxMax->value()) {//阈值 轮廓对象小于100忽略
116 | continue;
117 | }
118 | Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
119 |
120 |
121 | appendMsg("area " + QString::number(i) + ":" + QString::number(contourArea(contours[i])));
122 | appendMsg("center point x:" + QString::number(ccs[i].x * centerPointRatio) + " y:" + QString::number(ccs[i].y * centerPointRatio));
123 |
124 | //printf("center point x : %.2f y : %.2f\n", ccs[i].x+ ui.Point1_X->value(), ccs[i].y+ ui.Point1_Y->value());//打印中点坐标
125 | //printf("contours %d area : %.2f\n", i, contourArea(contours[i]));//打印面积
126 |
127 | drawContours(drawImg, contours, i, color, 2, 8, hierachy, 0, Point(ui.Point1_X->value(), ui.Point1_Y->value()));//绘画轮廓层次
128 | circle(drawImg, Point(ccs[i].x + ui.Point1_X->value(), ccs[i].y + ui.Point1_Y->value()), 1, color, 2, 8);//绘画中点
129 | }
130 |
131 | Image3 = drawImg(rect);//保存图
132 | //cv::cvtColor(Image3, Image3, cv::COLOR_BGR2RGB);//bgr转rgb
133 | //binaryMat.convertTo(binaryMat2, CV_8UC3);
134 |
135 | ////【2】定义一个Mat类型并给其设定ROI区域
136 | //Mat colorMat2;
137 | //colorMat.copyTo(colorMat2);
138 | //Mat imageROI = colorMat2(rect); //450,20为自定义起始点坐标
139 | //binaryMat.copyTo(colorMat2, imageROI);
140 |
141 | //ImgR = QImage((const uchar*)colorMat.data, colorMat.cols, colorMat.rows, QImage::Format_RGB888);
142 | ImgR = QImage((const uchar*)drawImg.data, drawImg.cols, drawImg.rows, QImage::Format_RGB888);
143 | QPixmap pixmap1 = QPixmap::fromImage(ImgR);
144 | pixmap1 = pixmap1.scaled(pixmap1.width(), pixmap1.height());
145 | //pixmap1 = pixmap1.scaled(640, 480);
146 | ui.rawlabel->setPixmap(pixmap1);
147 |
148 | //ImgB = QImage((const uchar*)drawImg.data, drawImg.cols, drawImg.rows, QImage::QImage::Format_RGB888);
149 | ImgB = QImage((const uchar*)gray_src1.data, gray_src1.cols, gray_src1.rows, QImage::QImage::Format_Indexed8);
150 | QPixmap pixmap2 = QPixmap::fromImage(ImgB);
151 | pixmap2 = pixmap2.scaled(pixmap2.width(), pixmap2.height());
152 | //pixmap2 = pixmap2.scaled(640, 480);
153 | ui.fanllabel->setPixmap(pixmap2);
154 | //ui.fanllabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
155 | ui.rawlabel->setScaledContents(true);
156 | ui.fanllabel->setScaledContents(true);
157 |
158 | t = ((double)cv::getTickCount() - t) / cv::getTickFrequency();//结束计时
159 | double fps = 1.0 / t;//转换为帧率
160 | cout << "FPS: " << fps << endl;//输出帧率
161 | }
162 | else if (ui.objectDetection->isChecked()) {
163 |
164 | double t = (double)cv::getTickCount();//开始计时
165 |
166 |
167 | if (isCamera) {
168 | //获取彩色数据
169 | pColor = (RGB888Pixel*)frame.getData();
170 | auto colorWidth = frame.getWidth();
171 | auto colorHeight = frame.getHeight();
172 |
173 |
174 | rawMat = cv::Mat(colorHeight, colorWidth, CV_8UC3, (void*)pColor);//彩色数据按BGR存储
175 | cv::flip(rawMat, rawMat, 1);//水平反转
176 | cv::cvtColor(rawMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
177 | }
178 | else if (isVideo) {
179 | cv::resize(frame1, frame1, cv::Size(640, 480), 0, 0, cv::INTER_LINEAR);
180 | rawMat = frame1;
181 | cv::cvtColor(rawMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
182 |
183 | }
184 | else if (isImage) {
185 | rawMat = image;
186 | cv::resize(rawMat, rawMat, cv::Size(640, 480), 0, 0, cv::INTER_LINEAR);
187 | cv::cvtColor(rawMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
188 | }
189 |
190 | //图像处理区域
191 | Rect rect = Rect(Point2i(ui.Point1_X->value(), ui.Point1_Y->value()), Point2i(ui.Point2_X->value(), ui.Point2_Y->value()));
192 | cv::rectangle(colorMat, rect, Scalar(255, 0, 0), 2);//画矩形
193 | cv::cvtColor(colorMat, colorMat, cv::COLOR_BGR2RGB);//bgr转rgb
194 |
195 | rawMat.copyTo(tailorMat);
196 | tailorMat = tailorMat(rect);//裁剪出矩形区域
197 |
198 |
199 | //保存raw图
200 | tailorMat.copyTo(Image1);
201 | cv::cvtColor(Image1, Image1, cv::COLOR_BGR2RGB);//bgr转r
202 |
203 |
204 |
205 | cv::cvtColor(tailorMat, tailorMat, cv::COLOR_BGR2RGB);//bgr转r
206 |
207 |
208 |
209 |
210 | result = detector.detect(tailorMat, ui.confThreshold->value(), ui.iouThreshold->value());//检测单帧画面 得到Detection类型的数组
211 |
212 | utilss::visualizeDetection(tailorMat, result, classNames);//在画面绘出矩形框以及信息
213 |
214 | Image2 = tailorMat;//保存detect检测结果图
215 |
216 | Mat colorMat2;
217 | colorMat.copyTo(colorMat2);
218 | Mat colorMat2ROI;
219 | colorMat2ROI = colorMat2(rect);
220 | tailorMat.copyTo(colorMat2ROI);
221 | cv::cvtColor(colorMat2, colorMat2, cv::COLOR_BGR2RGB);//bgr转r
222 |
223 | //ImgR = QImage((const uchar*)colorMat.data, colorMat.cols, colorMat.rows, QImage::Format_RGB888);
224 | ImgR = QImage((const uchar*)colorMat.data, colorMat.cols, colorMat.rows, QImage::Format_RGB888);
225 | QPixmap pixmap1 = QPixmap::fromImage(ImgR);
226 | pixmap1 = pixmap1.scaled(pixmap1.width(), pixmap1.height());
227 | //pixmap1 = pixmap1.scaled(640,480);
228 | ui.rawlabel->setPixmap(pixmap1);
229 |
230 | //ImgB = QImage((const uchar*)drawImg.data, drawImg.cols, drawImg.rows, QImage::QImage::Format_RGB888);
231 | ImgB = QImage((const uchar*)colorMat2.data, colorMat2.cols, colorMat2.rows, QImage::QImage::Format_RGB888);
232 | QPixmap pixmap2 = QPixmap::fromImage(ImgB);
233 | pixmap2 = pixmap2.scaled(pixmap2.width(), pixmap2.height());
234 | //pixmap2 = pixmap2.scaled(640,480);
235 | ui.fanllabel->setPixmap(pixmap2);
236 | //ui.fanllabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
237 | ui.rawlabel->setScaledContents(true);
238 | ui.fanllabel->setScaledContents(true);
239 |
240 | t = ((double)cv::getTickCount() - t) / cv::getTickFrequency();//结束计时
241 | double fps = 1.0 / t;//转换为帧率
242 | cout << "FPS: " << fps << endl;//输出帧率
243 | }
244 |
245 | }
246 | if (isCameraSuccess != STATUS_OK&&isVedioSuccess == false&&image.empty()) {
247 | this->vid_capture.release();
248 | visualTime->stop();
249 | isCameraOpen = false;
250 | //设置开始按钮不可点击
251 |
252 | ui.startButton->setEnabled(true);
253 | ui.closeButton->setEnabled(true);
254 |
255 |
256 | }
257 | if (colorMat.empty())//灰度图为空
258 | {
259 | appendMsg("彩色图为空");
260 | }
261 | else
262 | {
263 | emit signalJudge();
264 | }
265 |
266 | //保存当前帧
267 | if (isSaveVedio) {
268 | outputVideo << rawMat;
269 | }
270 |
271 | //});
272 | //t.join();
273 | }
274 | }
--------------------------------------------------------------------------------
/src/save.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | void MainWindow::on_imageSaveSet_clicked() {
3 | int nResult = -1;
4 | pDlg1->setWindowTitle(tr("图片保存设置"));
5 | nResult = pDlg1->exec();
6 | if (nResult == setDialog::Accepted) {//确认
7 | pDlg1->getMessage(isSaveImage1, isSaveImage2, isSaveImage3, imageSavePath);
8 | }
9 | }
10 | void MainWindow::on_vedioSaveSet_clicked() {
11 | int nResult = -1;
12 | pDlg2->setWindowTitle(tr("视频保存设置"));
13 | nResult = pDlg2->exec();
14 | if (nResult == setDialog::Accepted) {//确认
15 | pDlg2->getMessage(isSaveVedioLeft, isSaveVedioRight,videoSavePath);
16 | }
17 | }
18 | void MainWindow::on_imageSave_clicked() {
19 | //std::thread t([=]() {
20 | if (!visualTime->isActive()) {//如果没有开始检测则退出
21 | QMessageBox::critical(this, "错误提示框", "请开始检测之后再保存!");
22 | return;
23 | }
24 | //选择一个路径
25 | QDateTime dateTime(QDateTime::currentDateTime());//构造函数
26 | QString qStr = dateTime.toString("yyMMddhhmm");
27 | if (qStr != timeStr) {
28 | g_imagecount = 1;
29 | }
30 | timeStr = qStr;
31 | if (ui.objectDetection->isChecked()) {
32 | if (isSaveImage2) {
33 | QString filePath = imageSavePath+"/" + qStr + "_" + QString::number(g_imagecount) + "(raw)" + ".bmp";
34 | cv::imwrite(filePath.toStdString(), Image1);//将彩色图保存到本地
35 | }
36 | if (isSaveImage3) {
37 | QString filePath = imageSavePath+"/" + qStr + "_" + QString::number(g_imagecount) + "(detect)" + ".bmp";
38 | cv::imwrite(filePath.toStdString(), Image2);
39 | }
40 | g_imagecount++;
41 | }
42 | else if (ui.imageDetection->isChecked()) {
43 | if (isSaveImage1) {
44 | QString filePath = imageSavePath + "/" + qStr + "_" + QString::number(g_imagecount) + "(raw)" + ".bmp";
45 | cv::imwrite(filePath.toStdString(), Image1);
46 | }
47 | if (isSaveImage2) {
48 | QString filePath = imageSavePath + "/" + qStr + "_" + QString::number(g_imagecount) + "(canny)" + ".bmp";
49 | cv::imwrite(filePath.toStdString(), Image2);
50 | }
51 | if (isSaveImage3) {
52 | QString filePath = imageSavePath + "/" + qStr + "_" + QString::number(g_imagecount) + "(binary)" + ".bmp";
53 | cv::imwrite(filePath.toStdString(), Image3);
54 | }
55 | g_imagecount++;
56 | }
57 |
58 | appendMsg("缺陷数据保存完成,查看:" + imageSavePath);
59 | /* });
60 | t.join();*/
61 | }
62 | void MainWindow::on_vedioSave_clicked() {
63 | //std::thread t([=]() {
64 | if (!visualTime->isActive()) {//如果没有开始检测则退出
65 | QMessageBox::critical(this, "错误提示框", "请开始检测之后再录制视频!");
66 | return;
67 | }
68 | if (isSaveVedio==false) {
69 | if (videoSavePath.isEmpty()) {
70 | QMessageBox::critical(this, "错误提示框", "请设置视频保存路径\n");
71 | }
72 | else {
73 | isSaveVedio = true;
74 |
75 | /*cv::Size S = cv::Size((int)vid_capture.get(CAP_PROP_FRAME_WIDTH),
76 | (int)vid_capture.get(CAP_PROP_FRAME_HEIGHT));*/
77 | cv::Size S;
78 | if (isResolvingPower) {
79 | S = cv::Size(640, 480);
80 | }
81 | else {
82 | S = cv::Size(1280, 960);
83 | }
84 |
85 | //打开视频路径,设置基本信息 open函数中你参数跟上面给出的VideoWriter函数是一样的
86 | string str = videoSavePath.toLocal8Bit();
87 | outputVideo.open(str, VideoWriter::fourcc('H', '2', '6', '4'), 25, S, true);
88 |
89 |
90 |
91 | ui.vedioSave->setText("结束录制");
92 | }
93 | }
94 | else {
95 | outputVideo.release();
96 | ui.vedioSave->setText("视频录制");
97 | isSaveVedio = false;
98 | }
99 |
100 | //});
101 | // t.join();
102 | }
--------------------------------------------------------------------------------
/src/saveDataFile.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //保存缺陷图片
4 | void MainWindow::saveDataFile()
5 | {
6 | std::thread t([=]() {
7 | //选择一个路径
8 | QDateTime dateTime(QDateTime::currentDateTime());//构造函数
9 | QString qStr = dateTime.toString("yyMMddhhmm");
10 | if (qStr!=timeStr) {
11 | g_imagecount = 1;
12 | }
13 | timeStr = qStr;
14 | QString filePath = savePath + qStr + "_" + QString::number(g_imagecount++) + ".bmp";
15 | cv::imwrite(filePath.toStdString(), binaryMat);//将彩色图保存到本地
16 | //qDebug() << colorMat.rows;
17 | appendMsg("缺陷数据保存完成,查看:C:/hole_detection/dataset");
18 | });
19 | t.join();
20 | }
21 |
22 | //QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
--------------------------------------------------------------------------------
/src/setdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "setdialog.h"
2 |
3 | setDialog::setDialog(QWidget *parent)
4 | : QDialog(parent)
5 | {
6 | ui.setupUi(this);
7 | //connect(ui.acceptButton, SIGNAL(clicked()), this, SLOT(accept()));
8 | //connect(ui.rejectButton, SIGNAL(clicked()), this, SLOT(reject()));
9 |
10 | }
11 |
12 | setDialog::~setDialog()
13 | {
14 | }
15 |
16 |
17 | void setDialog::on_acceptButton_clicked() {
18 |
19 | //std::cout << "666";
20 |
21 | this->accept();
22 | }
23 |
24 |
25 |
26 | void setDialog::on_rejectButton_clicked() {
27 | reject();
28 | }
29 |
30 | void setDialog::on_cameraRadioButton_clicked() {
31 | ui.radioButton640->setCheckable(true);
32 | ui.radioButto1280->setCheckable(true);
33 | ui.radioButton640->setChecked(true);
34 | }
35 |
36 | void setDialog::on_videoRadioButton_clicked() {
37 | ui.radioButton640->setCheckable(false);
38 | ui.radioButto1280->setCheckable(false);
39 | QString fileName = QFileDialog::getOpenFileName(NULL, QStringLiteral("选择视频"), "./images", QStringLiteral("*mp4"));
40 | ui.videoChose->setText(fileName);
41 |
42 | }
43 | void setDialog::on_pictureRadioButton_clicked() {
44 | ui.radioButton640->setCheckable(false);
45 | ui.radioButto1280->setCheckable(false);
46 | QString fileName = QFileDialog::getOpenFileName(this, QStringLiteral("选择图片"), "./images", QStringLiteral("*jpg *bmp"));
47 | ui.pictureChose->setText(fileName);
48 |
49 | }
50 |
51 |
52 | void setDialog::getMessage(bool& isCamera, bool& isVedio,bool& isImage, bool& isResolvingPower,std::string &vedioStr,std::string & imageStr) {
53 | isCamera = ui.cameraRadioButton->isChecked();
54 | isVedio = ui.videoRadioButton->isChecked();
55 | isImage = ui.pictureRadioButton->isChecked();
56 | vedioStr= ui.videoChose->text().toLocal8Bit();
57 | imageStr= ui.pictureChose->text().toLocal8Bit();
58 | isResolvingPower = ui.radioButton640->isChecked();
59 | }
--------------------------------------------------------------------------------
/src/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 |
4 | size_t utilss::vectorProduct(const std::vector& vector)
5 | {
6 | if (vector.empty())
7 | return 0;
8 |
9 | size_t product = 1;
10 | for (const auto& element : vector)
11 | product *= element;
12 |
13 | return product;
14 | }
15 |
16 | std::wstring utilss::charToWstring(const char* str)//字符转字符串
17 | {
18 | typedef std::codecvt_utf8 convert_type;
19 | std::wstring_convert converter;
20 |
21 | return converter.from_bytes(str);
22 | }
23 |
24 |
25 | //加载类型名称
26 | std::vector utilss::loadNames(const std::string& path)
27 | {
28 | // load class names
29 | std::vector classNames;
30 | std::ifstream infile(path);
31 | if (infile.good())
32 | {
33 | std::string line;
34 | while (getline (infile, line))
35 | {
36 | if (line.back() == '\r')
37 | line.pop_back();
38 | classNames.emplace_back(line);
39 | }
40 | infile.close();
41 | }
42 | else
43 | {
44 | std::cerr << "ERROR: Failed to access class name path: " << path << std::endl;
45 | }
46 |
47 | return classNames;
48 | }
49 |
50 |
51 | //可视化检测
52 | void utilss::visualizeDetection(cv::Mat& image, std::vector& detections,
53 | const std::vector& classNames)
54 | {
55 | for (const Detection& detection : detections)
56 | {
57 | //检测物体画目标框
58 | cv::rectangle(image, detection.box, cv::Scalar(229, 160, 21), 2);
59 |
60 | int x = detection.box.x;
61 | int y = detection.box.y;
62 |
63 | int conf = (int)std::round(detection.conf * 100);
64 | int classId = detection.classId;
65 | std::string label = classNames[classId] + " 0." + std::to_string(conf);
66 |
67 | int baseline = 0;
68 |
69 | //画字的矩形
70 | cv::Size size = cv::getTextSize(label, cv::FONT_ITALIC, 0.8, 2, &baseline);
71 | cv::rectangle(image,
72 | cv::Point(x, y - 25), cv::Point(x + size.width, y),
73 | cv::Scalar(229, 160, 21), -1);
74 | //置信度
75 | cv::putText(image, label,
76 | cv::Point(x, y - 3), cv::FONT_ITALIC,
77 | 0.8, cv::Scalar(255, 255, 255), 2);//FONT_HERSHEY_SIMPLEX
78 | }
79 | }
80 |
81 | //填充调整图片大小 将原图变成预定大小的图片 640X640 方便模型进行预测
82 | void utilss::letterbox(const cv::Mat& image, cv::Mat& outImage,
83 | const cv::Size& newShape = cv::Size(640, 640),
84 | const cv::Scalar& color = cv::Scalar(114, 114, 114),
85 | bool auto_ = true,
86 | bool scaleFill = false,
87 | bool scaleUp = true,
88 | int stride = 32)
89 | {
90 | cv::Size shape = image.size();
91 | float r = std::min((float)newShape.height / (float)shape.height,
92 | (float)newShape.width / (float)shape.width);////计算图片缩小比例
93 | if (!scaleUp)
94 | r = std::min(r, 1.0f);//若缩小比例大于1则取1
95 |
96 | float ratio[2] {r, r};
97 | int newUnpad[2] {(int)std::round((float)shape.width * r),
98 | (int)std::round((float)shape.height * r)};//计算图片缩小的大小保留至整数
99 |
100 | auto dw = (float)(newShape.width - newUnpad[0]);//计算目标图片和缩小图片的宽度差 640-width*r
101 | auto dh = (float)(newShape.height - newUnpad[1]);//计算目标图片和缩小图片的高度差 640-height*r
102 |
103 | if (auto_)//宽度和高度是否是动态的
104 | {
105 | dw = (float)((int)dw % stride);
106 | dh = (float)((int)dh % stride);
107 | }
108 | else if (scaleFill)
109 | {
110 | dw = 0.0f;
111 | dh = 0.0f;
112 | newUnpad[0] = newShape.width;
113 | newUnpad[1] = newShape.height;
114 | ratio[0] = (float)newShape.width / (float)shape.width;
115 | ratio[1] = (float)newShape.height / (float)shape.height;
116 | }
117 |
118 | dw /= 2.0f;
119 | dh /= 2.0f;
120 |
121 | if (shape.width != newUnpad[0] && shape.height != newUnpad[1])
122 | {
123 | cv::resize(image, outImage, cv::Size(newUnpad[0], newUnpad[1]));//缩放图片
124 | }
125 |
126 | int top = int(std::round(dh - 0.1f));
127 | int bottom = int(std::round(dh + 0.1f));
128 | int left = int(std::round(dw - 0.1f));
129 | int right = int(std::round(dw + 0.1f));
130 | cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);//复制图像并且制作灰色边界
131 | }
132 |
133 |
134 | //缩放坐标
135 | void utilss::scaleCoords(const cv::Size& imageShape, cv::Rect& coords, const cv::Size& imageOriginalShape)
136 | {
137 | float gain = std::min((float)imageShape.height / (float)imageOriginalShape.height,
138 | (float)imageShape.width / (float)imageOriginalShape.width);
139 |
140 | int pad[2] = {(int) (( (float)imageShape.width - (float)imageOriginalShape.width * gain) / 2.0f),
141 | (int) (( (float)imageShape.height - (float)imageOriginalShape.height * gain) / 2.0f)};
142 |
143 | coords.x = (int) std::round(((float)(coords.x - pad[0]) / gain));
144 | coords.y = (int) std::round(((float)(coords.y - pad[1]) / gain));
145 |
146 | coords.width = (int) std::round(((float)coords.width / gain));
147 | coords.height = (int) std::round(((float)coords.height / gain));
148 |
149 | // // clip coords, should be modified for width and height
150 | // coords.x = utils::clip(coords.x, 0, imageOriginalShape.width);
151 | // coords.y = utils::clip(coords.y, 0, imageOriginalShape.height);
152 | // coords.width = utils::clip(coords.width, 0, imageOriginalShape.width);
153 | // coords.height = utils::clip(coords.height, 0, imageOriginalShape.height);
154 | }
155 |
156 | template
157 | T utilss::clip(const T& n, const T& lower, const T& upper)
158 | {
159 | return std::max(lower, std::min(n, upper));
160 | }
161 |
--------------------------------------------------------------------------------
/src/writeRequst.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | //给PLC写数据s
4 | void MainWindow::writeRequst()
5 | {
6 | int star_add = ui.portBoxOUT->value();//写入数据的起始地址
7 | quint16 value = 1;//要写入的数据
8 | quint16 number = 1;//写入数据的个数
9 | if (!modbusDevice)
10 | {
11 | appendMsg("Modbus模块建立出错");
12 | return;
13 | }
14 | //quint16 number1 = static_cast(number);
15 | QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::Coils, star_add, number);//参数:寄存器类型,数据起始地址,数据大小
16 | //int a = writeUnit.valueCount();
17 | //for (uint i = 0; i < writeUnit.valueCount(); i++)//循环写入
18 | //{
19 | //int ii = static_cast(i);//将uint类型数值静态转换为int型。
20 | //QString st = str1.mid(ii, 1);//获取指定位置子串,参数1从哪个开始,参数2一共几位
21 | writeUnit.setValue(0, value);//将用户输出的数据设置到写容器中
22 | //quint16 a = writeUnit.value(0);
23 | if (auto* reply = modbusDevice->sendWriteRequest(writeUnit, 0xFF))//1为服务器的serveAddress
24 | {
25 | if (!reply->isFinished())//返回未终止时
26 | {
27 | connect(reply, &QModbusReply::finished, this, [=]() {
28 | if (reply->error() == QModbusDevice::ProtocolError)
29 | {
30 | QString errorM1 = QString::fromLocal8Bit("Write response error: %1 (Mobus exception: 0x%2)").arg(reply->errorString()).arg(reply->rawResult().exceptionCode(), -1, 16);
31 | appendMsg(errorM1);
32 | }
33 | else if (reply->error() != QModbusDevice::NoError)//错误
34 | {
35 | QString errorM2 = QString::fromLocal8Bit("Write response error: %1 (code: 0x%2)").arg(reply->errorString()).arg(reply->error(), -1, 16);
36 | appendMsg(errorM2);
37 | }
38 | appendMsg("写入成功,数据为:" + QString::number(value));
39 | //emit signalRead();
40 | reply->deleteLater();
41 | });
42 | }
43 | else
44 | {
45 | //广播消息 不需要返回响应
46 | reply->deleteLater();// broadcast replies return immediately
47 | }
48 | }
49 | else
50 | {
51 | //QString errorM3 = ("写入错误: ") + modbusDevice->errorString();
52 | //appendMsg(errorM3);
53 | }
54 | }
--------------------------------------------------------------------------------
/weights1/best.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/weights1/best.onnx
--------------------------------------------------------------------------------
/weights1/best1_smi.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/weights1/best1_smi.onnx
--------------------------------------------------------------------------------
/weights1/class2.names:
--------------------------------------------------------------------------------
1 | label
--------------------------------------------------------------------------------
/weights1/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindowClass
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1205
10 | 764
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 | -
19 |
20 |
21 |
22 | 0
23 |
24 |
25 | 0
26 |
27 |
28 | 0
29 |
30 |
31 | 0
32 |
33 |
-
34 |
35 |
36 |
37 | 0
38 |
39 |
40 | 0
41 |
42 |
43 | 0
44 |
45 |
46 | 0
47 |
48 |
49 | 0
50 |
51 |
-
52 |
53 |
54 | QGroupBox{
55 | border-width:1px;
56 | border-style:solid;
57 | border-radius: 10px;
58 | border-color:gray;
59 | margin-top:3ex;
60 | }
61 | QGroupBox::title{
62 | subcontrol-origin:margin;
63 | subcontrol-position:top left;
64 | left:10px;
65 | margin-left:0px;
66 | padding:0 1px;
67 | }
68 |
69 |
70 |
71 | 检测区域
72 |
73 |
74 |
75 | 9
76 |
77 |
78 | 0
79 |
80 |
81 | 0
82 |
83 |
-
84 |
85 |
86 | Point1_X
87 |
88 |
89 |
90 | -
91 |
92 |
93 | Qt::Horizontal
94 |
95 |
96 |
97 | 5
98 | 20
99 |
100 |
101 |
102 |
103 | -
104 |
105 |
106 | Point2_X
107 |
108 |
109 |
110 | -
111 |
112 |
113 | 1280
114 |
115 |
116 |
117 | -
118 |
119 |
120 | 1280
121 |
122 |
123 |
124 | -
125 |
126 |
127 | Point1_Y
128 |
129 |
130 |
131 | -
132 |
133 |
134 | Point2_Y
135 |
136 |
137 |
138 | -
139 |
140 |
141 | 960
142 |
143 |
144 |
145 | -
146 |
147 |
148 | 960
149 |
150 |
151 |
152 |
153 |
154 |
155 | -
156 |
157 |
158 | Qt::Horizontal
159 |
160 |
161 |
162 | 40
163 | 20
164 |
165 |
166 |
167 |
168 | -
169 |
170 |
171 | QGroupBox{
172 | border-width:1px;
173 | border-style:solid;
174 | border-radius: 10px;
175 | border-color:gray;
176 | margin-top:3ex;
177 | }
178 | QGroupBox::title{
179 | subcontrol-origin:margin;
180 | subcontrol-position:top left;
181 | left:10px;
182 | margin-left:0px;
183 | padding:0 1px;
184 | }
185 |
186 |
187 |
188 | 边缘检测设置
189 |
190 |
191 |
192 | 9
193 |
194 |
195 | 0
196 |
197 |
-
198 |
199 |
200 | 1000
201 |
202 |
203 | 100
204 |
205 |
206 |
207 | -
208 |
209 |
210 | 100
211 |
212 |
213 | 10000
214 |
215 |
216 | 1000
217 |
218 |
219 |
220 | -
221 |
222 |
223 | 检测阈值
224 |
225 |
226 |
227 | -
228 |
229 |
230 | min
231 |
232 |
233 |
234 | -
235 |
236 |
237 | 255
238 |
239 |
240 |
241 | -
242 |
243 |
244 | max
245 |
246 |
247 |
248 |
249 |
250 |
251 | -
252 |
253 |
254 | Qt::Horizontal
255 |
256 |
257 |
258 | 40
259 | 20
260 |
261 |
262 |
263 |
264 | -
265 |
266 |
267 | QGroupBox{
268 | border-width:1px;
269 | border-style:solid;
270 | border-radius: 10px;
271 | border-color:gray;
272 | margin-top:0.5ex;
273 | }
274 | QGroupBox::title{
275 | subcontrol-origin:margin;
276 | subcontrol-position:top left;
277 | left:10px;
278 | bottom:5px
279 | margin-left:0px;
280 | padding:0 1px;
281 | }
282 |
283 |
284 |
285 | 灰度检测设置
286 |
287 |
288 |
289 | 9
290 |
291 |
292 | 11
293 |
294 |
295 | 9
296 |
297 |
298 | 0
299 |
300 |
-
301 |
302 |
303 | 灰度阈值
304 |
305 |
306 |
307 | -
308 |
309 |
310 | 255
311 |
312 |
313 |
314 | -
315 |
316 |
317 | 数量阈值
318 |
319 |
320 |
321 | -
322 |
323 |
324 |
325 |
326 |
327 | -
328 |
329 |
330 | Qt::Horizontal
331 |
332 |
333 |
334 | 40
335 | 20
336 |
337 |
338 |
339 |
340 | -
341 |
342 |
343 |
344 | 0
345 | 0
346 |
347 |
348 |
349 | Qt::NoFocus
350 |
351 |
352 | Qt::DefaultContextMenu
353 |
354 |
355 | QGroupBox{
356 | border-width:1px;
357 | border-style:solid;
358 | border-radius: 10px;
359 | border-color:gray;
360 | margin-top:3ex;
361 | }
362 | QGroupBox::title{
363 | subcontrol-origin:margin;
364 | subcontrol-position:top left;
365 | left:10px;
366 | margin-left:0px;
367 | padding:0 1px;
368 | }
369 |
370 |
371 |
372 | 目标检测设置
373 |
374 |
375 | false
376 |
377 |
378 |
-
379 |
380 |
381 | weight路径
382 |
383 |
384 |
385 | -
386 |
387 |
388 | 1.000000000000000
389 |
390 |
391 | QAbstractSpinBox::AdaptiveDecimalStepType
392 |
393 |
394 |
395 | -
396 |
397 |
398 | NMS阈值
399 |
400 |
401 |
402 | -
403 |
404 |
405 | label路径
406 |
407 |
408 |
409 | -
410 |
411 |
412 | 选择
413 |
414 |
415 |
416 | -
417 |
418 |
419 | 选择
420 |
421 |
422 |
423 | -
424 |
425 |
426 | 置信度
427 |
428 |
429 |
430 | -
431 |
432 |
433 | 2
434 |
435 |
436 | 1.000000000000000
437 |
438 |
439 | QAbstractSpinBox::AdaptiveDecimalStepType
440 |
441 |
442 |
443 | -
444 |
445 |
446 | -
447 |
448 |
449 | Qt::Horizontal
450 |
451 |
452 |
453 | 40
454 | 20
455 |
456 |
457 |
458 |
459 | -
460 |
461 |
462 |
463 |
464 |
465 | -
466 |
467 |
468 |
469 | 0
470 |
471 |
472 | 0
473 |
474 |
475 | 0
476 |
477 |
478 | 0
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 | -
487 |
488 |
489 |
490 | 4
491 |
492 |
493 | 0
494 |
495 |
496 | 4
497 |
498 |
499 | 0
500 |
501 |
-
502 |
503 |
504 | QFrame::Box
505 |
506 |
507 | QFrame::Sunken
508 |
509 |
510 |
511 |
512 |
513 |
514 | -
515 |
516 |
517 | QFrame::Box
518 |
519 |
520 | QFrame::Sunken
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 | -
531 |
532 |
533 | true
534 |
535 |
536 |
537 | 0
538 | 0
539 |
540 |
541 |
542 |
543 | 16777215
544 | 80
545 |
546 |
547 |
548 | QFrame::WinPanel
549 |
550 |
551 | QFrame::Sunken
552 |
553 |
554 | 1
555 |
556 |
557 | 0
558 |
559 |
560 |
561 | -
562 |
563 |
564 |
565 | 0
566 |
567 |
568 | 0
569 |
570 |
571 | 0
572 |
573 |
574 | 0
575 |
576 |
577 | 0
578 |
579 |
-
580 |
581 |
582 | QGroupBox{
583 | border-width:1px;
584 | border-style:solid;
585 | border-radius: 10px;
586 | border-color:gray;
587 | margin-top:3ex;
588 | }
589 | QGroupBox::title{
590 | subcontrol-origin:margin;
591 | subcontrol-position:top left;
592 | left:10px;
593 | margin-left:0px;
594 | padding:0 1px;
595 | }
596 |
597 |
598 |
599 | PLC设置
600 |
601 |
602 |
-
603 |
604 |
605 | -
606 |
607 |
608 | IP
609 |
610 |
611 |
612 | -
613 |
614 |
615 | -
616 |
617 |
618 | -
619 |
620 |
621 | 读取线圈地址
622 |
623 |
624 |
625 | -
626 |
627 |
628 | 读取测试
629 |
630 |
631 |
632 | 8
633 | 16
634 |
635 |
636 |
637 |
638 | -
639 |
640 |
641 | 写入测试
642 |
643 |
644 |
645 | 8
646 | 16
647 |
648 |
649 |
650 |
651 | -
652 |
653 |
654 | 写入线圈地址
655 |
656 |
657 |
658 | -
659 |
660 |
661 | Port
662 |
663 |
664 |
665 | -
666 |
667 |
668 |
669 |
670 |
671 | -
672 |
673 |
674 | Qt::Horizontal
675 |
676 |
677 |
678 | 40
679 | 20
680 |
681 |
682 |
683 |
684 | -
685 |
686 |
687 | QGroupBox{
688 | border-width:1px;
689 | border-style:solid;
690 | border-radius: 10px;
691 | border-color:gray;
692 | margin-top:3ex;
693 | }
694 | QGroupBox::title{
695 | subcontrol-origin:margin;
696 | subcontrol-position:top left;
697 | left:10px;
698 | margin-left:0px;
699 | padding:0 1px;
700 | }
701 |
702 |
703 |
704 | 保存
705 |
706 |
707 |
-
708 |
709 |
710 | 视频设置
711 |
712 |
713 |
714 | -
715 |
716 |
717 | 图片设置
718 |
719 |
720 |
721 | -
722 |
723 |
724 | 图片保存
725 |
726 |
727 |
728 | -
729 |
730 |
731 | 视频录制
732 |
733 |
734 |
735 |
736 |
737 |
738 | -
739 |
740 |
741 | Qt::Horizontal
742 |
743 |
744 |
745 | 40
746 | 20
747 |
748 |
749 |
750 |
751 | -
752 |
753 |
754 | QGroupBox{
755 | border-width:1px;
756 | border-style:solid;
757 | border-radius: 10px;
758 | border-color:gray;
759 | margin-top:3ex;
760 | }
761 | QGroupBox::title{
762 | subcontrol-origin:margin;
763 | subcontrol-position:top left;
764 | left:10px;
765 | margin-left:0px;
766 | padding:0 1px;
767 | }
768 |
769 |
770 |
771 | 检测方法
772 |
773 |
774 |
775 | 0
776 |
777 |
778 | 0
779 |
780 |
-
781 |
782 |
783 | 目标检测
784 |
785 |
786 | true
787 |
788 |
789 | true
790 |
791 |
792 |
793 | -
794 |
795 |
796 | 图像检测
797 |
798 |
799 |
800 |
801 |
802 |
803 | -
804 |
805 |
806 | Qt::Horizontal
807 |
808 |
809 |
810 | 40
811 | 20
812 |
813 |
814 |
815 |
816 | -
817 |
818 |
819 | QGroupBox{
820 | border-width:1px;
821 | border-style:solid;
822 | border-radius: 10px;
823 | border-color:gray;
824 | margin-top:3ex;
825 | }
826 | QGroupBox::title{
827 | subcontrol-origin:margin;
828 | subcontrol-position:top left;
829 | left:10px;
830 | margin-left:0px;
831 | padding:0 1px;
832 | }
833 |
834 |
835 |
836 | 推理方式
837 |
838 |
839 |
840 | 0
841 |
842 |
843 | 0
844 |
845 |
-
846 |
847 |
848 | GPU
849 |
850 |
851 | true
852 |
853 |
854 | true
855 |
856 |
857 |
858 | -
859 |
860 |
861 | CPU
862 |
863 |
864 |
865 |
866 |
867 |
868 | -
869 |
870 |
871 | Qt::Horizontal
872 |
873 |
874 |
875 | 40
876 | 20
877 |
878 |
879 |
880 |
881 | -
882 |
883 |
884 | false
885 |
886 |
887 | QGroupBox{
888 | border-width:1px;
889 | border-style:solid;
890 | border-radius: 10px;
891 | border-color:gray;
892 | margin-top:3ex;
893 | }
894 | QGroupBox::title{
895 | subcontrol-origin:margin;
896 | subcontrol-position:top left;
897 | left:10px;
898 | margin-left:0px;
899 | padding:0 1px;
900 | }
901 |
902 |
903 |
904 | 宽度设置
905 |
906 |
907 |
908 | 9
909 |
910 |
-
911 |
912 |
913 |
914 | 16777215
915 | 16777215
916 |
917 |
918 |
919 | 2000
920 |
921 |
922 |
923 |
924 |
925 |
926 | -
927 |
928 |
929 | Qt::Horizontal
930 |
931 |
932 |
933 | 40
934 | 20
935 |
936 |
937 |
938 |
939 | -
940 |
941 |
942 |
943 | 80
944 | 50
945 |
946 |
947 |
948 |
949 | Microsoft YaHei
950 | 10
951 | 50
952 | false
953 |
954 |
955 |
956 |
957 | QPushButton {
958 | border: 2px solid gray; /* QPushButton边框的宽度、样式和颜色 */
959 | border-radius: 3px; /* 边框圆角 */
960 | background-color: #F2F2F2; /* 背景颜色 */
961 | font-family: "Microsoft YaHei"; /* 文本字体族 */
962 | font-size: 10pt; /* 文本字体大小 */
963 | }
964 |
965 | QPushButton:hover { /* 鼠标悬浮在QPushButton上时的状态 */
966 | background-color: #298DFF;
967 | color: #F2F2F2;
968 | }
969 |
970 | QPushButton:checked { /* QPushButton可选中时的状态 */
971 | border: 1px solid #FF5242;
972 | background-color: #F2F2F2;
973 | color: #FF5242;
974 | }
975 |
976 | QPushButton:pressed { /* 鼠标按压在QPushButton上时的状态 */
977 | background-color: #257FE6;
978 | }
979 |
980 | QPushButton:checked:pressed { /* QPushButton处于可选中且鼠标按压在QPushButton上时的状态 */
981 | background-color: #F2F2F2;
982 | }
983 |
984 |
985 | 检测对象
986 |
987 |
988 |
989 | 16
990 | 16
991 |
992 |
993 |
994 |
995 | -
996 |
997 |
998 | Qt::Horizontal
999 |
1000 |
1001 |
1002 | 40
1003 | 20
1004 |
1005 |
1006 |
1007 |
1008 | -
1009 |
1010 |
1011 |
1012 | 80
1013 | 50
1014 |
1015 |
1016 |
1017 |
1018 | Microsoft YaHei
1019 | 10
1020 | 50
1021 | false
1022 |
1023 |
1024 |
1025 |
1026 | QPushButton {
1027 | border: 2px solid gray; /* QPushButton边框的宽度、样式和颜色 */
1028 | border-radius: 3px; /* 边框圆角 */
1029 | background-color: #F2F2F2; /* 背景颜色 */
1030 | font-family: "Microsoft YaHei"; /* 文本字体族 */
1031 | font-size: 10pt; /* 文本字体大小 */
1032 | }
1033 |
1034 | QPushButton:hover { /* 鼠标悬浮在QPushButton上时的状态 */
1035 | background-color: #298DFF;
1036 | color: #F2F2F2;
1037 | }
1038 |
1039 | QPushButton:checked { /* QPushButton可选中时的状态 */
1040 | border: 1px solid #FF5242;
1041 | background-color: #F2F2F2;
1042 | color: #FF5242;
1043 | }
1044 |
1045 | QPushButton:pressed { /* 鼠标按压在QPushButton上时的状态 */
1046 | background-color: #257FE6;
1047 | }
1048 |
1049 | QPushButton:checked:pressed { /* QPushButton处于可选中且鼠标按压在QPushButton上时的状态 */
1050 | background-color: #F2F2F2;
1051 | }
1052 |
1053 |
1054 | 连接PLC
1055 |
1056 |
1057 |
1058 | 16
1059 | 16
1060 |
1061 |
1062 |
1063 |
1064 | -
1065 |
1066 |
1067 | Qt::Horizontal
1068 |
1069 |
1070 |
1071 | 40
1072 | 20
1073 |
1074 |
1075 |
1076 |
1077 | -
1078 |
1079 |
1080 | true
1081 |
1082 |
1083 |
1084 | 80
1085 | 50
1086 |
1087 |
1088 |
1089 |
1090 | 0
1091 | 0
1092 |
1093 |
1094 |
1095 |
1096 | 0
1097 | 0
1098 |
1099 |
1100 |
1101 |
1102 | Microsoft YaHei
1103 | 10
1104 | 50
1105 | false
1106 | false
1107 | false
1108 | true
1109 |
1110 |
1111 |
1112 | false
1113 |
1114 |
1115 | false
1116 |
1117 |
1118 | Qt::StrongFocus
1119 |
1120 |
1121 | Qt::DefaultContextMenu
1122 |
1123 |
1124 |
1125 | QPushButton {
1126 | border: 2px solid gray; /* QPushButton边框的宽度、样式和颜色 */
1127 | border-radius: 3px; /* 边框圆角 */
1128 | background-color: #F2F2F2; /* 背景颜色 */
1129 | font-family: "Microsoft YaHei"; /* 文本字体族 */
1130 | font-size: 10pt; /* 文本字体大小 */
1131 | }
1132 |
1133 | QPushButton:hover { /* 鼠标悬浮在QPushButton上时的状态 */
1134 | background-color: #298DFF;
1135 | color: #F2F2F2;
1136 | }
1137 |
1138 | QPushButton:checked { /* QPushButton可选中时的状态 */
1139 | border: 1px solid #FF5242;
1140 | background-color: #F2F2F2;
1141 | color: #FF5242;
1142 | }
1143 |
1144 | QPushButton:pressed { /* 鼠标按压在QPushButton上时的状态 */
1145 | background-color: #257FE6;
1146 | }
1147 |
1148 | QPushButton:checked:pressed { /* QPushButton处于可选中且鼠标按压在QPushButton上时的状态 */
1149 | background-color: #F2F2F2;
1150 | }
1151 |
1152 |
1153 | 开始
1154 |
1155 |
1156 | false
1157 |
1158 |
1159 |
1160 | -
1161 |
1162 |
1163 | Qt::Horizontal
1164 |
1165 |
1166 |
1167 | 40
1168 | 20
1169 |
1170 |
1171 |
1172 |
1173 | -
1174 |
1175 |
1176 |
1177 | 80
1178 | 50
1179 |
1180 |
1181 |
1182 |
1183 | Microsoft YaHei
1184 | 10
1185 | 50
1186 | false
1187 |
1188 |
1189 |
1190 |
1191 | QPushButton {
1192 | border: 2px solid gray; /* QPushButton边框的宽度、样式和颜色 */
1193 | border-radius: 3px; /* 边框圆角 */
1194 | background-color: #F2F2F2; /* 背景颜色 */
1195 | font-family: "Microsoft YaHei"; /* 文本字体族 */
1196 | font-size: 10pt; /* 文本字体大小 */
1197 | }
1198 |
1199 | QPushButton:hover { /* 鼠标悬浮在QPushButton上时的状态 */
1200 | background-color: #298DFF;
1201 | color: #F2F2F2;
1202 | }
1203 |
1204 | QPushButton:checked { /* QPushButton可选中时的状态 */
1205 | border: 1px solid #FF5242;
1206 | background-color: #F2F2F2;
1207 | color: #FF5242;
1208 | }
1209 |
1210 | QPushButton:pressed { /* 鼠标按压在QPushButton上时的状态 */
1211 | background-color: #257FE6;
1212 | }
1213 |
1214 | QPushButton:checked:pressed { /* QPushButton处于可选中且鼠标按压在QPushButton上时的状态 */
1215 | background-color: #F2F2F2;
1216 | }
1217 |
1218 |
1219 | 关闭
1220 |
1221 |
1222 |
1223 | -
1224 |
1225 |
1226 | Qt::Horizontal
1227 |
1228 |
1229 |
1230 | 40
1231 | 20
1232 |
1233 |
1234 |
1235 |
1236 | -
1237 |
1238 |
1239 |
1240 |
1241 |
1242 | :/res/state_green_48.png
1243 |
1244 |
1245 |
1246 |
1247 |
1248 |
1249 |
1250 |
1251 |
1252 | -
1253 |
1254 |
1255 |
1256 |
1257 | 0
1258 | 0
1259 | 72
1260 | 15
1261 |
1262 |
1263 |
1264 | TextLabel
1265 |
1266 |
1267 |
1268 |
1269 |
1270 |
1271 |
1272 |
1273 |
1274 |
1275 |
1276 |
1277 |
1278 |
--------------------------------------------------------------------------------
/weights1/outputimagedialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | outputImageDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 501
10 | 357
11 |
12 |
13 |
14 | outputImageDialog
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 16777215
22 | 50
23 |
24 |
25 |
26 |
-
27 |
28 |
29 | 确认
30 |
31 |
32 |
33 | -
34 |
35 |
36 | 取消
37 |
38 |
39 |
40 |
41 |
42 |
43 | -
44 |
45 |
46 |
47 |
48 |
49 |
-
50 |
51 |
52 | Qt::LeftToRight
53 |
54 |
55 |
56 |
57 |
58 | Qt::AlignCenter
59 |
60 |
61 |
62 | -
63 |
64 |
65 |
66 | 16777215
67 | 60
68 |
69 |
70 |
71 | 保存设置
72 |
73 |
74 |
-
75 |
76 |
77 | Qt::Horizontal
78 |
79 |
80 |
81 | 10
82 | 20
83 |
84 |
85 |
86 |
87 | -
88 |
89 |
90 | 原图
91 |
92 |
93 |
94 | -
95 |
96 |
97 | Qt::Horizontal
98 |
99 |
100 |
101 | 40
102 | 20
103 |
104 |
105 |
106 |
107 | -
108 |
109 |
110 | 左窗口图
111 |
112 |
113 |
114 | -
115 |
116 |
117 | Qt::Horizontal
118 |
119 |
120 |
121 | 40
122 | 20
123 |
124 |
125 |
126 |
127 | -
128 |
129 |
130 | 右窗口图
131 |
132 |
133 |
134 | -
135 |
136 |
137 | Qt::Horizontal
138 |
139 |
140 |
141 | 10
142 | 20
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 | -
151 |
152 |
153 | 保存路径选择
154 |
155 |
156 |
157 | -
158 |
159 |
160 |
161 | 16777215
162 | 60
163 |
164 |
165 |
166 | 保存格式
167 |
168 |
169 |
-
170 |
171 |
172 | Qt::Horizontal
173 |
174 |
175 |
176 | 10
177 | 20
178 |
179 |
180 |
181 |
182 | -
183 |
184 |
185 |
186 | 60
187 | 16777215
188 |
189 |
190 |
191 | JPG
192 |
193 |
194 | false
195 |
196 |
197 |
198 | -
199 |
200 |
201 | Qt::Horizontal
202 |
203 |
204 |
205 | 40
206 | 20
207 |
208 |
209 |
210 |
211 | -
212 |
213 |
214 |
215 | 60
216 | 16777215
217 |
218 |
219 |
220 | BMP
221 |
222 |
223 | true
224 |
225 |
226 |
227 | -
228 |
229 |
230 | Qt::Horizontal
231 |
232 |
233 |
234 | 40
235 | 20
236 |
237 |
238 |
239 |
240 | -
241 |
242 |
243 |
244 | 60
245 | 16777215
246 |
247 |
248 |
249 | PNG
250 |
251 |
252 |
253 | -
254 |
255 |
256 | Qt::Horizontal
257 |
258 |
259 |
260 | 10
261 | 20
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
--------------------------------------------------------------------------------
/weights1/outputvediodialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | outputVedioDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 444
10 | 284
11 |
12 |
13 |
14 | outputVedioDialog
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 16777215
22 | 80
23 |
24 |
25 |
26 | 保存选择
27 |
28 |
29 |
-
30 |
31 |
32 | Qt::Horizontal
33 |
34 |
35 |
36 | 20
37 | 20
38 |
39 |
40 |
41 |
42 | -
43 |
44 |
45 | 左窗口
46 |
47 |
48 |
49 | -
50 |
51 |
52 | Qt::Horizontal
53 |
54 |
55 |
56 | 40
57 | 20
58 |
59 |
60 |
61 |
62 | -
63 |
64 |
65 | 右窗口
66 |
67 |
68 |
69 | -
70 |
71 |
72 | Qt::Horizontal
73 |
74 |
75 |
76 | 20
77 | 20
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | -
86 |
87 |
88 | 保存路径选择
89 |
90 |
91 |
92 | -
93 |
94 |
95 |
96 | 16777215
97 | 50
98 |
99 |
100 |
101 |
-
102 |
103 |
104 | 确认
105 |
106 |
107 |
108 | -
109 |
110 |
111 | 取消
112 |
113 |
114 |
115 |
116 |
117 |
118 | -
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/weights1/setdialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | setDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 465
10 | 316
11 |
12 |
13 |
14 | setDialog
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 16777215
22 | 50
23 |
24 |
25 |
26 |
-
27 |
28 |
29 | 确认
30 |
31 |
32 |
33 | -
34 |
35 |
36 | 取消
37 |
38 |
39 |
40 |
41 |
42 |
43 | -
44 |
45 |
46 |
47 |
48 |
49 |
50 | 0
51 |
52 |
53 | 0
54 |
55 |
-
56 |
57 |
58 | Qt::LeftToRight
59 |
60 |
61 | Astra mini
62 |
63 |
64 | Qt::AlignCenter
65 |
66 |
67 |
68 | -
69 |
70 |
71 | 视频检测
72 |
73 |
74 |
75 | -
76 |
77 |
78 | 相机检测
79 |
80 |
81 | true
82 |
83 |
84 |
85 | -
86 |
87 |
88 | -
89 |
90 |
91 | 图片检测
92 |
93 |
94 |
95 | -
96 |
97 |
98 | -
99 |
100 |
101 |
102 | 16777215
103 | 40
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | 0
112 |
113 |
114 | 0
115 |
116 |
-
117 |
118 |
119 | 640x480
120 |
121 |
122 | true
123 |
124 |
125 |
126 | -
127 |
128 |
129 | 1280x960
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/weights1/unchange_best.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fengzi666666/Defect-detection/5fa5ea07209f2216c772ce127b35479ab7d89551/weights1/unchange_best.onnx
--------------------------------------------------------------------------------