轮廓查找、图像矩、多边形测试、图像分水岭
- 1. 银行卡轮廓查找与绘制
- 2. [图像矩,多边形测试](http:///opencvdoc/2.3.2/html/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.html#point-polygon-test)
- 3. 图像分水岭
1. 银行卡轮廓查找与绘制
使用到的api
/*
参数说明:
输入图像image必须为一个2值单通道图像
contours参数为检测的轮廓数组,每一个轮廓用一个point类型的vector表示
hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],
分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
mode表示轮廓的检索模式
CV_RETR_EXTERNAL 表示只检测外轮廓
CV_RETR_LIST 检测的轮廓不建立等级关系
CV_RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
CV_RETR_TREE 建立一个等级树结构的轮廓。具体参考contours.c这个demo
method为轮廓的近似办法
CV_CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
CV_CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法
offset表示代表轮廓点的偏移量,可以设置为任意值。对ROI图像中找出的轮廓,并要在整个图像中进行分析时,这个参数还是很有用的。
*/
CV_EXPORTS_W void findContours( InputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset = Point());
// 查找轮廓
CV_EXPORTS void findContours( InputArray image, OutputArrayOfArrays contours,
int mode, int method, Point offset = Point());
// 获取可以包围轮廓的外层的矩形
CV_EXPORTS_W Rect boundingRect( InputArray array );
// 绘制轮廓
CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours,
int contourIdx, const Scalar& color,
int thickness = 1, int lineType = LINE_8,
InputArray hierarchy = noArray(),
int maxLevel = INT_MAX, Point offset = Point() );
以下是银行卡的轮廓查找与绘制
int main(){
Mat src = imread("E:/card.jpg");
if (!src.data){
cout << "read error" << endl;
return -1;
}
imshow("src", src);
// 梯度和二值化
Mat binary;
Canny(src,binary,50,150);
imshow("binary", binary);
//findContours(InputArray image, OutputArrayOfArrays contours,
// int mode, int method, Point offset = Point())
vector<vector<Point>> contours;
findContours(binary,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
Mat contours_mat = Mat::zeros(src.size(),CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
// 画轮廓
// boundingRect 获取可以包围轮廓的外层的矩形
Rect rect = boundingRect(contours[i]);
if (rect.width > src.cols / 2 && rect.height > src.rows / 2){
// 画轮廓
drawContours(contours_mat,contours,i,Scalar(0,0,255),1);
rectangle(contours_mat, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height), Scalar(255, 255, 255), 2);
break;
}
}
imshow("contours_mat", contours_mat);
waitKey(0);
return 0;
}
2. 图像矩,多边形测试
使用到的api
// measureDist: 为`true`的情况下, `<0:在外面,>0:在里面,==0:在轮廓上`。
// 为`false`的情况,`-1:在外面,1:在里面,0:在轮廓上`
double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist )
图像矩的一个小例子
int main(){
/// 创建一个图形
const int r = 100;
Mat src = Mat::zeros(Size(4 * r, 4 * r), CV_8UC1);
/// 绘制一系列点创建一个轮廓:
vector<Point2f> vert(6);
vert[0] = Point(1.5*r, 1.34*r);
vert[1] = Point(1 * r, 2 * r);
vert[2] = Point(1.5*r, 2.866*r);
vert[3] = Point(2.5*r, 2.866*r);
vert[4] = Point(3 * r, 2 * r);
vert[5] = Point(2.5*r, 1.34*r);
/// 在src内部绘制
for (int j = 0; j < 6; j++)
{
line(src, vert[j], vert[(j + 1) % 6], Scalar(255), 3, 8);
}
imshow("src", src);
// 查找轮廓
vector<vector<Point>> contours;
findContours(src,contours,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);
// 计算到轮廓的距离
Mat raw_dist(src.size(),CV_32FC1);
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
raw_dist.at<float>(row, col) = pointPolygonTest(contours[0], Point2f(col, row), true);
}
}
// 优化
Mat drawing = Mat::zeros(src.size(),CV_8UC3);
for (int row = 0; row < src.rows; row++)
{
for (int col = 0; col < src.cols; col++)
{
// raw_dist.at<float>(row, col) = pointPolygonTest(contours[0], Point2f(col, row), true);
float value = raw_dist.at<float>(row, col);
if (value < 0){ // 外面
drawing.at<Vec3b>(row, col)[0] = saturate_cast<int>((int)abs(value));
}
else if (value > 0){ // 里面
drawing.at<Vec3b>(row, col)[2] = saturate_cast<int>((int)value);
}
else{// 矩形上面
drawing.at<Vec3b>(row, col)[0] = 255;
drawing.at<Vec3b>(row, col)[1] = 255;
drawing.at<Vec3b>(row, col)[2] = 255;
}
}
}
imshow("drawing", drawing);
waitKey(0);
return 0;
}
3. 图像分水岭
使用到的api
CV_EXPORTS_W void watershed( InputArray image, InputOutputArray markers );