Je souhaite utiliser un seul rectangle pour couvrir le cercle de cette image:
Et obtenez ce résultat avec cv2.minAreaRect ( cnt)
:
Cette image semble être divisée en plusieurs parties. C'est peut-être parce qu'il y a un point d'arrêt sur le bord de cette image. pouvez-vous me dire comment utiliser un seul rectangle pour couvrir ce cercle de mon image? Merci beaucoup!
Voici mon code:
def draw_min_rect_circle(img, cnts): # conts = contours img = np.copy(img) for cnt in cnts: x, y, w, h = cv2.boundingRect(cnt) cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) # blue min_rect = cv2.minAreaRect(cnt) # min_area_rectangle min_rect = np.int0(cv2.boxPoints(min_rect)) cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2) # green (x, y), radius = cv2.minEnclosingCircle(cnt) center, radius = (int(x), int(y)), int(radius) # center and radius of minimum enclosing circle img = cv2.circle(img, center, radius, (0, 0, 255), 2) # red return img
3 Réponses :
Ce que vous devez faire est que vous ne devez obtenir qu'un seul contour de l'image en fusionnant les contours, c'est un peu difficile à faire, donc si vous voulez seulement un rect englobant autour de tous les contours, vous pouvez faire quelque chose en tant que tel
def draw_min_rect_circle(img, cnts): # conts = contours img = np.copy(img) x1,y1 = np.inf x2,y2 = 0 for cnt in cnts: x, y, w, h = cv2.boundingRect(cnt) if x > x1: x1=x if y > y1: y1=y if x2 < x+w x2 = x+w if y2 < y+h y2 = y+h w = x2 - x1 h = y2 - y1 r = math.sqrt((w*w) + (h*h)) / 2 cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) cv2.circle(img, (x1+w/2,y1+h/2), r, (0, 0, 255), 2)
Vous avez probablement recherché des contours avec cv2.findContours ()
et les avez parcourus pour dessiner le rectangle sur l'image. Le problème est que votre image n'a pas le cercle constitué d'une ligne connectée mais de plusieurs lignes brisées.
Les contours sont des courbes joignant tous les points continus (le long de la frontière), ayant la même couleur ou intensité (documentation OpenCV).
Donc, pour obtenir un meilleur résultat, vous devez d'abord préparer votre image avant de rechercher contours. Vous pouvez utiliser divers outils pour prétraiter l'image (vous pouvez rechercher la documentation OpenCV). Dans ce cas, j'essaierais d'exécuter la procédure appelée "fermeture" avec un petit noyau. La fermeture est une dilatation suivie d'une érosion des pixels. Cela peut aider à relier vos petits contours à un seul grand contour (cercle). Ensuite, vous pouvez sélectionner le plus grand et dessiner un rectangle de délimitation.
Exemple:
Image d'entrée:
import cv2 import numpy as np img = cv2.imread('test.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) kernel = np.ones((3,3), dtype=np.uint8) closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) _, contours, hierarchy = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) cnt = max(contours, key=cv2.contourArea) x,y,w,h = cv2.boundingRect(cnt) cv2.rectangle(img, (x,y), (x+w, y+h), (255,255,0), 1) cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()
Résultat:
Image après avoir effectué l'opération de fermeture:
J'espère que cela vous aidera. Bravo!
C'est une excellente solution. La méthode d'élimination du bruit en fermant puis en parcourant les contours pour trouver le maximum est simple mais très efficace.
Des solutions simples, s'ils fonctionnent, sont dans mon expérience les meilleures solutions. Heureux d'avoir aidé.
@kavko Merci pour votre aide! Votre solution fonctionne. C'est vraiment une excellente solution!
Il est possible de joindre tous les contours en un seul contour, car ce ne sont que de nombreux tableaux de coordonnées de points décrivant le contour. Vous pouvez utiliser np.concatenate (contours) et il semble que la fonction cv2.minAreaRect ne se soucie pas que les points du nouveau tableau ne soient pas continus. Dans mon cas, cela fonctionnait mieux que d'utiliser la fonction de fermeture, car j'ai des objets plus complexes. Si vous voulez, vous pouvez l'essayer, c'est simple. Voici à quoi devrait ressembler votre fonction:
def draw_min_rect_circle(img, cnts): # conts = contours img = np.copy(img) join_cnts = np.concatenate(cnts) x, y, w, h = cv2.boundingRect(join_cnts) cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2) # blue min_rect = cv2.minAreaRect(join_cnts) # min_area_rectangle min_rect = np.int0(cv2.boxPoints(min_rect)) cv2.drawContours(img, [min_rect], 0, (0, 255, 0), 2) # green (x, y), radius = cv2.minEnclosingCircle(join_cnts) center, radius = (int(x), int(y)), int(radius) # center and radius of minimum enclosing circle img = cv2.circle(img, center, radius, (0, 0, 255), 2) # red return img
On pourrait trouver une solution sur l'image binaire fournie, bien sûr, mais je pense que ce serait mieux si vous fournissiez votre image d'entrée d'origine, car il pourrait y avoir une meilleure solution globale pour votre problème.