此文主要提及关于opencv的findContour函数的一些使用心得,还有编写的一个findContour函数,主要是针对双边界的,单边界也有提及。
findContours(Mask,
contours,// 轮廓点
//CV_RETR_EXTERNAL,// 只检测外轮廓
//CV_RETR_CCOMP,
/*建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。
如果内孔内还有一个连通物体,这个物体的边界也在顶层。*/
CV_RETR_LIST, //检测的轮廓不建立等级关系
CV_CHAIN_APPROX_NONE);// 提取轮廓所有点
Mat ma(img.rows, img.cols, CV_8UC1,Scalar(0));
//Scalar color( rand()&255, rand()&255, rand()&255 );//彩色图像时第四个参数的定义
drawContours(ma, contours, -1, Scalar::all(255), 1);
说明:
1)Mask为输入Mat,必须为单通道二值图像(0,255);
2)contours必须为vector<vector<Point>>类型;
3)CV_RETR:CV_RETR_EXTERNAL只能检测外轮廓,若是里面还有轮廓则检测不出;
4)VC10,VC12版本好像基本会确定一个图片的边界轮廓,即图片四条边界构成的四边形轮廓,这样注意3)参数会出现没法提取轮廓的情况。
附一个函数:
/**************************************************************************/
/* img为只有两个值的图像,假设为a,b, */
/* contours存储边界, */
/* simpleContour=1,单条轮廓;simpleContour=0,双条轮廓,默认为1 */
/*单条轮廓做到纯粹单条略有bug ,有兴趣的可以修改一下 */
/*返回0,输入img错误,返回1,函数正确执行 */
/**************************************************************************/
int SFindContour(Mat img, vector<vector<Point>>& contours,bool simpleContour=1);
bool isBoundary(int i0, int j0, Mat img);
int iterContour(int i0, int j0, Mat img, vector<Point>& contourLine, vector<vector<bool>>& dealFlag, bool simpleContour);
int SFindContour(Mat img1, vector<vector<Point>>& contours, bool simpleContour)
{
contours.clear();
if (img1.channels() > 1)
{
return 0;
}
int jk[8] = { -1,0,1,-1,1,-1,0,1 };
int ik[8] = { -1,-1,-1,0,0,1,1,1 };
Mat img;
if(img1.step.buf[1]==1)
{
img = img1.clone();
}
else
img1.convertTo(img, CV_8UC1, 1, 0);
vector<vector<bool>> dealFlag(img.rows, vector<bool>(img.cols, 0));
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
for (int k = 0; k < 8; k++)
{
int ni = i + ik[k];
int nj = j + jk[k];
if (ni >= 0 && ni < img.rows&&nj >= 0 && nj < img.cols)
{
if (img.at<uchar>(i, j) != img.at<uchar>(ni, nj) && dealFlag[i][j] != 1)
{
if (simpleContour)
{
if (dealFlag[ni][nj] != 1)
{
vector<Point> line1;
iterContour(i, j, img, line1, dealFlag,simpleContour);
contours.push_back(line1);
line1.clear();
}
}
else
{
vector<Point> line1;
iterContour(i, j, img, line1, dealFlag,simpleContour);
contours.push_back(line1);
line1.clear();
}
}
}
}
}
}
img.release();
dealFlag.clear();
return 1;
}
bool isBoundary(int i0, int j0, Mat img)
{
int jk[8] = { -1,0,1,-1,1,-1,0,1 };
int ik[8] = { -1,-1,-1,0,0,1,1,1 };
for (int i = 0; i < 8; i++)
{
int ni = i0 + ik[i];
int nj = j0 + jk[i];
if (ni >= 0 && ni < img.rows&&nj >= 0 && nj < img.cols)
{
if (img.at<uchar>(i0, j0) != img.at<uchar>(ni, nj))
{
return 1;
}
}
}
return 0;
}
int iterContour(int i0, int j0, Mat img, vector<Point>& contourLine, vector<vector<bool>>& dealFlag, bool simpleContour)
{
int jk[8] = { -1,0,1,-1,1,-1,0,1 };
int ik[8] = { -1,-1,-1,0,0,1,1,1 };
contourLine.push_back(Point(i0, j0));
dealFlag[i0][j0] = 1;
//if (simpleContour)
//{
// for (int i = 0; i < 8; i++)
// {
// int ni = i0 + ik[i];
// int nj = j0 + jk[i];
// if (ni >= 0 && ni < img.rows&&nj >= 0 && nj < img.cols)
// {
// if (img.at<uchar>(ni, nj) != img.at<uchar>(i0, j0))
// dealFlag[ni][nj] = 1;
// }
// }
//}
for (int i = 0; i < 8; i++)
{
int ni = i0 + ik[i];
int nj = j0 + jk[i];
if (ni >= 0 && ni < img.rows&&nj >= 0 && nj < img.cols)
{
if (isBoundary(ni, nj, img) && img.at<uchar>(i0, j0) == img.at<uchar>(ni, nj) && dealFlag[ni][nj] != 1)
{
if (simpleContour)
{
int cnt=0;
for (int i = 0; i < 8; i++)
{
int nni = ni + ik[i];
int nnj = nj + jk[i];
if (nni >= 0 && nni < img.rows&&nnj >= 0 && nnj < img.cols)
{
if (img.at<uchar>(ni, nj) != img.at<uchar>(nni, nnj)&&dealFlag[nni][nnj]==1)
cnt++;
}
}
if (cnt < 2)
iterContour(ni, nj, img, contourLine, dealFlag, simpleContour);
}
else
{
iterContour(ni, nj, img, contourLine, dealFlag, simpleContour);
}
}
}
}
return 1;
}