利用opencv逼近二值图像的边界点,并过滤不需要的边界,达到寻边效果。(转载请说明出处)

二值化图像;

利用黑白像素值求差,得到边缘点;

过滤边缘点找到合适区域;

利用cvFitLine2D拟合线。

 

做的比较粗糙,搜寻时间在10ms左右,希望有研究opencv的朋友斧正。

效果预览:

 

void CvProcess::FindLine(
						 IplImage* orgImg ,//原始图像
						 IplImage*runImg,//显示用图像
						 CvRect rec,//roi
						 int thredValue,//二值化阈值
						 int lineAccuracy,//搜索精度
						 int SearchDirection,//搜索方向
						 int EdgePolarity)//搜索方式 黑到白 白到黑

{	
	cvCopy(orgImg,runImg);//原始图像拷贝到显示图像用于显示
	IplImage* thrdImg = cvCreateImage(//创建一个单通道二值图像用于各种处理
		cvSize(orgImg->width,orgImg->height), 
		IPL_DEPTH_8U, 
		1);	
	//将原始图像转换为单通道灰度图像
	cvCvtColor(runImg,thrdImg,CV_BGR2GRAY);
	//二值化处理
	cvThreshold(			
		thrdImg,
		thrdImg,
		thredValue,
		255,
		CV_THRESH_BINARY);

	// 	cvNamedWindow("");
	// 	cvShowImage("",thrdImg);	
	if(rec.width>0&&rec.width<IMAGE_WIDTH&&rec.height>0&&rec.width<IMAGE_HEIGHT)//判断是否有适合的ROI区域
	{   //设置ROI
		cvSetImageROI(runImg,rec);
		cvSetImageROI(thrdImg,rec);		

		//搜索边界
		CvPoint2D32f *EdgePoint2D = //用于存储搜索到的所有边界点
			(CvPoint2D32f *)malloc((IMAGE_HEIGHT*IMAGE_WIDTH) * sizeof(CvPoint2D32f));
		CvPoint2D32f *RelEdgePoint2D =//用于存储搜索到的正确的点
			(CvPoint2D32f *)malloc((IMAGE_HEIGHT*IMAGE_WIDTH) * sizeof(CvPoint2D32f));
		int EdgePoint2DCount=0;//点计数
		int RelEdgePoint2DCount=0;	//真实点计数	
		float *line = new float[4];	//用于画逼近线
		byte ftData=0,secData=0;	//搜索边界点所需资源
		//得到ROI区域内的搜索线
		std::vector<CLine> searchlines = GetRecLines(rec,lineAccuracy,SearchDirection);
		switch(SearchDirection)//搜索方向
		{
		case TB :	
			//上到下纵向搜索
			for (int i=0;i<thrdImg->roi->width;i++)
			{
				for (int j=0;j<thrdImg->roi->height-1;j++)
				{   //上下搜索所有的差值大于200的点
					ftData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i);//利用宏直接得到结果		
					//ftData=(thrdImg->imageData + i * thrdImg->widthStep)[j];//注意这里是 宽度用的是 widthStep 而不是 width
					secData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j+1,thrdImg->roi->xOffset+i);		
					switch(EdgePolarity)
					{
					case B2W:
						if(secData-ftData>200)//黑到白
						{
							for(int n=0;n<searchlines.size();n++)//搜索在搜索线上的点
							{
								if (searchlines[n].PTS.x==i&&searchlines[n].PTS.y<j
									&&searchlines[n].PTE.y>j)
								{
									EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); 	
								}
							}									
							if (EdgePoint2DCount>0)//大于2点时比较
							{							
								bool realPoint=TRUE;
								//删除X坐标相同的纵向点,减少逼近时误判几率
								for (int m=1;m<=EdgePoint2DCount;m++)
								{   
									if(EdgePoint2D[EdgePoint2DCount].x == EdgePoint2D[EdgePoint2DCount-m].x)
									{
										realPoint=FALSE;                           
									}
								}  							
								if(realPoint)//得到非重复点并画出
								{							
									RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);
									cvCircle(runImg,cvPoint(i,j),
										1,CV_RGB(255,0,0),2, CV_AA,0);	//画点
									RelEdgePoint2DCount++;														
								}
							}   
							EdgePoint2DCount++;
						}
						break;

					case W2B:
						if(ftData-secData>200)//白到黑
						{
							for(int n=0;n<searchlines.size();n++)//搜索在搜索线上的点
							{
								if (searchlines[n].PTS.x==i&&searchlines[n].PTS.y<j
									&&searchlines[n].PTE.y>j)
								{
									EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); 	
								}
							}									
							if (EdgePoint2DCount>0)//大于2点时比较
							{							
								bool realPoint=TRUE;
								//删除X坐标相同的纵向点,减少逼近时误判几率
								for (int m=1;m<=EdgePoint2DCount;m++)
								{   
									if(EdgePoint2D[EdgePoint2DCount].x == EdgePoint2D[EdgePoint2DCount-m].x)
									{
										realPoint=FALSE;                           
									}
								}  							
								if(realPoint)//得到非重复点并画出
								{							
									RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);
									cvCircle(runImg,cvPoint(i,j),
										1,CV_RGB(255,0,0),2, CV_AA,0);	//画点
									RelEdgePoint2DCount++;														
								}
							}   
							EdgePoint2DCount++;
						}
						break;
					}
				}
			} 							
			if(RelEdgePoint2DCount>2)//当找到的点大于2时在搜寻逼近线
			{	//找出逼近线					
				cvFitLine2D(RelEdgePoint2D,RelEdgePoint2DCount, CV_DIST_L1,NULL,0.01,0.01,line);  	
				CvPoint FirstPoint;//起点
				CvPoint LastPoint;//终点
				FirstPoint.x=int (line[2]-1000*line[0]);
				FirstPoint.y=int (line[3]-1000*line[1]);
				LastPoint.x=int (line[2]+1000*line[0]);
				LastPoint.y=int (line[3]+1000*line[1]);
				cvLine( runImg, FirstPoint, LastPoint, CV_RGB(255,0,0), 1, CV_AA);//画出逼近线		
			}
			break;

		case LR :
			//左到右横向搜索
			for (int j=0;j<thrdImg->roi->height;j++)		
			{
				for (int i=0;i<thrdImg->roi->width-1;i++)
				{
					ftData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i);//利用宏直接得到结果		
					//ftData=(thrdImg->imageData + i * thrdImg->widthStep)[j];//注意这里是 宽度用的是 widthStep 而不是 width
					secData=CV_IMAGE_ELEM(thrdImg,uchar,thrdImg->roi->yOffset+j,thrdImg->roi->xOffset+i+1);		
					switch(EdgePolarity)
					{
					case B2W:
						if(secData-ftData>200)//黑到白
						{
							for(int n=0;n<searchlines.size();n++)//point in searchlines
							{
								if (searchlines[n].PTS.y==j&&searchlines[n].PTS.x<i
									&&searchlines[n].PTE.x>i)
								{
									EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); 	
								}
							}									
							if (EdgePoint2DCount>0)//大于2点时比较
							{							
								bool realPoint=TRUE;
								for (int m=1;m<=EdgePoint2DCount;m++)//删除y坐标相同的横向点
								{   
									if(EdgePoint2D[EdgePoint2DCount].y == EdgePoint2D[EdgePoint2DCount-m].y)
									{
										realPoint=FALSE;                           
									}
								}  							
								if(realPoint)//得到非重复点并画出
								{							
									RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);
									cvCircle(runImg,cvPoint(i,j),
										1,CV_RGB(255,0,0),2, CV_AA,0);	//画点
									RelEdgePoint2DCount++;														
								}
							}   
							EdgePoint2DCount++;
						}
						break;

					case W2B:
						if(ftData-secData>200)//白到黑
						{
							for(int n=0;n<searchlines.size();n++)//找出在搜索线上的点
							{
								if (searchlines[n].PTS.y==j&&searchlines[n].PTS.x<i
									&&searchlines[n].PTE.x>i)
								{
									EdgePoint2D[EdgePoint2DCount]=cvPoint2D32f(i,j); 	
								}
							}									
							if (EdgePoint2DCount>0)//大于2点时比较
							{							
								bool realPoint=TRUE;
								for (int m=1;m<=EdgePoint2DCount;m++)//删除X坐标相同的纵向点
								{   
									if(EdgePoint2D[EdgePoint2DCount].y == EdgePoint2D[EdgePoint2DCount-m].y)
									{
										realPoint=FALSE;                           
									}
								}  							
								if(realPoint)//得到非重复点并画出
								{							
									RelEdgePoint2D[RelEdgePoint2DCount]=cvPoint2D32f(i,j);
									cvCircle(runImg,cvPoint(i,j),
										1,CV_RGB(255,0,0),2, CV_AA,0);	//draw points
									RelEdgePoint2DCount++;														
								}
							}   
							EdgePoint2DCount++;
						}
						break;
					}
				}
			} 
			//搜索逼近线							
			if(RelEdgePoint2DCount>2)
			{					
				cvFitLine2D(RelEdgePoint2D,RelEdgePoint2DCount, CV_DIST_L1,NULL,0.01,0.01,line);  	
				CvPoint FirstPoint;//起点
				CvPoint LastPoint;//终点
				FirstPoint.x=int (line[2]-1000*line[0]);
				FirstPoint.y=int (line[3]-1000*line[1]);
				LastPoint.x=int (line[2]+1000*line[0]);
				LastPoint.y=int (line[3]+1000*line[1]);
				cvLine( runImg, FirstPoint, LastPoint, CV_RGB(255,0,0), 1, CV_AA);//画出逼近线			
			}
			break;	
		}
		//释放资源
		free(EdgePoint2D); 		
		free(RelEdgePoint2D);
		delete[] line;
		searchlines.clear();
		cvResetImageROI(runImg);	
		cvResetImageROI(thrdImg);
		DrawRecLines(runImg,rec,lineAccuracy,SearchDirection);
	}

	//释放资源
	cvReleaseImage(&thrdImg);
}

//画ROI时候 连带画出搜索线
void CvProcess::DrawRecLines(IplImage* runImg,CvRect rec,int lineAccuracy,int SearchDirection)
{
	cvRectangleR(runImg,rec,CV_RGB(0,255,0),1, CV_AA,0);
	CvPoint RecPS=cvPoint(rec.x,rec.y),
		RecPE=cvPoint(rec.x+rec.width,rec.y+rec.height);
	switch(SearchDirection)
	{
	case TB :
		for (int i=1;i<lineAccuracy;i++)
		{
			CvPoint Ps=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPS.y);
			CvPoint Pe=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPE.y);	
			cvLine(runImg,Ps,Pe,CV_RGB(0,255,255),1, CV_AA,0);
		}      
		break;
	case LR :
		for (int i=1;i<lineAccuracy;i++)
		{
			CvPoint Ps=cvPoint(RecPS.x,((double)rec.height/lineAccuracy)*i+RecPS.y);
			CvPoint Pe=cvPoint(RecPE.x,((double)rec.height/lineAccuracy)*i+RecPS.y);
			cvLine(runImg,Ps,Pe,CV_RGB(0,255,255),1, CV_AA,0);
		}      
		break;
	}

}

//得到ROI内部搜索线
std::vector<CLine> CvProcess::GetRecLines(CvRect rec,int lineAccuracy,int SearchDirection)
{
	std::vector<CLine> SearchLines;
	CLine line;
	rec.x=0;//坐标转换值ROI区域
	rec.y=0;
	CvPoint RecPS=cvPoint(rec.x,rec.y),
		RecPE=cvPoint(rec.x+rec.width,rec.y+rec.height);
	switch(SearchDirection)
	{
	case TB :
		for (int i=1;i<lineAccuracy;i++)
		{
			line.PTS=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPS.y);
			line.PTE=cvPoint(((double)rec.width/lineAccuracy)*i+RecPS.x,RecPE.y);	
			SearchLines.push_back(line);		
		}     
		break;
	case LR :
		for (int i=1;i<lineAccuracy;i++)
		{
			line.PTS=cvPoint(RecPS.x,((double)rec.height/lineAccuracy)*i+RecPS.y);
			line.PTE=cvPoint(RecPE.x,((double)rec.height/lineAccuracy)*i+RecPS.y);	
			SearchLines.push_back(line);		
		}     
		break;	
	}

	return SearchLines;




 

你可能感兴趣的:(image,null,delete,存储,float,byte)