1. 程式人生 > >源程式設計之美,達萬物之理

源程式設計之美,達萬物之理

opencv中實現霍夫圓變換是通過霍夫梯度法。該原理是:首先對影象應用邊沿檢測(cvCanny)。然後,對邊緣影象中每一個非0點,考慮其區域性梯度(Sobel()函式計算X、Y方向的sobel一階導數得到梯度)。利用得到的梯度,由斜率指定的直線上的每一個點在累加器唄累計,這裡斜率是從一個指定的最小值到指定的最大值的距離。同時表姐邊緣影象中的每一個非零畫素的位置。然後從二維累加器中這些點中選擇候選中心,這些中心大於給定閾值並且大於其所有近鄰。候選中心在累加器中式降序排列的,以便於最支援畫素中心的首先出現。接下來對每一箇中心,考慮所有非零畫素與中心的距離,選擇最支援的一條半徑。

opencv中霍夫圓檢測函式:

CvSeq * cvHoughCircles (
CvArr *image,
void * Circle_storage,
int method,
double dp,
double min_dist,
double param1 = 100,
double param2 = 300,
int min_radius = 0,
int max_radius = 0,
);

circle_strorage 可以是CV_32FC3的單列陣列,三個通道分別儲存圓的位置和半徑。或者記憶體儲存器(memory storage),圓將變成一個序列CvSeq,由cvHoughCircle()返回一個指向這個序列的指標,同時將method 引數設為:CV_HOUGH_GRADIENT.

dp 是累加器影象的解析度,如果為1 ,則解析度是相同的,如果設定更大的值(例如2),累加器的解析度受此影響會變小(此情況為一半)。dp值大於等於1.

min_dist可以區分兩個不同圓之間的最小距離。

param1,param2是邊緣閾值、累加器閾值。

實驗程式碼:

#include <stdio.h>
#include <cv.h>
#include "highgui.h"



int main()
{
	cvNamedWindow("grayimg",1);
	//cvNamedWindow("edges",1);
	cvNamedWindow("hough",1);
	cvMoveWindow("grayimg",0,0);
	//cvMoveWindow("edges",300,60);
	cvMoveWindow("hough",30,0);
	IplImage * img = cvLoadImage("e:/circle.jpg");
	IplImage * gray = NULL,*edges = NULL, *circleimg = NULL;
	CvSize size;
	size.width = img->width;
	size.height = img->height;
	CvMemStorage * storage = cvCreateMemStorage(0);

	CvSeq *result = 0;

	gray = cvCreateImage(size,img->depth,1);
	edges = cvCreateImage(size,img->depth,1);
	circleimg = cvCreateImage(cvGetSize(img),img->depth,img->nChannels);
	cvCvtColor(img,gray,CV_RGB2GRAY);
	//cvCanny(gray,edges,50,100,3);
	
	cvCopy(img,circleimg);
	
	result = cvHoughCircles(gray,storage, CV_HOUGH_GRADIENT, 2, gray->width/10 );
	

	int index; // index 為直線索引
	for (index = 0; index < result->total; index ++)
	{
		float *p = (float *)cvGetSeqElem(result,index);
		CvPoint pt = cvPoint(cvRound( p[0]), cvRound(p[1]));
		cvCircle(circleimg, pt, cvRound(p[2]), CV_RGB(255,0,0));

		
	}


	cvShowImage("grayimg",gray);
	cvShowImage("edges",edges);
	cvShowImage("circleimg",circleimg);
	cvWaitKey();
	cvDestroyAllWindows();
	cvReleaseImage( &gray );
	cvReleaseImage(&img);
	//cvReleaseImage( &edges );
	system("pause");
	return 0;
	
}

result: