OpenCV 基于种子填充的连续域分析及选取程序

regionConnectAnalysis 是通过种子填充方法来寻找连通区域的,这种方法相比与two-pass的方法较慢。
/*! @function
*******************************************************************************
<PRE>
Function Name   : regionConnectAnalysis
-------------------------------------------------------------------------------
Function        : Region connected analysis using seed filling method
-------------------------------------------------------------------------------
Parameters      : < cv::Mat& binaryImage, cv::Mat& labelImage,int RegionNum >
[IN] param 1    : binaryImage     target image
[OUT] param 2   : labelImage	  Image combine by label
[IN] param 3    : RegionNum		  Region's number

Return                   : bool

Reference:https://blog.csdn.net/icvpr/article/details/10259577

<PRE>
******************************************************************************/
int regionConnectAnalysis(cv::Mat& binaryImage, cv::Mat& labelImage)
{
	// check input image
	if (binaryImage.empty() || binaryImage.type() != CV_8UC1)
		return false;

	// clear output image
	labelImage.release();
	binaryImage.convertTo(labelImage, CV_32SC1);

	// 8-neigbor Mat construction
	int DIR[8][2]={ { -1, -1 }, { -1, 0 }, { -1, 1 },
				  {0, -1}, { 0, 1 } ,
				  {1, -1}, { 1, 0 }, { 1, 1 } };
	

	// seed filling method
	int label = 1;
	cv::Point tmpPoint;

	int rows = binaryImage.rows;
	int cols = binaryImage.cols;
	//cv::Point tmpPoint = cv::Point(0, 0);


	for (int i = 0; i < rows; i++){
		for (int j = 0; j < cols; j++){
			
			if (labelImage.at<int>(i,j) == 1)
			{
				std::vector < cv::Point > neigborPixels;
				neigborPixels.push_back(cv::Point(j, i));
				++label;
				while (!neigborPixels.empty()){
					cv::Point seedPoint;
					seedPoint = neigborPixels.back();
					neigborPixels.pop_back();
					labelImage.at<int>(seedPoint) = label;

					// push the 8-neighbor
					for (int k = 0; k < 8; ++k){
						tmpPoint.x = seedPoint.x + DIR[k][0];
						tmpPoint.y = seedPoint.y + DIR[k][1];
						if (tmpPoint.x<0 || tmpPoint.y<0 || tmpPoint.x>(cols - 1) || tmpPoint.y>(rows - 1))
							continue;
						int tmpVal = labelImage.at<int>(tmpPoint);
						if (tmpVal == 1)
							neigborPixels.push_back(tmpPoint);

					}
				}
			}
		}
	}
	return label - 1;
}

当得出labelImage后,可以通过索引值找出感兴趣的区域,这里给出两种方法,一种是遍历Mat的每个像素,比较label ;另一个是通过建立灰度值为label的图像进行比较;

//遍历法
/*! @function
*******************************************************************************
<PRE>
Function Name   : selectRegion
-------------------------------------------------------------------------------
Function        : Select region from regions by label
-------------------------------------------------------------------------------
Parameters      : < cv::Mat& labelImage, cv::Mat& regionImage, int labelIndex >
[IN]  param 1    : labelImage      target image
[OUT] param 2    : regionImage	   interest region
[IN]  param 3    : labelIndex      label Index

Return          : bool
<PRE>
******************************************************************************/
bool selectRegion(cv::Mat& labelImage, cv::Mat& regionImage, int labelIndex)
{
	// check labelImage
	if (labelImage.empty() || labelImage.type() != CV_32SC1)
		return false;

	// clear regionImage
	regionImage.release();
	regionImage.create(labelImage.size(), CV_8UC1);

	// select
	int rows = labelImage.rows;
	int cols = labelImage.cols;
	cv::Point tmpPoint = cv::Point(0, 0);

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			tmpPoint = cv::Point(i, j);
			if (labelImage.at<int>(tmpPoint) == labelIndex)
				regionImage.at<uchar>(tmpPoint) = 255;
			else
				regionImage.at<uchar>(tmpPoint) = 0;
		}
	}
        return true
}
//Mat比较法
/*! @function
*******************************************************************************
<PRE>
Function Name   : selectRegionOptimize;
-------------------------------------------------------------------------------
Function        : Select region from regions by label
-------------------------------------------------------------------------------
Parameters      : < cv::Mat& labelImage, cv::Mat& regionImage, int labelIndex >
[IN]  param 1    : labelImage      target image
[OUT] param 2    : regionImage	   interest region
[IN]  param 3    : labelIndex      label Index

Return          : bool
<PRE>
******************************************************************************/
bool selectRegionOptimize(cv::Mat& labelImage, cv::Mat& regionImage, int labelIndex)
{
	// check labelImage
	if (labelImage.empty() || labelImage.type() != CV_32SC1)
		return false;

	// clear regionImage
	regionImage.release();
	regionImage.create(labelImage.size(), CV_8UC1);

	// find interest region
	cv::Mat tmp(labelImage.size(), CV_32SC1, cv::Scalar((double)labelIndex));
	regionImage = labelImage == tmp;

	return true;
}

分析这种方法的快慢

int main()
{
	Mat src = imread("D:/ImageProcessing  Images/DIP3E_Original_Images_CH09/Fig0916(a)(region-filling-reflections).tif");
	if (src.empty())
	{
		cout << "Empty image" << endl;
	}
	else
	{
		//imshow("orignal image", src);
	}
	
	// to gray image
	Mat gray, binaryImage;
	CVTL::RGB2GRAY(src, gray);

	cv::threshold(gray, binaryImage, 30, 1, cv::THRESH_BINARY);
	Mat labelImage, interestRegImage,ApiTmpImage,ApiRegImage;

	int regionNum = CVTL::regionConnectAnalysis(binaryImage, labelImage);
	
	double oldMethodStart = getTickCount();
	CVTL::selectRegion(labelImage, interestRegImage, 4);
	double oldMethodEnd = getTickCount();

	double newMethodStart = getTickCount();
	CVTL::selectRegionOptimize(labelImage, interestRegImage, 4);
	double newMethodEnd = getTickCount();

	double oldMethod = (oldMethodEnd - oldMethodStart) / getTickFrequency();
	double newMethod = (newMethodEnd - newMethodStart) / getTickFrequency();
	
	std::cout << "oldMethod :" << oldMethod << endl;
	std::cout << "newMethod :" << newMethod << endl;

	std::cout << regionNum << endl;
	imshow("interestRegImage", interestRegImage);

	waitKey(0);
	return 0;
}


原图如下


选取结果


两种方法用时:


可以看出第二种方法在速度上明显快于第一种。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值