web-dev-qa-db-fra.com

python opencv - détection de blob ou détection de cercle

J'ai des problèmes pour détecter les zones de cercle. Je l'ai essayé avec la fonction HoughCircles d'opencv. Cependant, même si les images sont assez similaires, les paramètres de la fonction doivent être différents afin de détecter les cercles.

Une autre approche que j'ai essayée était d'itérer sur chaque pixel et de vérifier si le pixel actuel est blanc. Si tel est le cas, vérifiez s'il y a un objet blob dans la zone (distance au centre de blob inférieure à un seuil). Si tel est le cas, ajoutez le pixel au blob, sinon créez un nouveau blob. Cela ne fonctionnait pas non plus correctement.

Quelqu'un a-t-il une idée de comment je peux faire ce travail (détection à 90%)? J'ai joint un exemple d'image et une autre image où j'ai marqué les cercles. Merci!

example

example with arrows

MISE À JOUR: Merci pour l'aide jusqu'à présent! C'est le code où j'acquiert les contours et les filtre par zone:

im = cv2.imread('extract_blue.jpg')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
im_gauss = cv2.GaussianBlur(imgray, (5, 5), 0)
ret, thresh = cv2.threshold(im_gauss, 127, 255, 0)
# get contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

contours_area = []
# calculate area and filter into new array
for con in contours:
    area = cv2.contourArea(con)
    if 1000 < area < 10000:
        contours_area.append(con)

Cela fonctionne assez bien. Je les ai dessinés sur l'image: contours_filtered_area

C'est la partie où j'ai filtré par circularité, elle passe juste en dessous du code où je filtre par zone:

contours_cirles = []

# check if contour is of circular shape
for con in contours_area:
    perimeter = cv2.arcLength(con, True)
    area = cv2.contourArea(con)
    if perimeter == 0:
        break
    circularity = 4*math.pi*(area/perimeter*perimeter)
    print circularity
    if 0.8 < circularity < 1.2:
        contours_cirles.append(con)

Cependant, la nouvelle liste 'contours_cirles' est vide. J'ai imprimé la 'circularité' dans la boucle et les valeurs sont toutes comprises entre 10 000 et 100 000.

MISE À JOUR # 2: Après avoir corrigé les crochets manquants, cela fonctionne maintenant!

contours_cirles = []

# check if contour is of circular shape
for con in contours_area:
    perimeter = cv2.arcLength(con, True)
    area = cv2.contourArea(con)
    if perimeter == 0:
        break
    circularity = 4*math.pi*(area/(perimeter*perimeter))
    print circularity
    if 0.7 < circularity < 1.2:
        contours_cirles.append(con)

Merci beaucoup les gars! :)

example_done

15
cmplx96

Comme point de départ, vous pouvez commencer par:

  • Trouver tous les contours dans l'image donnée en utilisant cv2.findContours()
  • Itérer sur chaque contour:
    • calculer l'aire, si l'aire du contour est dans une plage donnée, dites 70 < area < 150. Cela filtrera certains contours extrêmement petits et grands.
    • Après avoir filtré les contours avec le seuil de surface, vous devez vérifier le nombre d'arêtes de contour, ce qui peut être fait en utilisant: cv2.approxPolyDP(), pour un cercle len (environ) doit être> 8 mais <23. Ou vous pouvez appliquer ici des opérations plus sophistiquées pour détecter les cercles.

Vous devriez essayer d'implémenter cette approche et mettre à jour la question avec le code que vous écrirez désormais.

EDIT: Comme suggéré par @Miki, il existe un moyen meilleur et plus propre de détecter si une forme géométrique est de forme circulaire en utilisant circularity = 4pi (aire/périmètre ^ 2), et décidez d'un seuil tel que 0,9, pour vérifier si la forme est circulaire. Pour un cercle parfait circularity == 1. Vous pouvez affiner ce seuil selon vos besoins.

Vous pouvez consulter arcLength pour trouver le périmètre du contour et contourArea pour obtenir l'aire du contour requise pour calculer la circularité.

5
ZdaR

On pourrait essayer Hough Transformation aussi pour détecter les cercles dans l'image et jouer avec les seuils pour obtenir le résultat souhaité (cercles détectés dans des lignes de frontière vertes avec des points rouges comme centres):

import cv2
import numpy as np

img = cv2.imread('rbv2g.jpg',0)
img = cv2.medianBlur(img,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,10,
                            param1=50,param2=12,minRadius=0,maxRadius=20)

circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
    cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)

cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()

enter image description here

1
Sandipan Dey