1. 程式人生 > >opencv 簡單的實現霍夫變換(改進版)

opencv 簡單的實現霍夫變換(改進版)

//霍夫變換  輸入單通道二值影象 檢測直線數量
void HoughLines(Mat &img,int n)
{
	int i,j;
	//行列
	int row = img.rows;
	int col = img.cols;

	//極徑最大值為 對角線+寬
	int max_r = col + cvCeil (sqrt(double(row*row+col*col)));

	//累加器 三角函式
	int *line_cnt[180];
	double sin_[180],cos_[180],rad_ = CV_PI/180;
	for(i = 0; i < 180; i++)
	{
		//初始化累加器為0
		line_cnt[i] = new int[max_r]();
		//初始化三角函式
		sin_[i] = sin(i*rad_);
		cos_[i] = cos(i*rad_);
	}

	//極徑 極角
	int r = 0;
	int theta = 0;

	//遍歷影象 判斷並進行累加
	uchar *p;  
    for( i = 0; i < row; i++)  
    {  
        p = img.ptr<uchar>(i);  
        for ( j = 0; j < col; j++)  
        {
            if(p[j] != 0) 
			{
				for( theta =0; theta < 180 ; theta++)
				{
					//極座標 直線方程
					r =cvRound(j*cos_[theta]+i*sin_[theta]);
					//偏移 無負值
					r = r + col;
					line_cnt[theta][r]++;
				}
			}
        }  
    } 

	//存放取出最長的n條直線   
	int *line_n[3];
	line_n[0] = new int[n]();//極角
    line_n[1] = new int[n]();//極徑
	line_n[2] = new int[n]();//共點數量
	int tt = 0,rr = 0,cnt = 0;
	for(theta = 0; theta < 180; theta++)
	{
		for( r = 0; r < max_r; r++)
		{
			//最少共點 < 這條直線的共點 則替換 並嘗試進行冒泡
			if(line_n[2][n-1] < line_cnt[theta][r])
			{
				line_n[0][n-1] = theta;
				//累計的時候偏移過 這裡再偏移回來
				line_n[1][n-1] = r - col;
				line_n[2][n-1] = line_cnt[theta][r];
				//氣泡排序
				for(i = n - 1;i > 0; i--)
				{
					//如果大於 則交換
					if(line_n[2][i] > line_n[2][i-1])
					{
						tt = line_n[0][i];
						rr = line_n[1][i];
						cnt = line_n[2][i];
						line_n[0][i] = line_n[0][i-1];
						line_n[1][i] = line_n[1][i-1];
						line_n[2][i] = line_n[2][i-1];
						line_n[0][i-1] = tt;
						line_n[1][i-1] = rr;
						line_n[2][i-1] =cnt;
					}
					else
						break;
				}
			}
		}
	}

	//為了畫綠線 單通道轉換為三通道
    cvtColor(img, img, CV_GRAY2BGR);

	//畫出線段
	for(i = 0; i < n; i++ )  
    {
		Point pt1, pt2;  
		double a = cos_[line_n[0][i]], b = sin_[line_n[0][i]];  
		double x0 = a* line_n[1][i], y0 = b* line_n[1][i];  
		pt1.x = cvRound(x0 + max_r*(-b));  
		pt1.y = cvRound(y0 + max_r*(a));  
		pt2.x = cvRound(x0 - max_r*(-b));  
		pt2.y = cvRound(y0 - max_r*(a)); 
		//綠線
		line(img, pt1, pt2, Scalar(0,255,0), 1, CV_AA); 
    } 

	//-------------------釋放記憶體------------------------
	for(i = 0; i < 180; i++)
	{
		delete []line_cnt[i];
	}
	delete []line_n[0];
	delete []line_n[1];
	delete []line_n[2];
}