使用特定形状的轮廓包围
基本概念
在实际应用中, 经常会有将检测到的轮廓用多边形表示出来的需求, 提取包围轮廓的多边形也方便我们做进一步分析, 轮廓包围主要有一下几种:
- 轮廓外接矩形
- 轮廓最小外接矩形(旋转)
- 轮廓最小包围圆形
- 轮廓拟合椭圆
- 轮廓逼近多边形曲线
轮廓外接矩形不能进行旋转,为下图中所示的绿色框。
函数原型
轮廓外接矩形—boundingRect()
Rect boundingRect( InputArray points );
- points: 输入的二维点集, 可以填Mat类型或std::vector
- 返回值: Rect类矩形对象
代码
Mat srcImg =imread("33.png");
imshow("src", srcImg);
Mat dstImg = srcImg.clone(); //原图备份
cvtColor(srcImg, srcImg, CV_BGR2GRAY); //转为灰度图
threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY); //二值化
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(dstImg, contours, -1, Scalar(0, 0, 255), 2, 8); //绘制轮廓
int x0=0, y0=0, w0=0, h0=0;
for(int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8); //绘制轮廓
x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
rectangle(dstImg, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
}
imshow("boundRect", dstImg);
waitKey(0);
运行结果
应用实例一—分割硬币
代码
Mat srcImg =imread("D:\\1\\33.png");
imshow("src", srcImg);
Mat dstImg = srcImg.clone(); //原图备份
cvtColor(srcImg, srcImg, CV_BGR2GRAY); //转为灰度图
threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY); //二值化
imshow("threshold", srcImg);
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1)); //获得结构元素
dilate(srcImg, srcImg, element); //膨胀操作
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
drawContours(dstImg, contours, -1, Scalar(0, 0, 255), 2, 8); //绘制轮廓
int x0=0, y0=0, w0=0, h0=0;
for(int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8); //绘制轮廓
x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
if(w0>30 && h0>30)
rectangle(dstImg, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
}
imshow("boundRect", dstImg);
waitKey(0);
运行结果
注意知识点
1.膨胀
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1)); //获得结构元素
dilate(srcImg, srcImg, element); //膨胀操作
2.绘制条件
if(w0>30 && h0>30)
应用实例二—简单车牌字符分割
步骤是 :定位车牌区域;字符提取和分割
代码
Mat srcImg =imread("D:\\1\\car.jpg");
imshow("src", srcImg);
Mat dstImg = srcImg.clone(); //原图备份
medianBlur(srcImg, srcImg, 5); //中值滤波
cvtColor(srcImg, srcImg, CV_BGR2GRAY); //转为灰度图
threshold(srcImg, srcImg, 100, 255, CV_THRESH_BINARY); //二值化
imshow("threshold", srcImg);
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(srcImg, contours, hierarcy, CV_RETR_TREE, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(dstImg, contours, -1, Scalar(0, 0, 255), 2, 8); //绘制轮廓
int x0=0, y0=0, w0=0, h0=0;
for(int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
//drawContours(dstImg, contours, i, Scalar(0, 0, 255), 2, 8); //绘制轮廓
x0 = boundRect[i].x; //获得第i个外接矩形的左上角的x坐标
y0 = boundRect[i].y; //获得第i个外接矩形的左上角的y坐标
w0 = boundRect[i].width; //获得第i个外接矩形的宽度
h0 = boundRect[i].height; //获得第i个外接矩形的高度
if(w0>srcImg.cols/12 && w0<srcImg.cols/7 && h0>srcImg.rows/6 && h0<srcImg.rows*5/6)
{
char pic_name[10];
sprintf(pic_name, "E:\\%d.bmp", i);
Mat ROI = dstImg(Rect(x0, y0, w0, h0));
imwrite(pic_name, ROI);
rectangle(dstImg, Point(x0, y0), Point(x0+w0, y0+h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
}
}
imshow("boundRect", dstImg);
waitKey(0);
运行结果
知识点讲解
1.
if(w0>srcImg.cols/12 && w0<srcImg.cols/7 && h0>srcImg.rows/6 && h0<srcImg.rows*5/6)
这段代码用于控制分割图像的大小
2.滤波
需要进行滤波来去除边缘的一些杂点