1. 程式人生 > >利用opencv逼近二值影象的邊界點,並過濾不需要的邊界,達到尋邊效果。(轉載請說明出處)

利用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;

相關推薦

利用opencv逼近影象邊界過濾需要邊界達到效果轉載說明出處

二值化影象; 利用黑白畫素值求差,得到邊緣點; 過濾邊緣點找到合適區域; 利用cvFitLine2D擬合線。 做的比較粗糙,搜尋時間在10ms左右,希望有研究opencv的朋友斧正。 效果預覽: 、 void CvProcess::FindLine( Ip

OpenCV實現影象細化的演算法

        細化演算法通常和骨骼化、骨架化演算法是相同的意思,也就是thin演算法或者skeleton演算法。雖然很多影象處理的教材上不是這麼寫的,具體原因可以看這篇論文,Louisa Lam, Seong-Whan Lee, Ching Y. Suen,“Thinni

opencv實現影象的細化

opencv實現二值影象細化的演算法 細化演算法通常和骨骼化、骨架化演算法是相同的意思,也就是thin演算法或者skeleton演算法。雖然很多影象處理的教材上不是這麼寫的,具體原因可以看這篇論文,Louisa Lam, Seong-Whan Lee, Chin

利用PIL.ImageOps.invert實現影象黑白反轉

利用PIL.ImageOps.invert實現二值影象黑白反轉   import PIL.ImageOps from PIL import Image img = Image.open('D:\\Desktop\\計算機視覺\\image\\0.png') img =

OpenCV-影象連通域分析

通域分析對於影象處理後面涉及到模式識別的內容來說是基礎 連通區域(Connected Component)一般是指影象中具有相同畫素值且位置相鄰的前景畫素點組成的影象區域(Region,Blob)。連通區域分析(Connected Component Analysis,C

OpenCV學習筆記之針對影象的邊緣光滑處理突出部消除

處理程式碼分為兩部分,第一部分用於去除邊緣的突出部,第二部分用於邊緣光滑。具體如下所示 1.去除邊緣突出部 //去除二值影象邊緣的突出部 //uthreshold、vthreshold分別表示突出部的寬度閾值和高度閾值 //type代表突出部的顏色,0表示黑色,1代表白色

影象處理】利用種子填充法對影象進行連通域標記-計算目標中心位置方法2

種子填充法原理 大致演算法如下: 設二值化影象A中,畫素值為255的點是前景,為0的點是背景。A(x, y)為座標(x, y)處的畫素值,遍歷影象的每個畫素: 1、 如果畫素值不等於255,則繼續訪問下一個元素。 2、 如果畫素值為A(x, y) = 255,則新建一

opencv 刪除影象中面積較小的連通域

對於上圖的二值化影象,要去除左下角和右上角的噪點,方法:使用opencv去掉黑色面積較小的連通域。程式碼 CvSeq* contour = NULL; double minarea = 100.0; double tmparea = 0.0;

Ubuntu 14.04 下使用 OpenCV 圖片化處理

ubuntu14 install article all tail .net .com enc -o 參考: OpenCV - Ubuntu 14.04 64 bit 圖片二值化工具 Ubuntu 14.04 下使用 OpenCV 圖片二值化處理 TBD。Ubuntu

實現基於C語言的影象連通域標記演算法

實現基於C語言的二值影象連通域標記演算法 1 #include <stdio.h> 2 #include <stdarg.h> 3 #include <stddef.h> 4 #include <stdlib.h> 5 #includ

基於卷積神經網路特徵圖的影象分割

       目標檢測是當前大火的一個研究方向,FasterRCNN、Yolov3等一系列結構也都在多目標檢測的各種應用場景或者競賽中取得了很不錯的成績。但是想象一下,假設我們需要通過影象檢測某個產品上是否存在缺陷,或者通過衛星圖判斷某片海域是否有某公司的船隻

影象分析:影象連通域標記

一、前言 二值影象,顧名思義就是影象的亮度值只有兩個狀態:黑(0)和白(255)。二值影象在影象分析與識別中有著舉足輕重的地位,因為其模式簡單,對畫素在空間上的關係有著極強的表現力。在實際應用中,很多影象的分析最終都轉換為二值影象的分析,比如:醫學影象分析、前景檢測、字元識

影象的腐蝕膨脹原理附程式碼

程式碼: #include <iostream> #include<vector> #include<iomanip> using namespace std; #define picX 6 #define picY 6 type

利用opencv將多張影象做簡單的拼接

#include <iostream> #include <core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui

影象:B&W(黑白影象)、 Gray (灰度影象) 、單色影象//Color(彩色影象)

二值影象(binary image),即影象上的每一個畫素只有兩種可能的取值或灰度等級狀態,人們經常用黑白、B&W、單色影象表示二值影象。 B&W黑白影象: 只有黑色和白色,不存在過渡性的灰色,它一個畫素只需要一個二進位制位就能表示出來,即0表示

影象、灰度影象、彩色影象

二值影象 二值影象(Binary Image),按名字來理解只有兩個值,0和1,0代表黑,1代表白,或者說0表示背景,而1表示前景。其儲存也相對簡單,每個畫素只需要1Bit就可以完整儲存資訊。如果把每個畫素看成隨機變數,一共有N個畫素,那麼二值圖有2的N次方種變化,而8位灰度

SSE影象演算法優化系列十五:二值影象的Euclidean distance mapEDM)特徵圖計算及其優化 SSE影象演算法優化系列九:靈活運用SIMD指令16倍提升Sobel邊緣檢測的速度4000*3000的24點陣圖像時間由480ms降低到30ms

  Euclidean distance map(EDM)這個概念可能聽過的人也很少,其主要是用在二值影象中,作為一個很有效的中間處理手段存在。一般的處理都是將灰度圖處理成二值圖或者一個二值圖處理成另外一個二值圖,而EDM演算法確是由一幅二值圖生成一幅灰度圖。其核心定義如下:   The definitio

利用opencv將視訊轉為影象

本文做的是基於opencv將視訊幀轉成圖片輸出,由於一個視訊包含的幀數過多,經常我們並不是需要它的全部幀轉成圖片,因此我們希望可以設定每隔多少幀再轉一次圖片(本文設定為5幀),若有人需求是隻需要前多少幀,也可以類似的改寫下程式碼即可。 本文程式碼如下: #include <ios

C++——bmp影象的腐蝕、膨脹、開運算、閉運算

本文實現二值bmp影象的腐蝕、膨脹及開運算、閉運算操作。本文使用白色為前景、黑色為背景的二值圖進行操作:1、腐蝕腐蝕操作是結構原中心在被腐蝕影象中平移填充的過程。影象A被結構元B腐蝕,用集合論來表示如下式:                                   

MATLAB 求兩張大小完全相同影象影象的白色區域重疊面積

如下圖,兩副大小完全相同的二值影象,現求取白色區域的重疊面積左側影象為test01.jpg,右側為test02.jpg。思路為1.使用imsubtract將兩副影象進行相減操作,假設為test01-test02,則imsubtract(test01,test02),相減之後如