源程式設計之美,達萬物之理
阿新 • • 發佈:2019-01-10
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: