基于边缘检测和HSV的图像识别算法

打印 上一主题 下一主题

主题 515|帖子 515|积分 1545

DryDetect.h

  1. #pragma once
  2. #include <iostream>
  3. #include <io.h>
  4. #include <fstream>
  5. #include <algorithm>
  6. #include "opencv2/opencv.hpp"
  7. #include "opencv2/core.hpp"
  8. #include "opencv2/imgproc.hpp"
  9. #include "opencv2/highgui.hpp"
  10. using namespace std;
  11. using namespace cv;
  12. struct DryParam
  13. {
  14.         //cv::Rect DryCard = cv::Rect(375, 95, 295, 505); //1, x,y,w,h (375,95), 670,600)
  15.         //cv::Rect DryCard = cv::Rect(880, 385, 420, 745); //2, (880,385), (1300,1100)
  16.         cv::Rect DryCard = cv::Rect(1070, 300, 390, 710); //8, (1070,300), (1460,1010)
  17.         int drydetect = 1; //if 0, 不用算法定位
  18.         float resizeRatio = 0;
  19.         //边缘检测法
  20.         double thresh1 = 40;   //边缘检测阈值
  21.         double thresh2 = 255;
  22.         int minWidth = 80;  //限制格子的最大最小宽高
  23.         int minHeight = 80;
  24.         int maxWidth = 130;
  25.         int maxHeight = 130;
  26.         float alpha = 2; //图像对比度
  27.         float beta = 5;   //图像亮度
  28.         cv::Vec3b lower_black = cv::Vec3b(26, 14, 24);
  29.         cv::Vec3b upper_black = cv::Vec3b(115, 158, 125);     // 黑色
  30.         cv::Vec3b lower_black1 = cv::Vec3b(14, 0, 0);
  31.         cv::Vec3b upper_black1 = cv::Vec3b(70, 148, 82);     // 黑色1
  32.         cv::Vec3b lower_black2 = cv::Vec3b(14, 0, 0);
  33.         cv::Vec3b upper_black2 = cv::Vec3b(110, 255, 82);     // 黑色2
  34.         /*cv::Vec3b lower = cv::Vec3b(55, 24, 134); //白色
  35.         cv::Vec3b upper = cv::Vec3b(95, 50, 200);*/
  36.         cv::Vec3b lower = cv::Vec3b(43, 18, 134); //白色
  37.         cv::Vec3b upper = cv::Vec3b(95, 80, 200);
  38.         cv::Vec3b lower_white = cv::Vec3b(0, 0, 130); // 0, 0, 95); //亮白色
  39.         cv::Vec3b upper_white = cv::Vec3b(150, 50, 250); // 150, 42, 250);
  40.         cv::Vec3b lower_blue = cv::Vec3b(90, 133, 42);  //深蓝
  41.         cv::Vec3b upper_blue = cv::Vec3b(107, 255, 155);
  42.         cv::Vec3b lower_blue2 = cv::Vec3b(65, 113, 30);  //暗蓝
  43.         cv::Vec3b upper_blue2 = cv::Vec3b(95, 255, 124);
  44.         cv::Vec3b lower_green = cv::Vec3b(28, 151, 55);       // 绿色
  45.         cv::Vec3b upper_green = cv::Vec3b(40, 255, 145);
  46.         cv::Vec3b lower_green2 = cv::Vec3b(54, 74, 75);       // 浅绿
  47.         cv::Vec3b upper_green2 = cv::Vec3b(71, 145, 140);
  48.         //HSV颜色空间法
  49.         //L(26, 21, 42), H(118, 156, 130)
  50.         //亮白色 0,95,0,18,252,255
  51.         //蓝色:: 86,95,148,225,71,124
  52.         //浅白色: 55,95,24,50,134,200
  53.         // 绿色:28,40,216,250,74,148
  54.         //浅绿: 59,73,77,135,80,126
  55. };
  56. void PrintCostTime(const char* str, double& t1, double& t2);
  57. void getFiles(string path, vector<string>& files);
  58. bool findSquares(const Mat& image, std::vector<cv::Rect>& resultBoxes, DryParam& DP);
  59. void BrightnessContrast(Mat& src, DryParam& DP);
  60. void get_mask_image(Mat &HSV, Mat &mask_img, DryParam& DP);
  61. void get_morphology_image(Mat &mask_img);
  62. bool HSVDet(Mat& input, std::vector<cv::Rect>& detectBoxes, DryParam& DP);
  63. bool CannyDet(Mat& _input, std::vector<cv::Rect>& detectBoxes, DryParam& DP);
  64. void sort_boxes(std::vector<cv::Rect>& resultBoxes);
  65. /*
  66. DryAlg       干化学检测卡定位接口函数
  67. src:         裁剪后的干化学图片
  68. resultBoxes: 识别定位的结果
  69. DP:          定位算法可调参数
  70. */
  71. int DryAlg(Mat& src, std::vector<cv::Rect>& resultBoxes, DryParam& DP);
复制代码
DryDetect.cpp

  1. #include "DryDetect.h"
  2. void PrintCostTime(const char* str, double& t1, double& t2) {
  3.         double t = (t2 - t1) * 1000 / cv::getTickFrequency();
  4.         printf("%s ===> %.2f ms\n", str, t);
  5. }
  6. void getFiles(string path, vector<string>& files)
  7. {
  8.         //文件句柄
  9.         intptr_t hFile = 0;
  10.         //文件信息
  11.         struct _finddata_t fileinfo;
  12.         string p;
  13.         char* files_format[2] = { "\\*.jpg" ,"\\*.png" };
  14.         for (int i = 0; i < sizeof(files_format) / sizeof(char*); i++) {
  15.                 p.assign(path).append(files_format[i]);
  16.                 hFile = _findfirst(p.c_str(), &fileinfo);
  17.                 if (hFile != -1)
  18.                 {
  19.                         do
  20.                         {
  21.                                 //如果是目录,迭代之,如果不是,加入列表
  22.                                 if ((fileinfo.attrib &  _A_SUBDIR))
  23.                                 {
  24.                                         if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
  25.                                                 getFiles(p.assign(path).append("\").append(fileinfo.name), files);
  26.                                 }
  27.                                 else
  28.                                 {
  29.                                         files.push_back(p.assign(path).append("\").append(fileinfo.name));
  30.                                 }
  31.                         } while (_findnext(hFile, &fileinfo) == 0);
  32.                         _findclose(hFile);
  33.                 }
  34.         }
  35. }
  36. bool cmp(cv::Rect a, cv::Rect b)
  37. {
  38.         bool big = a.width * a.height > b.width * b.height;
  39.         return big;
  40. }
  41. int sort_indexes(std::vector<cv::Rect>& b)
  42. {
  43.         std::sort(b.begin(), b.end(), cmp);
  44.         return 0;
  45. }
  46. static inline float intersection_area(const cv::Rect& a, const cv::Rect& b)
  47. {
  48.         const float eps = 1e-5;
  49.         //cv::Rect_<float> inter = a & b;
  50.         float x1max = max(a.x, b.x);  // 求两个窗口左上角x坐标最大值
  51.         float x2min = min(a.width + a.x, b.width + b.x);  // 求两个窗口右下角x坐标最小值
  52.         float y1max = max(a.y, b.y);  // 求两个窗口左上角y坐标最大值
  53.         float y2min = min(a.height + a.y, b.height + b.y);  // 求两个窗口右下角y坐标最小值
  54.         float overlapWidth = x2min - x1max;   // 计算两矩形重叠的宽度
  55.         float overlapHeight = y2min - y1max;  // 计算两矩形重叠的高度
  56.         if (overlapHeight > 0 && overlapHeight > 0) {
  57.                 float inter1 = overlapWidth * overlapHeight;
  58.                 return inter1;
  59.         }
  60.         else {
  61.                 return -1;
  62.         }
  63.         //float inter2 = inter.area();
  64.        
  65. }
  66. std::vector<cv::Rect> nms_sorted_bboxes(std::vector<cv::Rect>& boxes, float nms_threshold)
  67. {
  68.         sort_indexes(boxes);
  69.         std::vector<cv::Rect> finalResults;
  70.         std::vector<int> keep;
  71.         finalResults.clear();
  72.         keep.clear();
  73.         const int n = boxes.size();
  74.         std::vector<float> areas(n);
  75.         for (int i = 0; i < n; i++)
  76.         {
  77.                 areas[i] = boxes[i].width * boxes[i].height;
  78.                 keep.push_back(1);
  79.         }
  80.         for (int i = 0; i < n; i++)
  81.         {
  82.                 const cv::Rect& a = boxes[i];
  83.                 if (keep[i]) {
  84.                         for (int j = i + 1; j < n; j++)
  85.                         {
  86.                                 const cv::Rect& b = boxes[j];
  87.                                 // intersection over union
  88.                                 float inter_area = intersection_area(a, b);
  89.                                 if (inter_area > 0) {
  90.                                         float union_area = areas[i] + areas[j] - inter_area;
  91.                                         // float IoU = inter_area / union_area
  92.                                         if (inter_area / union_area > nms_threshold)
  93.                                                 keep[i] = 0;
  94.                                 }
  95.                         }
  96.                 }
  97.         }
  98.         for (int i = 0; i < n; i++)
  99.         {
  100.                 if (keep[i])
  101.                 {
  102.                         finalResults.push_back(boxes[i]);
  103.                 }
  104.         }
  105.         return finalResults;
  106. }
  107. bool CannyDet(Mat& _input, std::vector<cv::Rect>& detectBoxes, DryParam& DP)
  108. {
  109.         Mat input = _input.clone();
  110.         Mat gray, canny, gray2;
  111.         BrightnessContrast(input, DP);
  112.         cv::cvtColor(input, gray, cv::COLOR_BGR2GRAY);
  113.         //cv::threshold(gray, canny, 20, 255, cv::THRESH_OTSU);
  114.         //cv::adaptiveThreshold(gray, gray2, 255, cv::THRESH_BINARY_INV, cv::ADAPTIVE_THRESH_GAUSSIAN_C, 5,4);
  115.         Canny(gray, canny, DP.thresh1, DP.thresh2);
  116.         //auto kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
  117.         Mat kernel = Mat::ones(cv::Size(5, 5), CV_8UC1);
  118.         morphologyEx(canny, canny, cv::MORPH_CLOSE, kernel);
  119.         //morphologyEx(canny, canny, cv::MORPH_OPEN, kernel);
  120.         std::vector<std::vector<cv::Point>> Contours;
  121.         cv::findContours(canny, Contours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
  122.         if (int(Contours.size()) == 0) {
  123.                 return false;
  124.         }
  125.         //int boxNumber = 0;
  126.         for (int i = 0; i < int(Contours.size()); i++)
  127.         {
  128.                 vector<Point> p = Contours[i];
  129.                 //auto Area = contourArea(p);
  130.                 cv::Rect rect = boundingRect(p);
  131.                 if (rect.width < DP.minWidth || rect.height < DP.minHeight)
  132.                 {
  133.                         continue;
  134.                 }
  135.                 if (rect.width > DP.maxWidth || rect.height > DP.maxHeight)
  136.                 {
  137.                         continue;
  138.                 }
  139.                 //boxNumber += 1;
  140.                 detectBoxes.push_back(rect);
  141.                 //cout << "area: " << "   w,h: " << rect.width << "x" << rect.height << endl;
  142.                 //rectangle(image, rect, Scalar(0, 0, 255), 1, 8); //画矩形
  143.         }
  144.         return true;
  145. }
  146. bool HSVDet(Mat& input, std::vector<cv::Rect>& detectBoxes, DryParam& DP)
  147. {
  148.         Mat blur, mask_img;
  149.         Mat HSV = Mat(input.size(), CV_8UC3);
  150.         //GaussianBlur(input, blur, Size(5, 5), 0);
  151.         //medianBlur(input, blur, 5);
  152.         cvtColor(input, HSV, COLOR_BGR2HSV);
  153.         get_mask_image(HSV, mask_img, DP); //获取二值化图像
  154.         get_morphology_image(mask_img);
  155.         std::vector<std::vector<cv::Point>> Contours;
  156.         cv::findContours(mask_img, Contours, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE);
  157.         if (int(Contours.size()) == 0)
  158.         {
  159.                 return false;
  160.         }
  161.         //int boxNumber = 0;
  162.         for (int i = 0; i < int(Contours.size()); i++)
  163.         {
  164.                 vector<Point> p = Contours[i];
  165.                 cv::Rect rect = boundingRect(p);
  166.                 if (rect.width < DP.minWidth || rect.height < DP.minHeight)
  167.                 {
  168.                         continue;
  169.                 }
  170.                 if (rect.width > DP.maxWidth || rect.height > DP.maxHeight)
  171.                 {
  172.                         continue;
  173.                 }
  174.                 //boxNumber += 1;
  175.                 detectBoxes.push_back(rect);
  176.         }
  177.         return true;
  178. }
  179. bool findSquares(const Mat& _src, std::vector<cv::Rect>& resultBoxes, DryParam& DP)
  180. {
  181.         std::vector<cv::Rect>detectBoxes;
  182.         resultBoxes.clear();
  183.         detectBoxes.clear();
  184.         Mat image = _src.clone();
  185.         Mat blur, gray, dst, canny, hsv, mask;
  186.         //medianBlur(image, blur, 5);
  187.         //GaussianBlur(image, blur, Size(5, 5), 0);
  188.         HSVDet(image, detectBoxes, DP);  // HSVDet
  189.         CannyDet(image, detectBoxes, DP); // CannyDet
  190.         if (int(detectBoxes.size()) == 0) {
  191.                 return false;
  192.         }
  193.         resultBoxes = nms_sorted_bboxes(detectBoxes, 0.35);
  194.         //resultBoxes = detectBoxes;
  195.         //for (int i = 0; i < int(resultBoxes.size()); i++)
  196.         //{
  197.         //        rectangle(image, resultBoxes[i], Scalar(0, 0, 255), 1, 8); //画矩形
  198.         //}
  199.         //cout << "boxNumber: " << resultBoxes.size() << endl;
  200.         //cv::imshow("result", image);
  201.         //cv::waitKey(0);
  202.         if (int(resultBoxes.size()) == 8) {
  203.                 return true;
  204.         }
  205.         return false;
  206. }
  207. void BrightnessContrast(Mat& src, DryParam& DP)
  208. {
  209.         int height = src.rows;
  210.         int width = src.cols;
  211.         //float alpha = 1.3;
  212.         //float beta = 30;
  213.         //dst = Mat::zeros(src.size(), src.type());
  214.         for (int row = 0; row < height; row++) {
  215.                 uchar *pixel = src.ptr<uchar>(row);
  216.                 for (int col = 0; col < width; col++) {
  217.                         if (src.channels() == 3) {
  218.                                 pixel[0] = saturate_cast<uchar>(pixel[0] * DP.alpha + DP.beta);
  219.                                 pixel[1] = saturate_cast<uchar>(pixel[1] * DP.alpha + DP.beta);
  220.                                 pixel[2] = saturate_cast<uchar>(pixel[2] * DP.alpha + DP.beta);
  221.                                 pixel += 3;
  222.                         }
  223.                         else if (src.channels() == 1) {
  224.                                 pixel[col] = pixel[col] * DP.alpha + DP.beta;
  225.                         }
  226.                 }
  227.         }
  228. }
  229. void get_mask_image(Mat &HSV, Mat &mask_img, DryParam& DP)
  230. {
  231.         Mat mask1, mask2, mask3, mask4, mask5, mask6;
  232.         cv::inRange(HSV, DP.lower_black2, DP.upper_black2, mask_img);
  233.         bitwise_not(mask_img, mask_img);
  234.         /*cv::inRange(HSV, DP.lower, DP.upper, mask6);
  235.         cv::inRange(HSV, DP.lower_white, DP.upper_white, mask1);
  236.        
  237.         cv::inRange(HSV, DP.lower_blue, DP.upper_blue, mask2);
  238.         cv::inRange(HSV, DP.lower_blue2, DP.upper_blue2, mask5);
  239.         cv::inRange(HSV, DP.lower_green, DP.upper_green, mask3);
  240.         cv::inRange(HSV, DP.lower_green2, DP.upper_green2, mask4);
  241.         mask_img = mask6 +mask2 + mask3 + mask4 + mask5 + mask1;*/
  242.         //bitwise_not(mask_img, mask_img);
  243. }
  244. void get_morphology_image(Mat &mask_img)
  245. {
  246.         auto kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
  247.         morphologyEx(mask_img, mask_img, cv::MORPH_CLOSE, kernel);
  248.         morphologyEx(mask_img, mask_img, cv::MORPH_OPEN, kernel);
  249. }
  250. bool cmp2(cv::Rect a, cv::Rect b)
  251. {
  252.         return a.x < b.x;
  253. }
  254. bool cmp3(cv::Rect a, cv::Rect b)
  255. {
  256.         return a.y < b.y;
  257. }
  258. void sort_boxes(std::vector<cv::Rect>& boxes)
  259. {
  260.         std::vector<cv::Rect> xBoxes, yBoxes;
  261.         xBoxes.clear();
  262.         yBoxes.clear();
  263.         std::sort(boxes.begin(), boxes.end(), cmp2);
  264.         xBoxes.insert(xBoxes.end(), boxes.begin(), boxes.begin() + 4); //左边一列
  265.         yBoxes.insert(yBoxes.end(), boxes.begin() + 4, boxes.end());   //右边一列
  266.         std::sort(xBoxes.begin(), xBoxes.end(), cmp3);
  267.         std::sort(yBoxes.begin(), yBoxes.end(), cmp3);
  268.         boxes.clear();
  269.         boxes.insert(boxes.end(), xBoxes.begin(), xBoxes.end());
  270.         boxes.insert(boxes.end(), yBoxes.begin(), yBoxes.end());
  271. }
  272. int DryAlg(Mat& src, std::vector<cv::Rect>& resultBoxes, DryParam& DP)
  273. {
  274.         if (!src.data) {
  275.                 //cout << "load image error..." << endl;
  276.                 return -1;
  277.         }
  278.         Mat input;
  279.         //将原图裁剪并缩小 resizeRatio;
  280.         //Mat img = src(DP.DryCard);
  281.         Mat img = src.clone();
  282.         int col = img.cols;
  283.         int row = img.rows;
  284.         if (DP.resizeRatio > 0) {
  285.                 cv::resize(img, input, Size(col * DP.resizeRatio, row * DP.resizeRatio));
  286.         }
  287.         else {
  288.                 input = img;
  289.         }
  290.         //double t1 = cv::getTickCount();
  291.         if (!findSquares(input, resultBoxes, DP))
  292.         {
  293.                 return 0;
  294.         }
  295.         sort_boxes(resultBoxes);
  296.         //double t2 = cv::getTickCount();
  297.         //PrintCostTime("findSquares:", t1, t2);
  298.         for (int i = 0; i < resultBoxes.size(); i++)
  299.         {
  300.                 //rectangle(input, resultBoxes[i], Scalar(0, 0, 255), 1);
  301.                 //将检测坐标映射回原图
  302.                 if (DP.resizeRatio > 0) {
  303.                         resultBoxes[i].x /= DP.resizeRatio;
  304.                         resultBoxes[i].y /= DP.resizeRatio;
  305.                         resultBoxes[i].width /= DP.resizeRatio;
  306.                         resultBoxes[i].height /= DP.resizeRatio;
  307.                 }
  308.                 //rectangle(img, resultBoxes[i], Scalar(0, 0, 255), 2);
  309.                 //resultBoxes[i].x += DP.DryCard.x;
  310.                 //resultBoxes[i].y += DP.DryCard.y;
  311.                 //rectangle(src, resultBoxes[i], Scalar(0, 0, 255), 2);
  312.         }
  313.         //cv::resize(src, src, Size(src.cols * 0.5, src.rows * 0.5));
  314.         cv::imwrite("out.jpg", src);
  315.         //cv::imshow("out", src);
  316.         //cv::imshow("result", img);
  317.         //cv::waitKey(0);
  318.         return 1;
  319. }
复制代码
main.cpp

  1. #include "DryDetect.h"
  2. int main()
  3. {
  4.         Mat src = cv::imread("H:\\ImageProcess\\Dry\\image\\7.jpg");
  5.         /*
  6.         -1:传入图片错误
  7.         0:没有检测到框
  8.         1:成功检测到了框
  9.         */
  10.         DryParam DP;
  11.         //以下参数做成配置文件可修改
  12.         DP.minWidth = 80;   // 可调参数,限制格子的最大最小宽高
  13.         DP.minHeight = 80;
  14.         DP.maxWidth = 180;
  15.         DP.maxHeight = 180;
  16.         DP.drydetect = 1; //if 0, 不用算法定位
  17.         std::vector<cv::Rect> resultBoxes; //算法识别结果
  18.         /*
  19.         Dryflag:
  20.         -1: 传入图片错误
  21.         0:  没有检测到框
  22.         1:  成功检测到了框
  23.         */
  24.         int Dryflag;
  25.         if (DP.drydetect = 0)  //0: 不调用算法定位
  26.         {
  27.                 Dryflag = 0;
  28.         }
  29.         else
  30.         {
  31.                 Dryflag = DryAlg(src, resultBoxes, DP);
  32.         }
  33.         switch (Dryflag)
  34.         {
  35.         case -1:
  36.         {
  37.                 cout << "load image error..." << endl;
  38.                 break;
  39.         }
  40.         case 0:
  41.         {
  42.                 cout << "detect box fail..." << endl;
  43.                 break;
  44.         }
  45.         default:
  46.                 break;
  47.         }
  48.         return 0;
  49. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表