DryDetect.h
- #pragma once
- #include <iostream>
- #include <io.h>
- #include <fstream>
- #include <algorithm>
- #include "opencv2/opencv.hpp"
- #include "opencv2/core.hpp"
- #include "opencv2/imgproc.hpp"
- #include "opencv2/highgui.hpp"
- using namespace std;
- using namespace cv;
- struct DryParam
- {
- //cv::Rect DryCard = cv::Rect(375, 95, 295, 505); //1, x,y,w,h (375,95), 670,600)
- //cv::Rect DryCard = cv::Rect(880, 385, 420, 745); //2, (880,385), (1300,1100)
- cv::Rect DryCard = cv::Rect(1070, 300, 390, 710); //8, (1070,300), (1460,1010)
- int drydetect = 1; //if 0, 不用算法定位
- float resizeRatio = 0;
- //边缘检测法
- double thresh1 = 40; //边缘检测阈值
- double thresh2 = 255;
- int minWidth = 80; //限制格子的最大最小宽高
- int minHeight = 80;
- int maxWidth = 130;
- int maxHeight = 130;
- float alpha = 2; //图像对比度
- float beta = 5; //图像亮度
- cv::Vec3b lower_black = cv::Vec3b(26, 14, 24);
- cv::Vec3b upper_black = cv::Vec3b(115, 158, 125); // 黑色
- cv::Vec3b lower_black1 = cv::Vec3b(14, 0, 0);
- cv::Vec3b upper_black1 = cv::Vec3b(70, 148, 82); // 黑色1
- cv::Vec3b lower_black2 = cv::Vec3b(14, 0, 0);
- cv::Vec3b upper_black2 = cv::Vec3b(110, 255, 82); // 黑色2
- /*cv::Vec3b lower = cv::Vec3b(55, 24, 134); //白色
- cv::Vec3b upper = cv::Vec3b(95, 50, 200);*/
- cv::Vec3b lower = cv::Vec3b(43, 18, 134); //白色
- cv::Vec3b upper = cv::Vec3b(95, 80, 200);
- cv::Vec3b lower_white = cv::Vec3b(0, 0, 130); // 0, 0, 95); //亮白色
- cv::Vec3b upper_white = cv::Vec3b(150, 50, 250); // 150, 42, 250);
- cv::Vec3b lower_blue = cv::Vec3b(90, 133, 42); //深蓝
- cv::Vec3b upper_blue = cv::Vec3b(107, 255, 155);
- cv::Vec3b lower_blue2 = cv::Vec3b(65, 113, 30); //暗蓝
- cv::Vec3b upper_blue2 = cv::Vec3b(95, 255, 124);
- cv::Vec3b lower_green = cv::Vec3b(28, 151, 55); // 绿色
- cv::Vec3b upper_green = cv::Vec3b(40, 255, 145);
- cv::Vec3b lower_green2 = cv::Vec3b(54, 74, 75); // 浅绿
- cv::Vec3b upper_green2 = cv::Vec3b(71, 145, 140);
- //HSV颜色空间法
- //L(26, 21, 42), H(118, 156, 130)
- //亮白色 0,95,0,18,252,255
- //蓝色:: 86,95,148,225,71,124
- //浅白色: 55,95,24,50,134,200
- // 绿色:28,40,216,250,74,148
- //浅绿: 59,73,77,135,80,126
- };
- void PrintCostTime(const char* str, double& t1, double& t2);
- void getFiles(string path, vector<string>& files);
- bool findSquares(const Mat& image, std::vector<cv::Rect>& resultBoxes, DryParam& DP);
- void BrightnessContrast(Mat& src, DryParam& DP);
- void get_mask_image(Mat &HSV, Mat &mask_img, DryParam& DP);
- void get_morphology_image(Mat &mask_img);
- bool HSVDet(Mat& input, std::vector<cv::Rect>& detectBoxes, DryParam& DP);
- bool CannyDet(Mat& _input, std::vector<cv::Rect>& detectBoxes, DryParam& DP);
- void sort_boxes(std::vector<cv::Rect>& resultBoxes);
- /*
- DryAlg 干化学检测卡定位接口函数
- src: 裁剪后的干化学图片
- resultBoxes: 识别定位的结果
- DP: 定位算法可调参数
- */
- int DryAlg(Mat& src, std::vector<cv::Rect>& resultBoxes, DryParam& DP);
复制代码 DryDetect.cpp
- #include "DryDetect.h"
- void PrintCostTime(const char* str, double& t1, double& t2) {
- double t = (t2 - t1) * 1000 / cv::getTickFrequency();
- printf("%s ===> %.2f ms\n", str, t);
- }
- void getFiles(string path, vector<string>& files)
- {
- //文件句柄
- intptr_t hFile = 0;
- //文件信息
- struct _finddata_t fileinfo;
- string p;
- char* files_format[2] = { "\\*.jpg" ,"\\*.png" };
- for (int i = 0; i < sizeof(files_format) / sizeof(char*); i++) {
- p.assign(path).append(files_format[i]);
- hFile = _findfirst(p.c_str(), &fileinfo);
- if (hFile != -1)
- {
- do
- {
- //如果是目录,迭代之,如果不是,加入列表
- if ((fileinfo.attrib & _A_SUBDIR))
- {
- if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
- getFiles(p.assign(path).append("\").append(fileinfo.name), files);
- }
- else
- {
- files.push_back(p.assign(path).append("\").append(fileinfo.name));
- }
- } while (_findnext(hFile, &fileinfo) == 0);
- _findclose(hFile);
- }
- }
- }
- bool cmp(cv::Rect a, cv::Rect b)
- {
- bool big = a.width * a.height > b.width * b.height;
- return big;
- }
- int sort_indexes(std::vector<cv::Rect>& b)
- {
- std::sort(b.begin(), b.end(), cmp);
- return 0;
- }
- static inline float intersection_area(const cv::Rect& a, const cv::Rect& b)
- {
- const float eps = 1e-5;
- //cv::Rect_<float> inter = a & b;
- float x1max = max(a.x, b.x); // 求两个窗口左上角x坐标最大值
- float x2min = min(a.width + a.x, b.width + b.x); // 求两个窗口右下角x坐标最小值
- float y1max = max(a.y, b.y); // 求两个窗口左上角y坐标最大值
- float y2min = min(a.height + a.y, b.height + b.y); // 求两个窗口右下角y坐标最小值
- float overlapWidth = x2min - x1max; // 计算两矩形重叠的宽度
- float overlapHeight = y2min - y1max; // 计算两矩形重叠的高度
- if (overlapHeight > 0 && overlapHeight > 0) {
- float inter1 = overlapWidth * overlapHeight;
- return inter1;
- }
- else {
- return -1;
- }
- //float inter2 = inter.area();
-
- }
- std::vector<cv::Rect> nms_sorted_bboxes(std::vector<cv::Rect>& boxes, float nms_threshold)
- {
- sort_indexes(boxes);
- std::vector<cv::Rect> finalResults;
- std::vector<int> keep;
- finalResults.clear();
- keep.clear();
- const int n = boxes.size();
- std::vector<float> areas(n);
- for (int i = 0; i < n; i++)
- {
- areas[i] = boxes[i].width * boxes[i].height;
- keep.push_back(1);
- }
- for (int i = 0; i < n; i++)
- {
- const cv::Rect& a = boxes[i];
- if (keep[i]) {
- for (int j = i + 1; j < n; j++)
- {
- const cv::Rect& b = boxes[j];
- // intersection over union
- float inter_area = intersection_area(a, b);
- if (inter_area > 0) {
- float union_area = areas[i] + areas[j] - inter_area;
- // float IoU = inter_area / union_area
- if (inter_area / union_area > nms_threshold)
- keep[i] = 0;
- }
- }
- }
- }
- for (int i = 0; i < n; i++)
- {
- if (keep[i])
- {
- finalResults.push_back(boxes[i]);
- }
- }
- return finalResults;
- }
- bool CannyDet(Mat& _input, std::vector<cv::Rect>& detectBoxes, DryParam& DP)
- {
- Mat input = _input.clone();
- Mat gray, canny, gray2;
- BrightnessContrast(input, DP);
- cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
- //cv::threshold(gray, canny, 20, 255, cv::THRESH_OTSU);
- //cv::adaptiveThreshold(gray, gray2, 255, cv::THRESH_BINARY_INV, cv::ADAPTIVE_THRESH_GAUSSIAN_C, 5,4);
- Canny(gray, canny, DP.thresh1, DP.thresh2);
- //auto kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
- Mat kernel = Mat::ones(cv::Size(5, 5), CV_8UC1);
- morphologyEx(canny, canny, cv::MORPH_CLOSE, kernel);
- //morphologyEx(canny, canny, cv::MORPH_OPEN, kernel);
- std::vector<std::vector<cv::Point>> Contours;
- cv::findContours(canny, Contours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
- if (int(Contours.size()) == 0) {
- return false;
- }
- //int boxNumber = 0;
- for (int i = 0; i < int(Contours.size()); i++)
- {
- vector<Point> p = Contours[i];
- //auto Area = contourArea(p);
- cv::Rect rect = boundingRect(p);
- if (rect.width < DP.minWidth || rect.height < DP.minHeight)
- {
- continue;
- }
- if (rect.width > DP.maxWidth || rect.height > DP.maxHeight)
- {
- continue;
- }
- //boxNumber += 1;
- detectBoxes.push_back(rect);
- //cout << "area: " << " w,h: " << rect.width << "x" << rect.height << endl;
- //rectangle(image, rect, Scalar(0, 0, 255), 1, 8); //画矩形
- }
- return true;
- }
- bool HSVDet(Mat& input, std::vector<cv::Rect>& detectBoxes, DryParam& DP)
- {
- Mat blur, mask_img;
- Mat HSV = Mat(input.size(), CV_8UC3);
- //GaussianBlur(input, blur, Size(5, 5), 0);
- //medianBlur(input, blur, 5);
- cvtColor(input, HSV, COLOR_BGR2HSV);
- get_mask_image(HSV, mask_img, DP); //获取二值化图像
- get_morphology_image(mask_img);
- std::vector<std::vector<cv::Point>> Contours;
- cv::findContours(mask_img, Contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
- if (int(Contours.size()) == 0)
- {
- return false;
- }
- //int boxNumber = 0;
- for (int i = 0; i < int(Contours.size()); i++)
- {
- vector<Point> p = Contours[i];
- cv::Rect rect = boundingRect(p);
- if (rect.width < DP.minWidth || rect.height < DP.minHeight)
- {
- continue;
- }
- if (rect.width > DP.maxWidth || rect.height > DP.maxHeight)
- {
- continue;
- }
- //boxNumber += 1;
- detectBoxes.push_back(rect);
- }
- return true;
- }
- bool findSquares(const Mat& _src, std::vector<cv::Rect>& resultBoxes, DryParam& DP)
- {
- std::vector<cv::Rect>detectBoxes;
- resultBoxes.clear();
- detectBoxes.clear();
- Mat image = _src.clone();
- Mat blur, gray, dst, canny, hsv, mask;
- //medianBlur(image, blur, 5);
- //GaussianBlur(image, blur, Size(5, 5), 0);
- HSVDet(image, detectBoxes, DP); // HSVDet
- CannyDet(image, detectBoxes, DP); // CannyDet
- if (int(detectBoxes.size()) == 0) {
- return false;
- }
- resultBoxes = nms_sorted_bboxes(detectBoxes, 0.35);
- //resultBoxes = detectBoxes;
- //for (int i = 0; i < int(resultBoxes.size()); i++)
- //{
- // rectangle(image, resultBoxes[i], Scalar(0, 0, 255), 1, 8); //画矩形
- //}
- //cout << "boxNumber: " << resultBoxes.size() << endl;
- //cv::imshow("result", image);
- //cv::waitKey(0);
- if (int(resultBoxes.size()) == 8) {
- return true;
- }
- return false;
- }
- void BrightnessContrast(Mat& src, DryParam& DP)
- {
- int height = src.rows;
- int width = src.cols;
- //float alpha = 1.3;
- //float beta = 30;
- //dst = Mat::zeros(src.size(), src.type());
- for (int row = 0; row < height; row++) {
- uchar *pixel = src.ptr<uchar>(row);
- for (int col = 0; col < width; col++) {
- if (src.channels() == 3) {
- pixel[0] = saturate_cast<uchar>(pixel[0] * DP.alpha + DP.beta);
- pixel[1] = saturate_cast<uchar>(pixel[1] * DP.alpha + DP.beta);
- pixel[2] = saturate_cast<uchar>(pixel[2] * DP.alpha + DP.beta);
- pixel += 3;
- }
- else if (src.channels() == 1) {
- pixel[col] = pixel[col] * DP.alpha + DP.beta;
- }
- }
- }
- }
- void get_mask_image(Mat &HSV, Mat &mask_img, DryParam& DP)
- {
- Mat mask1, mask2, mask3, mask4, mask5, mask6;
- cv::inRange(HSV, DP.lower_black2, DP.upper_black2, mask_img);
- bitwise_not(mask_img, mask_img);
- /*cv::inRange(HSV, DP.lower, DP.upper, mask6);
- cv::inRange(HSV, DP.lower_white, DP.upper_white, mask1);
-
- cv::inRange(HSV, DP.lower_blue, DP.upper_blue, mask2);
- cv::inRange(HSV, DP.lower_blue2, DP.upper_blue2, mask5);
- cv::inRange(HSV, DP.lower_green, DP.upper_green, mask3);
- cv::inRange(HSV, DP.lower_green2, DP.upper_green2, mask4);
- mask_img = mask6 +mask2 + mask3 + mask4 + mask5 + mask1;*/
- //bitwise_not(mask_img, mask_img);
- }
- void get_morphology_image(Mat &mask_img)
- {
- auto kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
- morphologyEx(mask_img, mask_img, cv::MORPH_CLOSE, kernel);
- morphologyEx(mask_img, mask_img, cv::MORPH_OPEN, kernel);
- }
- bool cmp2(cv::Rect a, cv::Rect b)
- {
- return a.x < b.x;
- }
- bool cmp3(cv::Rect a, cv::Rect b)
- {
- return a.y < b.y;
- }
- void sort_boxes(std::vector<cv::Rect>& boxes)
- {
- std::vector<cv::Rect> xBoxes, yBoxes;
- xBoxes.clear();
- yBoxes.clear();
- std::sort(boxes.begin(), boxes.end(), cmp2);
- xBoxes.insert(xBoxes.end(), boxes.begin(), boxes.begin() + 4); //左边一列
- yBoxes.insert(yBoxes.end(), boxes.begin() + 4, boxes.end()); //右边一列
- std::sort(xBoxes.begin(), xBoxes.end(), cmp3);
- std::sort(yBoxes.begin(), yBoxes.end(), cmp3);
- boxes.clear();
- boxes.insert(boxes.end(), xBoxes.begin(), xBoxes.end());
- boxes.insert(boxes.end(), yBoxes.begin(), yBoxes.end());
- }
- int DryAlg(Mat& src, std::vector<cv::Rect>& resultBoxes, DryParam& DP)
- {
- if (!src.data) {
- //cout << "load image error..." << endl;
- return -1;
- }
- Mat input;
- //将原图裁剪并缩小 resizeRatio;
- //Mat img = src(DP.DryCard);
- Mat img = src.clone();
- int col = img.cols;
- int row = img.rows;
- if (DP.resizeRatio > 0) {
- cv::resize(img, input, Size(col * DP.resizeRatio, row * DP.resizeRatio));
- }
- else {
- input = img;
- }
- //double t1 = cv::getTickCount();
- if (!findSquares(input, resultBoxes, DP))
- {
- return 0;
- }
- sort_boxes(resultBoxes);
- //double t2 = cv::getTickCount();
- //PrintCostTime("findSquares:", t1, t2);
- for (int i = 0; i < resultBoxes.size(); i++)
- {
- //rectangle(input, resultBoxes[i], Scalar(0, 0, 255), 1);
- //将检测坐标映射回原图
- if (DP.resizeRatio > 0) {
- resultBoxes[i].x /= DP.resizeRatio;
- resultBoxes[i].y /= DP.resizeRatio;
- resultBoxes[i].width /= DP.resizeRatio;
- resultBoxes[i].height /= DP.resizeRatio;
- }
- //rectangle(img, resultBoxes[i], Scalar(0, 0, 255), 2);
- //resultBoxes[i].x += DP.DryCard.x;
- //resultBoxes[i].y += DP.DryCard.y;
- //rectangle(src, resultBoxes[i], Scalar(0, 0, 255), 2);
- }
- //cv::resize(src, src, Size(src.cols * 0.5, src.rows * 0.5));
- cv::imwrite("out.jpg", src);
- //cv::imshow("out", src);
- //cv::imshow("result", img);
- //cv::waitKey(0);
- return 1;
- }
复制代码 main.cpp
- #include "DryDetect.h"
- int main()
- {
- Mat src = cv::imread("H:\\ImageProcess\\Dry\\image\\7.jpg");
- /*
- -1:传入图片错误
- 0:没有检测到框
- 1:成功检测到了框
- */
- DryParam DP;
- //以下参数做成配置文件可修改
- DP.minWidth = 80; // 可调参数,限制格子的最大最小宽高
- DP.minHeight = 80;
- DP.maxWidth = 180;
- DP.maxHeight = 180;
- DP.drydetect = 1; //if 0, 不用算法定位
- std::vector<cv::Rect> resultBoxes; //算法识别结果
- /*
- Dryflag:
- -1: 传入图片错误
- 0: 没有检测到框
- 1: 成功检测到了框
- */
- int Dryflag;
- if (DP.drydetect = 0) //0: 不调用算法定位
- {
- Dryflag = 0;
- }
- else
- {
- Dryflag = DryAlg(src, resultBoxes, DP);
- }
- switch (Dryflag)
- {
- case -1:
- {
- cout << "load image error..." << endl;
- break;
- }
- case 0:
- {
- cout << "detect box fail..." << endl;
- break;
- }
- default:
- break;
- }
- return 0;
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |