Python и OpenCV. Как определить все (заполненные) круги / круглые объекты в изображении?

Я пытаюсь создать программу, которая открывает изображение, просматривает его для кругов / круглых фигур и возвращает координаты, чтобы я мог использовать функцию cv.Circle для рисования кругов по обнаруженному кругу.

Мой вопрос: как получить координаты / радиусы окружностей, обнаруженных на изображении, используя cv.HoughCircles() ?

Используя эту страницу, я узнал, как обнаружить круги (мне потребовалось много времени, чтобы узнать, так как я не понимаю термины, такие как порог, и документация OpenCV для Python действительно бедна, почти нет). К сожалению, на этой странице он не показывал, как извлекать информацию о каждом круге, обнаруженном из созданного 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 , чтобы я мог обнаружить действительно маленькие круги (например, 3 мм на экране)?

Спасибо всем за ваше время и усилия, пытаясь помочь мне!

Изображение, с которым я работаю, это: введите описание изображения здесь

Последние два параметра – это то, что кажется переданным cv.Canny() , что означает, что cv.Canny() вызывается из cv.HoughCircles() . Я не слишком уверен в этом.

Что касается размеров, кажется, что следующие два параметра (после 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, он прост в использовании и имеет хорошие образцы на их веб-странице.