思维导图

图像轮廓与图像分割修复

1.查找绘制轮廓

// 用Canny算子检测边缘
Canny( g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3 );

// 寻找轮廓
findContours( g_cannyMat_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );

// 绘出轮廓
Mat drawing = Mat::zeros( g_cannyMat_output.size(), CV_8UC3 );
for( int i = 0; i< g_vContours.size(); i++ )
{
	Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );//任意值
	drawContours( drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point() );
}

2.寻找凸包

// 寻找轮廓
findContours( g_thresholdImage_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );

// 遍历每个轮廓,寻找其凸包
vector<vector<Point> >hull( g_vContours.size() );
for( unsigned int i = 0; i < g_vContours.size(); i++ )
{  
	convexHull( Mat(g_vContours[i]), hull[i], false );
}

// 绘出轮廓及其凸包
Mat drawing = Mat::zeros( g_thresholdImage_output.size(), CV_8UC3 );
for(unsigned  int i = 0; i< g_vContours.size(); i++ )
{
	Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );
	drawContours( drawing, g_vContours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
	drawContours( drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
}

3.多边形包围轮廓

// 使用Threshold检测边缘
threshold( g_grayImage, threshold_output, g_nThresh, 255, THRESH_BINARY );

// 找出轮廓
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );

// 多边形逼近轮廓 + 获取矩形和圆形边界框
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
vector<Point2f>center( contours.size() );
vector<float>radius( contours.size() );

//一个循环,遍历所有部分,进行本程序最核心的操作
for( unsigned int i = 0; i < contours.size(); i++ )
{ 
	approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );//用指定精度逼近多边形曲线 
	boundRect[i] = boundingRect( Mat(contours_poly[i]) );//计算点集的最外面(up-right)矩形边界
	minEnclosingCircle( contours_poly[i], center[i], radius[i] );//对给定的 2D点集,寻找最小面积的包围圆形 
}

// 绘制多边形轮廓 + 包围的矩形框 + 圆形框
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int unsigned i = 0; i<contours.size( ); i++ )
{
	Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );//随机设置颜色
	drawContours( drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point() );//绘制轮廓
	rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );//绘制矩形
	circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );//绘制圆
}

4.图像的矩

// 使用Canndy检测边缘
Canny( g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3 );

// 找到轮廓
findContours( g_cannyMat_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );

// 计算矩
vector<Moments> mu(g_vContours.size() );
for(unsigned int i = 0; i < g_vContours.size(); i++ )
{ mu[i] = moments( g_vContours[i], false ); }

//  计算中心矩
vector<Point2f> mc( g_vContours.size() );
for( unsigned int i = 0; i < g_vContours.size(); i++ )
{ mc[i] = Point2f( static_cast<float>(mu[i].m10/mu[i].m00), static_cast<float>(mu[i].m01/mu[i].m00 )); }

// 绘制轮廓
Mat drawing = Mat::zeros( g_cannyMat_output.size(), CV_8UC3 );
for( unsigned int i = 0; i< g_vContours.size(); i++ )
{
	Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );//随机生成颜色值
	drawContours( drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point() );//绘制外层和内层轮廓
	circle( drawing, mc[i], 4, color, -1, 8, 0 );;//绘制圆
}

5.分水岭算法

//定义一些参数
int i, j, compCount = 0;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;

//寻找轮廓
findContours(g_maskImage, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);

//轮廓为空时的处理
if( contours.empty() )
	continue;

//拷贝掩膜
Mat maskImage(g_maskImage.size(), CV_32S);
maskImage = Scalar::all(0);

//循环绘制出轮廓
for( int index = 0; index >= 0; index = hierarchy[index][0], compCount++ )
	drawContours(maskImage, contours, index, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX);

//compCount为零时的处理
if( compCount == 0 )
	continue;

//生成随机颜色
vector<Vec3b> colorTab;
for( i = 0; i < compCount; i++ )
{
	int b = theRNG().uniform(0, 255);
	int g = theRNG().uniform(0, 255);
	int r = theRNG().uniform(0, 255);

	colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}

//计算处理时间并输出到窗口中
double dTime = (double)getTickCount();
watershed( srcImage, maskImage );
dTime = (double)getTickCount() - dTime;
printf( "\t处理时间 = %gms\n", dTime*1000./getTickFrequency() );

//双层循环,将分水岭图像遍历存入watershedImage中
Mat watershedImage(maskImage.size(), CV_8UC3);
for( i = 0; i < maskImage.rows; i++ )
	for( j = 0; j < maskImage.cols; j++ )
	{
		int index = maskImage.at<int>(i,j);
		if( index == -1 )
			watershedImage.at<Vec3b>(i,j) = Vec3b(255,255,255);
		else if( index <= 0 || index > compCount )
			watershedImage.at<Vec3b>(i,j) = Vec3b(0,0,0);
		else
			watershedImage.at<Vec3b>(i,j) = colorTab[index - 1];
	}

	//混合灰度图和分水岭效果图并显示最终的窗口
	watershedImage = watershedImage*0.5 + grayImage*0.5;
	imshow( WINDOW_NAME2, watershedImage );

6.图像修补

inpaintMask = Mat::zeros(srcImage1.size(), CV_8U);

参考书籍《OpenCV3编程入门》