3 对象提取
3.1 题目
如下图,去除圆之外的杂物,并计算圆的半径。
3.2 思路
- 二值化处理tuxiang
- 形态学操作去除小杂物
- 轮廓查找,根据面积横纵比进行筛选找出圆
- 感兴趣区域保留
3.3 示例代码
#include <opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
Mat sorImg = imread("test.jpg", IMREAD_UNCHANGED);
imshow("sorImg", sorImg);
Mat grayImg;
cvtColor(sorImg, grayImg, COLOR_BGR2GRAY);
// 第一步:二值化
threshold(grayImg, grayImg, 220, 255, THRESH_BINARY_INV);
// 第二步:形态学操作
Mat morphologyImg;
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(11, 11));
// 闭操作先填充空洞
morphologyEx(grayImg, morphologyImg, MORPH_CLOSE, kernel);
开操作去除小杂物
kernel = getStructuringElement(MORPH_RECT, Size(11, 11));
morphologyEx(morphologyImg, morphologyImg, MORPH_OPEN, kernel);
// 第三步:轮廓查找,根据面积、横纵比进行筛选
// 查找轮廓
vector<vector<Point>> contours;
vector<Vec4i>hireachy;
findContours(morphologyImg, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE);
Mat contoursImg = Mat::zeros(morphologyImg.size(),CV_8UC3);
Rect dstRect;
for (int i = 0; i < contours.size(); ++i)
{
// 检查面积去除面积小的轮廓
float area = contourArea(contours[i]);
if (area < 400)
continue;
// 检测轮廓矩形,估算横纵比,去除横纵比较大的轮廓
Rect rect = boundingRect(contours[i]);
float ratio = float(rect.height) / float(rect.width);
if (!(ratio<1.2 && ratio>0.8))
continue;
dstRect = rect;
drawContours(contoursImg, contours, i, Scalar(0, 0, 255), 2, 8, Mat(), 0);
cout << "circle Area is: " << area << endl
<< "circle length is: " << arcLength(contours[i], true)
<< "radius length is: " << arcLength(contours[i], true) / 2 * 3.141592653;
}
//第四步:感兴趣区域提取保留圆
Mat roiImg = sorImg(dstRect);
Mat dstImg(sorImg.size(), sorImg.type(),Scalar(255,255,255));
Mat dstRoi = dstImg(dstRect);
dstRoi &= roiImg;
imshow("Dstimg", dstImg);
waitKey();
return 0;
}
效果图:
3.4 关键API
findContours:查找轮廓。
contourArea:计算轮廓的面积。
boundingRect:计算轮廓的垂直边界最小矩形。
3.5 总结
利用轮廓查找,结合针对的轮廓的一些变换,如矩形变换、周长变换,可以达到去除并查找某些特定形状的需求。