5.11实例应用

5.11.1 颜色圆检测

RGB:

RGBA(Alpha),A用于描述三原色的透明度!

单通道:

俗称灰度图,每个像素点只能有一个值表示颜色,它的像素值在0到255之间,0是黑色,255是白色,中间值是一些不同等级的灰色,可以说灰度是黑与白之间的过渡色!

多通道:

多通道也就是RGB三原色,每个像素点有三个字节来表示(RGB),分别最大取值范围是0-255,可以组合成千万种颜色。

所以三通道想要组合成黑白色(灰度)必须三原色值相同。也就是说灰度图不一定是单通道,但是单通道一定是灰度图!

色调、饱和度、亮度(Hue, Saturation, Value):

色调(偏向)

色调决定一个像素点中的颜色更偏向于哪一方(RGB):

饱和度(深浅):

饱和度决定了颜色空间中颜色分量,饱和度越高,说明颜色越深,饱和度越低,说明颜色越浅!

亮度(明暗):

亮度决定颜色空间中颜色的明暗程度!

RGB和HSV关系:

其实色调,饱和度,亮度都是通过特定的算法经过计算修改RGB三色而达到的控制颜色效果!

  • 色调(H:hue):用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;
  • 饱和度(S:saturation):取值范围为0.0~1.0,值越大,颜色越饱和。
  • 亮度(V:value):取值范围为0(黑色)~255(白色)。

参考:

https://blog.csdn.net/bjbz_cxy/article/details/79701006

OpenCV下有个函数可以直接将RGB模型转换为HSV模型,注意的是OpenCV中H∈ [0, 180), S ∈ [0, 255], V ∈ [0, 255]。 

HoughCircles()使用比较关键是参数的设置

 1 ////////////https://blog.csdn.net/piaoxuezhong/article/details/60757278
 2 ////////找出圆绘制圆心和外圆
 3 #include <opencv2/opencv.hpp>
 4 #include <opencv2/imgproc/imgproc.hpp>
 5 
 6 using namespace cv;
 7 using namespace std;
 8 
 9 int main(int argc, char** argv)
10 {
11 
12     Mat srcImage = imread("D:\1块硬币.jpg");
13     Mat midImage, dstImage;
14     imshow("【原始图】", srcImage);
15 
16     cvtColor(srcImage, midImage, CV_BGR2GRAY);//转化边缘检测后的图为灰度图
17     GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);
18     vector<Vec3f> circles;
19     HoughCircles(midImage, circles, CV_HOUGH_GRADIENT, 1, midImage.rows / 20, 100, 100, 0, 0);
20     //依次在图中绘制出圆
21     for (size_t i = 0; i < circles.size(); i++)
22     {
23         Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
24         int radius = cvRound(circles[i][2]);
25         //绘制圆心
26         circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
27         //绘制圆轮廓
28         circle(srcImage, center, radius, Scalar(155, 50, 255), 3, 8, 0);
29     }
30 
31     imshow("【效果图】", srcImage);
32     waitKey(0);
33     return 0;
34 }
View Code

第1张图片:

第2张图片:

参考:https://blog.csdn.net/piaoxuezhong/article/details/60757278

 1 ////////https://blog.csdn.net/linqianbi/article/details/78936612
 2 #include<opencv2highguihighgui.hpp>
 3 #include<opencv2imgprocimgproc.hpp>
 4 #include<iostream>
 5 #include<vector>
 6 using namespace cv;
 7 using namespace std;
 8 int main()
 9 {
10     Mat srcImage = imread("D:\颜色圆.jpg");
11     if (!srcImage.data)
12     {
13         printf("could not load image...
");
14         return -1;
15     }
16     imshow("srcImage", srcImage);
17     Mat resultImag = srcImage.clone();
18     //中值滤波
19     medianBlur(srcImage, srcImage, 3);
20     //转换成HSV颜色空间
21     Mat hsvImage;
22     cvtColor(srcImage, hsvImage, CV_BGR2HSV);
23     imshow("hsvImage", hsvImage);
24     //颜色阈值化处理
25     //定义高低阈值
26     Mat lowMat;
27     Mat upperMat;
28     //红色H的范围是[0,10]  [160,180]
29     inRange(hsvImage, Scalar(0, 100, 100), Scalar(10, 255, 255), lowMat);
30     inRange(hsvImage, Scalar(160, 100, 100), Scalar(179, 255, 255), upperMat);
31     imshow("lowMat", lowMat);
32     imshow("upperMat", upperMat);
33     //将高低阈值合并
34     Mat redMat;
35     addWeighted(lowMat, 1, upperMat, 1, 0, redMat);
36     imshow("redMat", redMat);
37     //高斯滤波
38     GaussianBlur(redMat, redMat, Size(9, 9), 2, 2);
39     //霍夫圆加测
40     vector<Vec3f>  circles;
41     HoughCircles(redMat, circles, CV_HOUGH_GRADIENT, 1, redMat.rows / 8, 100, 50, 0, 0);
42     //如果没有检测到圆
43     if (circles.size() == 0)
44         return -1;
45     for (int i = 0; i < circles.size(); i++)
46     {
47         //求出圆心的位置和圆半径的大小
48         Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
49         int radius = cvRound(circles[i][2]);
50         circle(resultImag, center, radius, Scalar(0, 255, 0), 5);
51     }
52     imshow("resultImag", resultImag);
53     waitKey(0);
54     return 0;
55 }
View Code

1.将原始图片的BGR颜色空间转换到HSV色彩空间

2.根据红色在HSV中的范围,对图像进行阈值分割,红色的圆被保留(白色),其他的变成黑色

3.对步骤二检测到的高低阈值的颜色圆进行合并,找出属于红色的圆

4.利用霍夫圆检测算法找出步骤3中的圆

 

拓展:

如果要选中找出蓝色圆:

需要一个取色和调色小工具,这个小工具支持HSV空间的取色。不过不管是这个小工具还是PS中,H的范围都是0~360,S的范围是0到百分之百,V的范围也是0到百度分之百,这个也和百科上的解释是一致的。所以你在具体使用的时候要按比例转化一下哦!比如车牌蓝在标准HSV中是(225,100%,81%)那么转换到OpenCV中就是(225/360*180,255*100%,255*81%)!

参考:https://blog.csdn.net/wenhao_ir/article/details/51850948 

下面是用HoughCircles函数进行霍夫变换圆检测的实例。由于HoughCircles函数内是调用Canny函数进行边缘检测,opencv的Canny函数是不包括平滑滤波这一步的,因此为了增强抗干扰能力,在使用HoughCircles函数之前,我们先对原图进行滤波处理,我们使用的是高斯模糊方法。 

 参考:

https://blog.csdn.net/piaoxuezhong/article/details/60757278

https://blog.csdn.net/linqianbi/article/details/78936612

https://blog.csdn.net/poem_qianmo/article/details/26977557

https://blog.csdn.net/yanxiaolx/article/details/62889943

未研究:https://blog.csdn.net/taily_duan/article/details/51886019 

http://www.opencv.org.cn/forum.php?mod=viewthread&tid=34096

5.11.2 车牌区域检测

  1 ////////https://blog.csdn.net/z827997640/article/details/80527581
  2 
  3 #include <iostream>
  4 #include <vector>
  5 #include <stdint.h>
  6 #include "opencv2/core/core.hpp"
  7 #include "opencv2/highgui/highgui.hpp"
  8 #include "opencv2/imgproc/imgproc.hpp"
  9 #include "opencv2/features2d/features2d.hpp"
 10 // 提取竖直的sobel边缘
 11 bool SobelVerEdge(cv::Mat srcImage, cv::Mat& resultImage)
 12 {
 13     CV_Assert(srcImage.channels() == 1);
 14     srcImage.convertTo(srcImage, CV_32FC1);
 15     // 水平方向的 Sobel 算子
 16     cv::Mat sobelx = (cv::Mat_<float>(3, 3) << -0.125, 0, 0.125,
 17         -0.25, 0, 0.25,
 18         -0.125, 0, 0.125);
 19     cv::Mat ConResMat;
 20     // 卷积运算
 21     cv::filter2D(srcImage, ConResMat, srcImage.type(), sobelx);
 22     // 计算梯度的幅度
 23     cv::Mat graMagMat;
 24     cv::multiply(ConResMat, ConResMat, graMagMat);
 25     // 根据梯度幅度及参数设置阈值
 26     int scaleVal = 4;
 27     double thresh = scaleVal * cv::mean(graMagMat).val[0];
 28     cv::Mat resultTempMat = cv::Mat::zeros(
 29         graMagMat.size(), graMagMat.type());
 30     float* pDataMag = (float*)graMagMat.data;
 31     float* pDataRes = (float*)resultTempMat.data;
 32     const int nRows = ConResMat.rows;
 33     const int nCols = ConResMat.cols;
 34     for (int i = 1; i != nRows - 1; ++i) {
 35         for (int j = 1; j != nCols - 1; ++j) {
 36             // 计算该点梯度与水平或垂直梯度值大小比较结果
 37             bool b1 = (pDataMag[i * nCols + j] > pDataMag[i *
 38                 nCols + j - 1]);
 39             bool b2 = (pDataMag[i * nCols + j] > pDataMag[i *
 40                 nCols + j + 1]);
 41             bool b3 = (pDataMag[i * nCols + j] > pDataMag[(i - 1)
 42                 * nCols + j]);
 43             bool b4 = (pDataMag[i * nCols + j] > pDataMag[(i + 1)
 44                 * nCols + j]);
 45             // 判断邻域梯度是否满足大于水平或垂直梯度
 46             // 并根据自适应阈值参数进行二值化
 47             pDataRes[i * nCols + j] = 255 * ((pDataMag[i *
 48                 nCols + j] > thresh) &&
 49                 ((b1 && b2) || (b3 && b4)));
 50         }
 51     }
 52     resultTempMat.convertTo(resultTempMat, CV_8UC1);
 53     resultImage = resultTempMat.clone();
 54     return true;
 55 }
 56 // 疑似区域提取
 57 cv::Mat getPlateArea(cv::Mat srcImage, cv::Mat sobelMat)
 58 {
 59     // 转换成hsv 
 60     cv::Mat img_h, img_s, img_v, imghsv;
 61     std::vector<cv::Mat> hsv_vec;
 62     cv::cvtColor(srcImage, imghsv, CV_BGR2HSV);
 63     cv::imshow("hsv", imghsv);
 64     cv::waitKey(0);
 65     // 分割hsv通道
 66     cv::split(imghsv, hsv_vec);
 67     img_h = hsv_vec[0];
 68     img_s = hsv_vec[1];
 69     img_v = hsv_vec[2];
 70     img_h.convertTo(img_h, CV_32F);
 71     img_s.convertTo(img_s, CV_32F);
 72     img_v.convertTo(img_v, CV_32F);
 73     double max_s, max_h, max_v;
 74     cv::minMaxIdx(img_h, 0, &max_h);
 75     cv::minMaxIdx(img_s, 0, &max_s);
 76     cv::minMaxIdx(img_v, 0, &max_v);
 77     // 各个通道归一化
 78     img_h /= max_h;
 79     img_s /= max_s;
 80     img_v /= max_v;
 81     // hsv 限定范围元素提取
 82     cv::Mat bw_blue = ((img_h>0.45) &
 83         (img_h<0.75) &
 84         (img_s>0.15) &
 85         (img_v>0.25));
 86     int height = bw_blue.rows;
 87     int width = bw_blue.cols;
 88     cv::Mat bw_blue_edge = cv::Mat::zeros(bw_blue.size(), bw_blue.type());
 89     cv::imshow("bw_blue", bw_blue);
 90     cv::waitKey(0);
 91     // 车牌疑似区域提取
 92     for (int k = 1; k != height - 2; ++k)
 93     {
 94         for (int l = 1; l != width - 2; ++l)
 95         {
 96             cv::Rect rct;
 97             rct.x = l - 1;
 98             rct.y = k - 1;
 99             rct.height = 3;
100             rct.width = 3;
101             if ((sobelMat.at<uchar>(k, l) == 255) && (cv::countNonZero(bw_blue(rct)) >= 1))
102                 bw_blue_edge.at<uchar>(k, l) = 255;
103         }
104     }
105     // 形态学闭操作
106     cv::Mat morph;
107     cv::morphologyEx(bw_blue_edge, morph, cv::MORPH_CLOSE,
108         cv::Mat::ones(2, 25, CV_8UC1));
109     cv::Mat imshow5;
110     cv::resize(bw_blue_edge, imshow5, cv::Size(), 1, 1);
111     cv::imshow("morphology_bw_blue_edge", imshow5);
112     cv::waitKey(0);
113     // 连通区域提取
114     cv::imshow("morph", morph);
115     std::vector<std::vector<cv::Point> > region_contours;
116     cv::findContours(morph.clone(), region_contours,
117         CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
118     std::vector<cv::Rect> candidates;
119     std::vector<cv::Mat> candidates_img;
120     cv::Mat result;
121     for (size_t n = 0; n != region_contours.size(); ++n)
122     {
123         // 去除高度宽度不符合条件区域
124         cv::Rect rect = cv::boundingRect(region_contours[n]);
125         int sub = cv::countNonZero(morph(rect));
126         double ratio = double(sub) / rect.area();
127         double wh_ratio = double(rect.width) / rect.height;
128         if (ratio > 0.5 && wh_ratio > 2 && wh_ratio < 5 &&
129             rect.height > 12 && rect.width > 60)
130         {
131             cv::Mat small = bw_blue_edge(rect);
132             result = srcImage(rect);
133             cv::imshow("rect", srcImage(rect));
134             cv::waitKey(0);
135         }
136     }
137     return result;
138 }
139 int main()
140 {
141     cv::Mat srcImage = cv::imread("D:\车辆4.jpg");
142     if (!srcImage.data)
143         return 1;
144     cv::Mat srcGray;
145     cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);
146     cv::imshow("srcImage", srcImage);
147     // sobel 提取边缘
148     cv::Mat sobelMat;
149     SobelVerEdge(srcGray, sobelMat);
150     cv::imshow("Sobel", sobelMat);
151     // 疑似区域提取
152     cv::Mat result = getPlateArea(srcImage, sobelMat);
153     cv::imshow("result", result);
154     return 0;
155 }
View Code

  1 ////////https://blog.csdn.net/hust_bochu_xuchao/article/details/52230694
  2 ////////第4章图片“车辆4”才识别出车牌
  3 #include "opencv2/highgui/highgui.hpp"
  4 #include "opencv2/features2d.hpp"
  5 #include "opencv2/imgproc/imgproc.hpp"
  6 #include <iostream>
  7 // Mser车牌目标检测
  8 std::vector<cv::Rect> mserGetPlate(cv::Mat srcImage)
  9 {
 10     // HSV空间转换
 11     cv::Mat gray, gray_neg;
 12     cv::Mat hsi;
 13     cv::cvtColor(srcImage, hsi, CV_BGR2HSV);
 14     // 通道分离
 15     std::vector<cv::Mat> channels;
 16     cv::split(hsi, channels);
 17     // 提取h通道
 18     gray = channels[1];
 19     cv::imshow("提取h通道", gray);
 20     // 灰度转换 
 21     cv::cvtColor(srcImage, gray, CV_BGR2GRAY);
 22     // 取反值灰度
 23     gray_neg = 255 - gray;
 24     std::vector<std::vector<cv::Point> > regContours;
 25     std::vector<std::vector<cv::Point> > charContours;
 26 
 27     // 创建MSER对象
 28     cv::Ptr<cv::MSER> mesr1 = cv::MSER::create(2, 10, 5000, 0.5, 0.3);
 29     cv::Ptr<cv::MSER> mesr2 = cv::MSER::create(2, 2, 400, 0.1, 0.3);
 30 
 31 
 32     std::vector<cv::Rect> bboxes1;
 33     std::vector<cv::Rect> bboxes2;
 34     // MSER+ 检测
 35     mesr1->detectRegions(gray, regContours, bboxes1);
 36     // MSER-操作
 37     mesr2->detectRegions(gray_neg, charContours, bboxes2);
 38 
 39     cv::Mat mserMapMat = cv::Mat::zeros(srcImage.size(), CV_8UC1);
 40     cv::Mat mserNegMapMat = cv::Mat::zeros(srcImage.size(), CV_8UC1);
 41 
 42     for (int i = (int)regContours.size() - 1; i >= 0; i--)
 43     {
 44         // 根据检测区域点生成mser+结果
 45         const std::vector<cv::Point>& r = regContours[i];
 46         for (int j = 0; j < (int)r.size(); j++)
 47         {
 48             cv::Point pt = r[j];
 49             mserMapMat.at<unsigned char>(pt) = 255;
 50         }
 51     }
 52     // MSER- 检测
 53     for (int i = (int)charContours.size() - 1; i >= 0; i--)
 54     {
 55         // 根据检测区域点生成mser-结果
 56         const std::vector<cv::Point>& r = charContours[i];
 57         for (int j = 0; j < (int)r.size(); j++)
 58         {
 59             cv::Point pt = r[j];
 60             mserNegMapMat.at<unsigned char>(pt) = 255;
 61         }
 62     }
 63     // mser结果输出
 64     cv::Mat mserResMat;
 65     // mser+与mser-位与操作
 66     mserResMat = mserMapMat & mserNegMapMat;
 67     cv::imshow("mserMapMat", mserMapMat);
 68     cv::imshow("mserNegMapMat", mserNegMapMat);
 69     cv::imshow("mserResMat", mserResMat);
 70     // 闭操作连接缝隙
 71     cv::Mat mserClosedMat;
 72     cv::morphologyEx(mserResMat, mserClosedMat,
 73         cv::MORPH_CLOSE, cv::Mat::ones(1, 20, CV_8UC1));
 74     cv::imshow("mserClosedMat", mserClosedMat);
 75     // 寻找外部轮廓
 76     std::vector<std::vector<cv::Point> > plate_contours;
 77     cv::findContours(mserClosedMat, plate_contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
 78     // 候选车牌区域判断输出
 79     std::vector<cv::Rect> candidates;
 80     for (size_t i = 0; i != plate_contours.size(); ++i)
 81     {
 82         // 求解最小外界矩形
 83         cv::Rect rect = cv::boundingRect(plate_contours[i]);
 84         // 宽高比例
 85         double wh_ratio = rect.width / double(rect.height);
 86         // 不符合尺寸条件判断
 87         if (rect.height > 20 && wh_ratio > 4 && wh_ratio < 7)
 88             candidates.push_back(rect);
 89     }
 90     return  candidates;
 91 }
 92 int main()
 93 {
 94     cv::Mat srcImage = cv::imread("D:\车辆4.jpg");
 95     if (srcImage.empty())
 96         return-1;
 97     cv::imshow("src Image", srcImage);
 98     // 候选车牌区域检测
 99     std::vector<cv::Rect> candidates;
100     candidates = mserGetPlate(srcImage);
101     // 车牌区域显示
102     for (int i = 0; i < candidates.size(); ++i)
103     {
104         cv::imshow("rect", srcImage(candidates[i]));
105         cv::waitKey();
106     }
107     cv::waitKey(0);
108     return 0;
109 }
View Code

原文地址:https://www.cnblogs.com/thebreakofdawn/p/9535654.html