[英]Python and OpenCV. How do I detect all (filled)circles/round objects in an image?
我正在嘗試制作一個打開圖像的程序,掃描它的圓形/圓形並返回坐標,以便我可以使用cv.Circle
函數在檢測到的圓上繪制圓圈。
我的問題是:如何使用cv.HoughCircles()
圖像中檢測到的圓的坐標/半徑?
使用這個頁面,我發現了如何檢測圓圈(這花了我很多時間才發現,因為我不理解像閾值這樣的術語,而Python的OpenCV文檔真的很差,幾乎沒有)。 不幸的是,在該頁面上它沒有顯示如何提取從創建的CvMat
檢測到的每個圓的信息。 如何提取該信息/是否有其他方式(例如,使用MemoryStorage()
)?
到目前為止這是我的代碼:
import cv, opencv
def main():
im = cv.LoadImageM("Proba.jpg")
gray = cv.CreateImage(cv.GetSize(im), 8, 1)
edges = cv.CreateImage(cv.GetSize(im), 8, 1)
cv.CvtColor(im, gray, cv.CV_BGR2GRAY)
cv.Canny(gray, edges, 50, 200, 3)
cv.Smooth(gray, gray, cv.CV_GAUSSIAN, 9, 9)
storage = cv.CreateMat(im.rows, 1, cv.CV_32FC3)
cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 2, gray.height/4, 200, 100)
# Now, supposing it found circles, how do I extract the information?
print storage.r
if __name__ == '__main__':
main()
另外, HoughCircles
的最后兩個參數需要具有什么值才能檢測出真正的小圓圈(如屏幕上的3mm)?
謝謝大家的時間和精力來幫助我!
我正在使用的圖像是這樣的:
最后兩個參數是什么似乎要傳遞給cv.Canny()
這意味着cv.Canny()
是從內部被稱為cv.HoughCircles()
我不太確定。
至於尺寸,似乎接下來的兩個參數(在200, 100)
之后200, 100)
默認為0
,這可能意味着檢測到所有尺寸。
從C ++示例的源代碼中,我還可以猜測您不需要進行Canny邊緣檢測:
#include <cv.h>
#include <highgui.h>
#include <math.h>
using namespace cv;
int main(int argc, char** argv)
{
Mat img, gray;
if( argc != 2 && !(img=imread(argv[1], 1)).data)
return -1;
cvtColor(img, gray, CV_BGR2GRAY);
// smooth it, otherwise a lot of false circles may be detected
GaussianBlur( gray, gray, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
HoughCircles(gray, circles, CV_HOUGH_GRADIENT,
2, gray->rows/4, 200, 100 );
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// draw the circle center
circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
namedWindow( "circles", 1 );
imshow( "circles", img );
return 0;
}
你想把這個C ++代碼轉換成Python嗎?
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// draw the circle center
circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
據我所知, CvMat
對象是可迭代的,就像一個列表:
for circle in storage:
radius = circle[2]
center = (circle[0], circle[1])
cv.Circle(im, center, radius, (0, 0, 255), 3, 8, 0)
我沒有任何測試圖像,所以不要說我的話這是有效的。 您的完整代碼可能是:
import cv
def main():
im = cv.LoadImage('Proba.jpg')
gray = cv.CreateImage(cv.GetSize(im), 8, 1)
edges = cv.CreateImage(cv.GetSize(im), 8, 1)
cv.CvtColor(im, gray, cv.CV_BGR2GRAY)
#cv.Canny(gray, edges, 20, 55, 3)
storage = cv.CreateMat(im.width, 1, cv.CV_32FC3)
cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 5, 25, 200, 10)
for i in xrange(storage.width - 1):
radius = storage[i, 2]
center = (storage[i, 0], storage[i, 1])
print (radius, center)
cv.Circle(im, center, radius, (0, 0, 255), 3, 8, 0)
cv.NamedWindow('Circles')
cv.ShowImage('Circles', im)
cv.WaitKey(0)
if __name__ == '__main__':
main()
看看我對這個問題的答案是否有一些有用的源代碼(它是C但是我使用的是C ++編譯器,因為它更寬松)。
首先,我裁剪你的圖像(為了方便使用)並對你的圖像應用一個閾值,將前景與背景分開:
然后我直接將源代碼應用於閾值圖像。 這是文本輸出:
center x: 330 y: 507 A: 13 B: 4
center x: 78 y: 507 A: 22 B: 4
center x: 270 y: 503 A: 8 B: 8
center x: 222 y: 493 A: 21 B: 17
center x: 140 y: 484 A: 17 B: 18
center x: 394 y: 478 A: 17 B: 15
center x: 311 y: 468 A: 8 B: 8
center x: 107 y: 472 A: 12 B: 12
center x: 7 y: 472 A: 6 B: 19
center x: 337 y: 442 A: 10 B: 9
center x: 98 y: 432 A: 10 B: 10
center x: 357 y: 421 A: 7 B: 7
center x: 488 y: 429 A: 22 B: 23
center x: 411 y: 400 A: 13 B: 12
center x: 42 y: 400 A: 11 B: 12
center x: 365 y: 391 A: 14 B: 13
center x: 141 y: 396 A: 19 B: 19
center x: 9 y: 379 A: 8 B: 18
center x: 192 y: 365 A: 10 B: 9
center x: 347 y: 340 A: 20 B: 20
center x: 8 y: 305 A: 7 B: 13
center x: 95 y: 308 A: 23 B: 24
center x: 318 y: 297 A: 15 B: 15
center x: 159 y: 285 A: 10 B: 10
center x: 412 y: 291 A: 26 B: 27
center x: 504 y: 278 A: 6 B: 16
center x: 233 y: 277 A: 20 B: 20
center x: 459 y: 256 A: 15 B: 15
center x: 7 y: 239 A: 6 B: 9
center x: 377 y: 239 A: 14 B: 14
center x: 197 y: 228 A: 12 B: 12
center x: 302 y: 237 A: 12 B: 22
center x: 98 y: 224 A: 24 B: 23
center x: 265 y: 203 A: 18 B: 18
center x: 359 y: 202 A: 22 B: 22
center x: 149 y: 201 A: 20 B: 21
center x: 219 y: 169 A: 7 B: 9
center x: 458 y: 172 A: 20 B: 20
center x: 497 y: 157 A: 13 B: 21
center x: 151 y: 125 A: 18 B: 17
center x: 39 y: 109 A: 9 B: 10
center x: 81 y: 116 A: 20 B: 19
center x: 249 y: 104 A: 14 B: 13
center x: 429 y: 76 A: 23 B: 24
center x: 493 y: 33 A: 11 B: 10
center x: 334 y: 26 A: 12 B: 14
這是輸出圖像:
主要問題是沒有檢測到合並在一起的圓圈。 該代碼最初是為檢測填充省略號而編寫的,因此您可以通過調整代碼來處理此問題。
python中的類似解決方案。 最初我試圖運行這里描述的輪廓檢測,但它不能很好地工作。 所以首先需要一些閾值處理。 閾值代碼在這里:
fimg = misc.imread("boubles.jpg")
gimg = color.colorconv.rgb2grey(fimg)
vimg = []
for l in gimg:
l2 = sign(l - 0.50) / 2 + 0.5
vimg.append(l2)
img = array(vimg)
imshow(img)
有了這個我得到這樣的圖像:
在上面鏈接中描述的邊緣檢測后,我得到了這個:
如果檢查代碼,您會發現計算對象非常容易。 唯一的問題是,一些氣泡被計算兩次。 我猜測閾值函數也可以改進。 但我建議使用skimage,它易於使用,並且在他們的網頁上有很好的樣本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.