python - How to find the centre of these sometimes-overlapping circles -


as part of project i'm working on, need find centre-point of "blobs" in image using opencv python. i'm having bit of trouble it, , appreciate or insight :)

my current method to: contours of images, overlay ellipses on those, use blob detector find centre of each of these. works well, have extraneous blobs need ignore, , blobs touching each-other.

here's example of when goes well: good source image: good source image after extracting contours: after extracting contours with blobs detected: with blobs detected

and when goes poorly (you can see it's incorrectly overlayed ellipse on 3 blobs, , detected 1 don't want): bad source image: bad source image after extracting contours: after extracting contours with blobs detected: with blobs detected

this code use. i'm unsure of other option.

def process_and_detect(img_path):     img = cv2.imread(path)     imgray = cv2.cvtcolor(img, cv2.color_bgr2gray)      ret, thresh = cv2.threshold(imgray, 50, 150, 0)     im2, contours, hierarchy = cv2.findcontours(thresh, cv2.retr_tree, cv2.chain_approx_simple)     drawn_img = np.zeros(img.shape, np.uint8)     min_area = 50     min_ellipses = []     cnt in contours:         if cv2.contourarea(cnt) >= min_area:             ellipse = cv2.fitellipse(cnt)             cv2.ellipse(drawn_img,ellipse,(0,255,0),-1)     plot_img(drawn_img, size=12)      # change thresholds     params = cv2.simpleblobdetector_params()     params.filterbycolor = true     params.blobcolor = 255     params.filterbycircularity = true     params.mincircularity = 0.75     params.filterbyarea = true     params.minarea = 150     # set detector     detector = cv2.simpleblobdetector_create(params)      # detect blobs.     keypoints = detector.detect(drawn_img)     k in keypoints:         x = round(k.pt[0])         y = round(k.pt[1])         line_length = 20         cv2.line(img, (x-line_length, y), (x+line_length, y), (255, 0, 0), 2)         cv2.line(img, (x, y-line_length), (x, y+line_length), (255, 0, 0), 2)     plot_img(img, size=12) 

thank reading far, sincerely hope can me out, or point me in right direction. thanks!

blob detector

currently, implementation redundant. simpleblobdetector() docs:

the class implements simple algorithm extracting blobs image:

  1. convert source image binary images applying thresholding several thresholds minthreshold (inclusive) maxthreshold (exclusive) distance thresholdstep between neighboring thresholds.
  2. extract connected components every binary image findcontours() , calculate centers.
  3. group centers several binary images coordinates. close centers form 1 group corresponds 1 blob, controlled mindistbetweenblobs parameter.
  4. from groups, estimate final centers of blobs , radiuses , return locations , sizes of keypoints.

so you're implementing part of steps already, might give unexpected behavior. try playing parameters see if can figure out work (try creating trackbars play parameters , live results of algorithm different blob detector parameters).

modifying pipeline

however, you've got of own pipeline written, can remove blob detector , implement own algorithm. if drop threshold bit, can marked circles, , blob detection simple contour detection. if have separate contour each blob, can calculate centroid of contour moments(). example:

def process_and_detect(img_path):      img = cv2.imread(img_path)     imgray = cv2.cvtcolor(img, cv2.color_bgr2gray)      ret, thresh = cv2.threshold(imgray, 100, 255, cv2.thresh_binary)      contours = cv2.findcontours(thresh, cv2.retr_tree, cv2.chain_approx_simple)[1]     line_length = 20     c in contours:         if cv2.contourarea(c) >= min_area:             m = cv2.moments(c)             x = int(m['m10']/m['m00'])             y = int(m['m01']/m['m00'])              cv2.line(img, (x-line_length, y), (x+line_length, y), (255, 0, 0), 2)             cv2.line(img, (x, y-line_length), (x, y+line_length), (255, 0, 0), 2) 

detected centroids

getting more involved

this same pipeline can used automatically loop through threshold values don't have guess , hardcode values. since blobs seem same size, can loop through until contours have same area. e.g. finding median contour size, defining percentage of median size above , below you'll allow, , checking if contours detected fit in bounds.

here's animated gif of mean. notice gif stops once contours separated:

contour areas shrinking until similar

then can find centroids of separated contours. here's code:

def process_and_detect(img_path):      img = cv2.imread(img_path)     imgray = cv2.cvtcolor(img, cv2.color_bgr2gray)      thresh_val in range(0, 255):          # threshold , detect contours         thresh = cv2.threshold(imgray, thresh_val, 255, cv2.thresh_binary)[1]         contours = cv2.findcontours(thresh,                                     cv2.retr_tree, cv2.chain_approx_simple)[1]          # filter contours area         min_area = 50         filtered_contours = [c c in contours                              if cv2.contourarea(c) >= min_area]         area_contours = [cv2.contourarea(c) c in filtered_contours]          # acceptable deviation median contour area         median_area = np.median(area_contours)         dev = 0.3         lowerb = median_area - dev*median_area         upperb = median_area + dev*median_area          # break when contours within deviation median area         if ((area_contours > lowerb) & (area_contours < upperb)).all():             break      # draw center location of blobs     line_length = 8     cross_color = (255, 0, 0)     c in filtered_contours:         m = cv2.moments(c)         x = int(m['m10']/m['m00'])         y = int(m['m01']/m['m00'])         cv2.line(img, (x-line_length, y), (x+line_length, y), cross_color, 2)         cv2.line(img, (x, y-line_length), (x, y+line_length), cross_color, 2) 

centroids found

note here looped through possible threshold values range(0, 255) give 0, 1, ..., 254 start higher , skip through few values @ time with, say, range(50, 200, 5) 50, 55, ..., 195 of course faster.


Comments

Popular posts from this blog

android - InAppBilling registering BroadcastReceiver in AndroidManifest -

python Tkinter Capturing keyboard events save as one single string -

sql server - Why does Linq-to-SQL add unnecessary COUNT()? -