OpenCv学习笔记1-轮廓检测
一、轮廓检测的基本原理
实现思路:通过找出在一张图片中满足特定像素值的像素点,实现轮廓绘制。
实验流程:
(1)颜色空间转换
(2)二值化处理
(3)腐蚀膨胀
(4)轮廓绘制
二、实验流程
1.颜色空间转换
实验第一步需要将RGB颜色空间转成HSV颜色空间,RGB对硬件友好,而HSV则对我们人眼友好,根据下面的表格我们可以得出需要的结果
例如我们如果想要框出这两车的车牌号,我们就可以直接用微信截图里的框(bushi),我们就可以把颜色为蓝色的点集寻找出来,使用阈值处理得到二值图
2.二值化处理
代码如下(示例):
// 转颜色空间
// 转颜色空间
cvtColor(img, dst, CV_BGR2HSV);
Mat dstImage;
//二值化,+90为调整过后的参数,可以自行修改得到最佳值
inRange(dst, Scalar(105, 53+90, 46), Scalar(114, 255, 255), dstImage);
3.腐蚀膨胀
腐蚀膨胀的主要作用就是去除噪声
腐蚀:遍历一个点周围的8个点,将当前点修改为周围点中的最小值
膨胀:遍历一个点周围的8个点,将当前点修改为周围点中的最大值
直接使用opencv中的现成库!
代码如下(示例):
// 转颜色空间
//腐蚀膨胀
Mat dstImage1_5;
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
erode(dstImage, dstImage1_5, element, Point(-1, -1), 1, 0);
Mat dstImage1_75;
dilate(dstImage1_5, dstImage1_75, element, Point(-1, -1), 1);
前后效果图:
可以看出,左侧的噪声明显减少
4.轮廓绘制
第一步,找点集
我们在上面得到了二值图,即得到了想要部分(白色)和不想要部分,那么第二步,我们则需要找出边界的点集,使用以下函数即可
findContours(dstImage, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
第二步,找点集的外接矩形
在上面的函数处理后,返回的contours是一个点集,我们对这些点集直接使用下面函数寻找其外接矩形
boundRect[i] = boundingRect(Mat(contours[i]));
对返回的多个矩形通过长宽进行筛选,最终得到正确结果
double wh = boundRect[i].width / boundRect[i].height;
if(wh>2&& boundRect[i].height>20)
完整代码
#include<iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include<cstdlib>
#include<ctime>
using namespace std;
using namespace cv;
int main() {
//定义变量
Mat img;
Mat dst;
Mat result;
//载入图片
img = imread("C:\\Users\\EDZ\\Desktop\\1.jpg");
// 转颜色空间
cvtColor(img, dst, CV_BGR2HSV);
Mat dstImage;
//二值化
inRange(dst, Scalar(105, 53+90, 46), Scalar(114, 255, 255), dstImage);
//腐蚀膨胀
Mat dstImage1_5;
Mat element = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
erode(dstImage, dstImage1_5, element, Point(-1, -1), 1, 0);
Mat dstImage1_75;
dilate(dstImage1_5, dstImage1_75, element, Point(-1, -1), 1);
//轮廓绘制
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(dstImage, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
vector<RotatedRect> box(contours.size()); //定义最小外接矩形集合
Point2f rect[4];
for (int i = 0; i < contours.size(); i++)
{
box[i] = minAreaRect(Mat(contours[i])); //计算每个轮廓最小外接矩形
boundRect[i] = boundingRect(Mat(contours[i]));
box[i].points(rect); //把最小外接矩形四个端点复制给rect数组
double wh = boundRect[i].width / boundRect[i].height;
if(wh>2&& boundRect[i].height>20){
rectangle(img, Point(boundRect[i].x, boundRect[i].y), Point(boundRect[i].x + boundRect[i].width, boundRect[i].y + boundRect[i].height), Scalar(0, 255, 0), 2, 8);
for (int j = 0; j < 4; j++)
{
line(img, rect[j], rect[(j + 1) % 4], Scalar(0, 255, 0), 2, 8); //绘制最小外接矩形每条边
}
}
imshow("结果图", img);
}
/*通道统一
Mat dstImage2;
//cvtColor(dstImage1_75, dstImage2, COLOR_GRAY2BGR);
cvtColor(dstImage, dstImage2, COLOR_GRAY2BGR);
//掩码
Mat r;
bitwise_and(img2, dstImage2, r);*/
//显示原图
namedWindow("Image");
imshow("Image", img);
// 显示二值图
namedWindow("二值化后的图像1");
imshow("二值化后的图像1", dstImage);
//腐蚀膨胀图
namedWindow("腐蚀膨胀后的图像1");
imshow("腐蚀膨胀后的图像1", dstImage1_75);
//掩码图
//namedWindow("掩码图");
//imshow("掩码图", r);
waitKey(0);
return 0;
}
效果图: