opencv findContour函数

此文主要提及关于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;
}






  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值