zoukankan      html  css  js  c++  java
  • 图像的连通域检测的堆栈算法

        图像的连通域寻找在直觉上可使用递归的方法,进而可以使用堆栈数据结构进行改进。本文描述了一个图像寻找连通域的堆栈方法,四连通域和八联通域的选择可以使用一个参数来确定。

         以下是代码:

    //根据种子点寻找8连通域//使用两遍扫描//查找所有的连通域
    //划分为前景、背景、和无关位置
    //一个点 也必须当做连通域
    bool CD2DetectInPic::searchConBy8Con(
    	const cv::Mat& _binImg, cv::Mat& _lableImg,
    	float valueForeB,float valueForeUp, int GlintSizeLowerBound, int GlintSizeUpperBound,
    	std::vector<std::vector<cv::Point > > &foreAreas)
    {  
    	// connected component analysis (8-component)  
    	// use seed filling algorithm  
    	// 1. begin with a foreground pixel and push its foreground neighbors into a stack;  
    	// 2. pop the top pixel on the stack and label it with the same label until the stack is empty  
    
    	if (_binImg.channels()>1)
    	{
    		cv::cvtColor(_binImg,_lableImg,cv::COLOR_BGR2GRAY);
    	}
    
    	foreAreas.resize(0);
    
    	////寻找4连通域
            //int xNum[4] = {1,0,-1,0};  
         //int yNum[4] = {0,1,0,-1};  
     
    	//寻找8连通域
    	int xNum[8] = {1,1,0,-1,-1,-1,0,1};  
    	int yNum[8] = {0,1,1,1,0,-1,-1,-1};  
    
    
    	//一遍扫描,得出前景和背景点,进行标记
    	//背景点标记为0,前景点标记为1,其他标记为255
    	//cv::imshow("",_lableImg);//cv::waitKey(0);
    
    	IplImage imageLabel = _lableImg;
    	for (int i=0;i< imageLabel.height;++i)
    	{
    		char* pI = (char*)imageLabel.imageData + i * imageLabel.widthStep;
    		for (int j=0;j<imageLabel.width;++j )
    		{
    			if ( *pI >=valueForeB &&*pI <=valueForeUp)//避开单一值失误!
    			{
    				*pI =   1;
    			} 
    			else
    			{
    				*pI = 255;
    			}
    			++pI;
    		}
    	}
    
    
    	//对label图像进行遍历,寻找连通域
    	//对Mark矩阵,进行修改,不修改标识矩阵
    	cv::Mat imageMark(&imageLabel);
    	cv::Mat imageMarkRe = imageMark.clone();
    
    #if SHOW_TEMP
    	cv::imshow("imageMarkRe",imageMarkRe);//cv::waitKey(0);
    #endif
    
    	std::stack<std::pair<int,int> > neighborPixels;  
    	//对图片每个点进行寻找连通域,必须遍历
    	for (int m =0; m<imageMark.rows; ++m )
    	{
    		for (int n=0; n< imageMark.cols; ++n)
    		{
    			//亮点,使用数组取代条件查找。。。  
    			CvPoint seedT; 
    			if (imageMarkRe.at<uchar>(m,n) <120 )//遍历前景
    			{
    				std::vector<cv::Point >  foreArea;
    
    				int x = seedT.x = n;  //遍历当前点
    				int y = seedT.y = m;  
      
    				neighborPixels.push(std::pair<int,int>(x,y) ) ;   
    				
    				cv::Point P(x,y);  
    				foreArea.push_back(P);//要把第一个点当做连通域
    
    				while (!neighborPixels.empty())  
    				{  
    					// get the top pixel on the stack and label it with the same label  
    					std::pair<int,int> curPixel = neighborPixels.top() ; 
    					int curX = seedT.x = curPixel.first  ;  
    					int curY = seedT.y = curPixel.second ;  
    
    					neighborPixels.pop(); //标记取出,同时标记已遍历
    					imageMarkRe.at<uchar>(curY,curX) = 255;//标记为已遍历
    
    					//寻找前景8连通域
    					//if (imageMark.at<uchar>(seedT.y,seedT.x) <120 && imageMarkRe.at<uchar>(seedT.y,seedT.x) <120)
    					{
    						for(int k=0 ;k<8 ;k++)  //四联通要修改为4
    						{  
    							int yy = curY + yNum[k];  
    							int xx = curX + xNum[k];  
    							if (yy <0 || xx <0 ||yy >= imageMarkRe.rows || xx >= imageMarkRe.cols )
    							{
    								continue;
    							} 
    							else
    							{
    								if (imageMark.at<uchar>(yy,xx) <120  && imageMarkRe.at<uchar>(yy,xx) <120 )
    								{
    									cv::Point P(xx,yy);
    									std::pair<int,int>   seedCur;  
    									seedCur.first  =seedT.x = xx;  
    									seedCur.second =seedT.y = yy;  
    
    									foreArea.push_back(P);
    									neighborPixels.push(seedCur);
    
    									imageMarkRe.at<uchar>(yy,xx) = 255;//标记为已遍历
    								} 
    							}
    
    						}
    					}
    
    				}
    				if (foreArea.size()>=GlintSizeLowerBound && foreArea.size()<=GlintSizeUpperBound)
    				{
    					foreAreas.push_back(foreArea);
    				}
    				
    			}
    
    		}
    	}
    
    	return true;
    }

    二值化图像的结果:

       


    除去小的边缘的效果:

        

  • 相关阅读:
    数学工具WZgrapher
    零线和地线的区别,示波器如何测量市电?
    使用直流稳压电源时的注意事项!
    中文全角和半角输入有什么区别?
    ThinkingRock:使用方法
    2014记首
    如何使用Excel绘制甘特图
    AStyle代码格式工具在source insight中的使用
    STM32F103系列命名规则
    上市公司行情查询站点
  • 原文地址:https://www.cnblogs.com/wishchin/p/9200066.html
Copyright © 2011-2022 走看看