import cvimport numpy as npWAITKEY_DELAY_MS = 10STOP_KEY = 'q'cv.NamedWindow("image - press 'q' to quit", cv.CV_WINDOW_AUTOSIZE);cv.NamedWindow("post-process", cv.CV_WINDOW_AUTOSIZE);key_pressed = Falsewhile key_pressed != STOP_KEY: # grab image orig = cv.LoadImage('circles3.jpg') # create tmp images grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1) processed = cv.CreateImage(cv.GetSize(orig), 8, 1) cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3) cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY) # do some processing on the grey scale image cv.Erode(grey_scale, processed, None, 10) cv.Dilate(processed, processed, None, 10) cv.Canny(processed, processed, 5, 70, 3) cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15) storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3) # these parameters need to be adjusted for every single image HIGH = 50 LOW = 140 try: # extract circles cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, HIGH, LOW) for i in range(0, len(np.asarray(storage))): print "circle #%d" %i Radius = int(np.asarray(storage)[i][0][2]) x = int(np.asarray(storage)[i][0][0]) y = int(np.asarray(storage)[i][0][1]) center = (x, y) # green dot on center and red circle around cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0) cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0) cv.Circle(processed, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0) cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0) except: print "nothing found" pass # show images cv.ShowImage("image - press 'q' to quit", orig) cv.ShowImage("post-process", processed) cv_key = cv.WaitKey(WAITKEY_DELAY_MS) key_pressed = chr(cv_key & 255)
正如你可以從下面的兩個例子看到,“圈子發(fā)現(xiàn)質量”變化頗多: CASE1: CASE2: 案例1案例2和基本形象,但仍算法檢測到不同的圈子。如果我提出的算法的圖像與不同大小的圓圈,在圓檢測甚至可能這主要是由于HIGH
和LOW
這需要單獨為每個新的圖片。 因此,我的問題:什么使這個算法的可能性更應該是大小和顏色不變,讓各界有不同的顏色和不同尺寸的檢測。 Hough變換是不是做事情的最好方法是什么?有沒有更好的辦法?import cv2import mathimport numpy as npd_red = cv2.cv.RGB(150, 55, 65)l_red = cv2.cv.RGB(250, 200, 200)orig = cv2.imread("c.jpg")img = orig.copy()img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)detector = cv2.FeatureDetector_create('MSER')fs = detector.detect(img2)fs.sort(key = lambda x: -x.size)def supress(x): for f in fs: distx = f.pt[0] - x.pt[0] disty = f.pt[1] - x.pt[1] dist = math.sqrt(distx*distx + disty*disty) if (f.size > x.size) and (dist<f.size/2): return Truesfs = [x for x in fs if not supress(x)]for f in sfs: cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), d_red, 2, cv2.CV_AA) cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), l_red, 1, cv2.CV_AA)h, w = orig.shape[:2]vis = np.zeros((h, w*2+5), np.uint8)vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)vis[:h, :w] = origvis[:h, w+5:w*2+5] = imgcv2.imshow("image", vis)cv2.imwrite("c_o.jpg", vis)cv2.waitKey()cv2.destroyAllWindows()
正如你可以看到它的基礎上,MSER的blob檢測。代碼沒有預處理的圖像除了簡單的映射成灰度。缺少這些淡yellow的斑點在你的圖像的預期。 理論 總之:你不知道怎么樣的問題,除了與他們的描述只給出兩個示例圖像。在這里,我解釋為什么我在我的愚見是問什么是攻擊問題之前,有關于這個問題是很重要的。 回到主要問題:什么是這個問題?讓我們來看看這是一個搜索問題。為了簡化,我們正在尋找圓與給定尺寸/問題歸結為找到中心.each像素是候選中心,因此,在搜索空間中包含的所有像素。P = {p1, ..., pn} P: search spacep1...pn: pixels
為了解決這個問題,尋找其他兩個函數應該被定義為:E(P) : enumerates the search spaceV(p) : checks whether the item/pixel has the desirable properties, the items passing the check are added to the output list
假設算法無所謂,或將強力搜索可以在其中E需要的每一個像素,并傳遞到五,在實際應用中,重要的是要減少搜索空間和V的效率 我們正在接近主要問題。我們如何定義V,更準確地說應該如何應做什么候選人的性能解決分割成的兩分法的問題可取和不可取。該方法是找到定義基于屬性的簡單決策規(guī)則的屬性可以。這是你做的試驗和錯誤是什么。你是從正面和負面的例子,學習編程的分類。這是你不知道你想要做什么。你必須/樂曲的決策規(guī)則和/或預處理的數據,即,對于二分法問題所用的屬性的變化(所希望的候選)被減少。你的機器學習算法,以找到一組給定的例子的最優(yōu)值。還有一大堆的從決策樹學習算法編程你這個問題。你可以一個學習算法找到幾個圓檢測算法的最優(yōu)值,看看哪一個給出了一個更好的精度。這需要你只需要收集樣本圖像的學習算法的主要負擔。 另一種方法來提高它經常被忽視的是利用額外隨手如果您知道圓的顏色幾乎為零額外的努力,你可以提高檢測的準確性顯著。如果您知道圓的平面上的位置,你想檢測的成像圈,你應該把這兩套位置之間的轉換是通過一個2D單應說明。和單應可只得到4分。然后,你可以提高到有石頭的特定領域的知識的價值往往被低估??此@樣,在第一種方法中,我們嘗試基于樣本數量有限近似決策規(guī)則。在第二種方法中,我們知道了決策規(guī)則,只需要找到一種方法來有效地利用他們的算法。 總結 總之,有兩種方法來提高解的精度/:工具型:找到一個更簡單的算法/用較少的/扭捏算法/自動化這個過程中機器學習算法號 信息化:都是很容易在你不要的問題“你知道的問題是什么。對于這兩個圖像您分享我一個blob檢測不是針對背景減除我建議嘗試估計的背景顏色的兩個圖像是沒有變化的,而圓圈的顏色有所不同。和大部分區(qū)域是光禿禿的。HoughCircles
在隔離,結果,或者,處理通道,每個通道處理前通道上,其中,然后操作HoughCircles
。在下面我嘗試,我試圖分裂為RGB通道,處理,警惕過度飽和的圖像cv.And
為了避免這個問題(在這個階段我的圈子總是在白色背景上的黑色戒指/盤)。 2:前處理是相當棘手的,其往往是最好的玩弄。我已經為AdaptiveThreshold
這是一個非常強大的,可以通過閾值處理根據他們當地的平均像素提升圖像邊緣(類似的過程也發(fā)生在哺乳動物視覺系統(tǒng)的早期通路)。這是因為它降低了噪音。我dilate/erode
只有一個通行證。我一直保留著你如何讓他們的其他。它Canny
前HoughCircles
的確幫助了很多與發(fā)現(xiàn)“實心圓',所以可能最好保持它。這前處理是相當沉重的,并可能導致更多的'滴狀圈子'假陽性,但在我們的情況下,這或許是可取的? 3:正如您所指出的HoughCirclesparam2
(您的LOW
)需要為每個圖像,以獲得最佳的解決方案,其實從文檔:較小的是,可以檢測到更多的假圓圈。trouble的是甜蜜點將會是不同的每張圖片。我覺得這里的最好的辦法是讓設置一個條件,通過做不同的搜索param2
值,直到這個條件你的圖片顯示不重疊的圓圈,而當param2
太低,我們通常會得到重疊的圓圈負荷。所以我建議尋找的:的非重疊的最大數量,和非包含的圓因此,我們繼續(xù)呼吁HoughCircles用不同的值param2
直到我做到這一點我下面的例子中,僅僅通過param2
直到它達到閾值的假設。這將是更快的方式(而且很容易做到),如果你執(zhí)行一個二進制搜索找到的時候,但你必須要小心,異常處理作為opencv的經常拋出一個錯誤,對無辜的值param2
(至少在我的安裝)。不同的條件,我們將要匹配的將是圓的數量。 4:有沒有更多的約束,我們可以添加到模型?越多的東西,我們可以告訴我們的模型的一個簡單的任務,我們可以把它檢測圈。例如,我們知道:圈數。-即使是上限或下限是有幫助的。 或背景的圓圈的可能的顏色,或“非圓形”。 它們的大小。 在那里他們可以在一個圖像。5:影像中的斑點可能只是籠統(tǒng)地被稱為圈子!考慮兩個'非圓形的斑點“在你的第二個形象,我的代碼無法找到他們(good!),但...如果我'的Photoshop'他們,讓他們有更圓,我的代碼中可以找到它們...也許如果你要檢測的東西都是不圓,采用不同的方法,如Tim Lukins
可能會更好。 問題 通過這樣做繁重的預處理AdaptiveThresholding
和`康力“可以有很多失真特性的圖像,這可能會導致錯誤的檢測圓的,或不正確的報告。例如加工后大量固態(tài)盤會出現(xiàn)一個圈,所以HughesCircles可能會發(fā)現(xiàn)內環(huán)。此外,即使該文檔注意:...通常功能檢測的圓圈“中心好,但它可能無法找到正確的半徑。如果您需要更精確的半徑的檢測,我建議以下方法(不原始圖像,光線追跡從圓的中心報道,在不斷擴大的交叉(4條:上/下/左/右) 在每個RGB通道單獨做到這一點 在一個合理的方式結合起來,每個通道的每個射線(即翻轉,偏移,規(guī)模等必要的) 取平均值為每條射線的前幾個像素,用它來檢測其中射線上的顯著發(fā)生偏差。 這4點是圓周上的點估計。 使用這四個估計,以確定更精確和中心位置(?。?。 這可以推廣的膨脹環(huán)來代替4射線。結果 在結束該代碼確實很不錯了不少的這些例子介紹的都是代碼如下所示: 檢測各界在你的第一個圖像: 如何處理前圖像看上去之前精明的過濾器被應用(不同顏色的圓圈是高度可見的): 檢測所有,但兩(斑點)在第二個圖像: 改變第二圖像(斑點是圓afied,和大的橢圓形變得更圓,提高檢測),所有檢測到的: 確實頗能檢測這個康定斯基的繪畫中心(我無法找到,由于他的邊界條件同心環(huán))。 代碼:import cvimport numpy as npoutput = cv.LoadImage('case1.jpg')orig = cv.LoadImage('case1.jpg')# create tmp imagesrrr=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)ggg=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)bbb=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)processed = cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)def channel_processing(channel): pass cv.AdaptiveThreshold(channel, channel, 255, adaptive_method=cv.CV_ADAPTIVE_THRESH_MEAN_C, thresholdType=cv.CV_THRESH_BINARY, blockSize=55, param1=7) #mop up the dirt cv.Dilate(channel, channel, None, 1) cv.Erode(channel, channel, None, 1)def inter_centre_distance(x1,y1,x2,y2): return ((x1-x2)**2 + (y1-y2)**2)**0.5def colliding_circles(circles): for index1, circle1 in enumerate(circles): for circle2 in circles[index1+1:]: x1, y1, Radius1 = circle1[0] x2, y2, Radius2 = circle2[0] #collision or containment: if inter_centre_distance(x1,y1,x2,y2) < Radius1 + Radius2: return Truedef find_circles(processed, storage, LOW): try: cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, 30, LOW)#, 0, 100) great to add circle constraint sizes. except: LOW += 1 print 'try' find_circles(processed, storage, LOW) circles = np.asarray(storage) print 'number of circles:', len(circles) if colliding_circles(circles): LOW += 1 storage = find_circles(processed, storage, LOW) print 'c', LOW return storagedef draw_circles(storage, output): circles = np.asarray(storage) print len(circles), 'circles found' for circle in circles: Radius, x, y = int(circle[0][2]), int(circle[0][0]), int(circle[0][1]) cv.Circle(output, (x, y), 1, cv.CV_RGB(0, 255, 0), -1, 8, 0) cv.Circle(output, (x, y), Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)#split image into RGB componentscv.Split(orig,rrr,ggg,bbb,None)#process each componentchannel_processing(rrr)channel_processing(ggg)channel_processing(bbb)#combine images using logical 'And' to avoid saturationcv.And(rrr, ggg, rrr)cv.And(rrr, bbb, processed)cv.ShowImage('before canny', processed)# cv.SaveImage('case3_processed.jpg',processed)#use canny, as HoughCircles seems to prefer ring like circles to filled ones.cv.Canny(processed, processed, 5, 70, 3)#smooth to reduce noise a bit morecv.Smooth(processed, processed, cv.CV_GAUSSIAN, 7, 7)cv.ShowImage('processed', processed)#find circles, with parameter searchstorage = find_circles(processed, storage, 100)draw_circles(storage, output)# show imagescv.ShowImage("original with circles", output)cv.SaveImage('case1.jpg',output)cv.WaitKey(0)
fitellipse.py
和squares.py
。 為了您的闡發(fā),我介紹的這些實例的混合動力版,并根據您的原始來源。檢測到的輪廓是在紅,綠和擬合橢圓。這還沒有應用:預處理步驟需要一些調整,以檢測更微弱的圈子。 可以進一步測試該輪廓以確定它是否是一個圓或不...祝你好運!import cvimport numpy as np# grab imageorig = cv.LoadImage('circles3.jpg')# create tmp imagesgrey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)processed = cv.CreateImage(cv.GetSize(orig), 8, 1)cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)# do some processing on the grey scale imagecv.Erode(grey_scale, processed, None, 10)cv.Dilate(processed, processed, None, 10)cv.Canny(processed, processed, 5, 70, 3)cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)#storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)storage = cv.CreateMemStorage(0)contours = cv.FindContours(processed, storage, cv.CV_RETR_EXTERNAL)# N.B. 'processed' image is modified by this!#contours = cv.ApproxPoly (contours, storage, cv.CV_POLY_APPROX_DP, 3, 1) # If you wanted to reduce the number of points...cv.DrawContours (orig, contours, cv.RGB(0,255,0), cv.RGB(255,0,0), 2, 3, cv.CV_AA, (0, 0)) def contour_iterator(contour): while contour: yield contour contour = contour.h_next()for c in contour_iterator(contours): # Number of points must be more than or equal to 6 for cv.FitEllipse2 if len(c) >= 6: # Copy the contour into an array of (x,y)s PointArray2D32f = cv.CreateMat(1, len(c), cv.CV_32FC2) for (i, (x, y)) in enumerate(c): PointArray2D32f[0, i] = (x, y) # Fits ellipse to current contour. (center, size, angle) = cv.FitEllipse2(PointArray2D32f) # Convert ellipse data from float to integer representation. center = (cv.Round(center[0]), cv.Round(center[1])) size = (cv.Round(size[0] * 0.5), cv.Round(size[1] * 0.5)) # Draw ellipse cv.Ellipse(orig, center, size, angle, 0, 360, cv.RGB(255,0,0), 2,cv.CV_AA, 0)# show imagescv.ShowImage("image - press 'q' to quit", orig)#cv.ShowImage("post-process", processed)cv.WaitKey(-1)
編輯: 剛剛更新的說,我認為一個重要的所有這些答案是,有很多可以應用到你尋求承認為圓形哪些進一步的假設和約束條件。我自己的答案是沒有借口在這一點-無論是在低級別的預處理或高級裝修。事實上,許多的圓圈是不是真正的圓形,由于它們的繪制方法或圖像的non-affine/projective變換,并與它們是如何呈現(xiàn)的其他屬性/捕獲(顏色,噪聲,照明邊厚)-所有的結果在短短的一個圖像在任何數量的可能的候選圈。 有更復雜的技術。但他們會花費你。我個人喜歡@飛梭想法addaptive門檻。這是快速,可靠,合理,您可以再進一步的測試最終的輪廓(例如使用胡或管件與橢圓軸的一個簡單的比率測試-例如,如果((分(大小)/最大(大?。?gt; 0.7)。 一如以往與計算機視覺有實用主義,原則,parsomony之間的緊張關系。由于我喜歡告訴別人誰認為簡歷是很容易的,它不是-它實際上是一個問題。最好的,你經??梢韵M@外面是工作的大部分HSV
變換,平滑的副本,然后取原和平滑副本之間的差異。這將讓你dH, dS, dV
值的每個點(在色調,飽和度,數值局部變化)。廣場和添加來獲得一個圖像,附近所有的邊(內部和外部)的山峰。 我的第二個是本地的正?;?,但我不知道如果這甚至是必要的。這個想法是,你不關心特別多關于你離開了邊緣信號的精確值,它應該是二進制反正(邊或不)。因此,您可以通過當地的平均水平(其中地方是在你邊尺寸的量級)除以正?;拿總€值。HoughCircles
該模型是一個完美的圓。的,有可能不存在將使得檢測更加不穩(wěn)定和橢圓形的圈里你的照片,而不會增加誤報的數量。在另一方面,由于相關的非封閉的正圓或一個完美的圓圈,一個“凹”可能會持續(xù)出現(xiàn)。所以根據您的期望輸出您可能會或可能不希望 這就是說,有我看這可能會幫助你對你的方式使用此功能的幾件事情:HoughCircles
電話Canny
在內部,所以我想你可以離開了呼叫。param1
(你叫HIGH
)通常被初始化周圍的一個值200
。它作為一個到內部調用Canny
:cv.Canny(processed, cannied, HIGH, HIGH/2)
。這可能有助于運行Canny
自己喜歡這個,看看如何設置HIGH
受影響的霍夫正在處理與圖像變換。param2
(你叫LOW
)通常被初始化圍繞一個值100
。這是Hough變換的蓄電池的投票門檻。設置它更多的假陰性,更降低誤報。我相信這是你想開始擺弄周圍的第一個。參考: 重新更新:實心圓:當你發(fā)現(xiàn)圓的形狀與Hough變換可以測試,如果他們通過采樣邊界的顏色它假想圓內的一個或多個點的填補?;蛘吣銘撊ψ咏o定的背景色內一個或多個點。如果比較或的情況下,如果它失敗圓圈顯示為實心。**Active Contours**
活動輪廓模型關于活動輪廓的好處是,他們幾乎完美融入任何給定的形狀。無論是正方形或三角形,在你的情況下,他們是完美的人選。 如果你能夠提取圓的中心,這是偉大的?;顒虞喞偸切枰粋€點開始從他們既可以增大或縮小以適合。沒有必要使中心總是對準到中心。有一點偏移仍然是好的。 和你的情況,如果你讓輪廓,從中心向外生長,應休息一圓的邊界。 需要注意的是活動輪廓生長或氣球的能量可以設置輪廓的方向,向內或向外。 你可能會需要在灰度梯度圖像。但你仍然可以在色彩嘗試為好。如果它的工作原理! 如果你不提供中心,扔在大量活躍的輪廓,然后讓增長/萎縮。該安定下來的輪廓被保留,不安的是扔掉。這是一個暴力的方法。將CPU密集型。但將需要更多細致的工作,以確保你離開正確的輪廓和扔掉壞的。我希望這種方式可以解決這個問題。聯(lián)系客服