├── 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 | ![image](introduce/image1.jpg) 7 | 8 | ![image](introduce/image2.jpg) 9 | 10 | ![image](introduce/image3.jpg) 11 | 12 | ![image](introduce/image4.jpg) 13 | 14 | ![image](introduce/image5.jpg) 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 --------------------------------------------------------------------------------