Je veux faire une rectification planaire, pour convertir de gauche à droite:
J'ai le code pour faire la correction, mais j'ai besoin des 4 coins de coin.
J'utilise le code suivant pour les trouver:
import cv2 image = cv2.imread('input.png') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) canny = cv2.Canny(gray, 120, 255, 1) corners = cv2.goodFeaturesToTrack(canny,4,0.5,50) for corner in corners: x,y = corner.ravel() cv2.circle(image,(x,y),5,(36,255,12),-1) cv2.imshow("result", image) cv2.waitKey()
Il lit l'image et la transforme en niveaux de gris + astucieux
Mais les coins résultants (trouvés par cv2.goodFeaturesToTrack) ne sont pas ceux souhaités:
J'ai besoin des coins externes de la carte, un indice pour y parvenir?
Merci
Voici le fichier input.png:
3 Réponses :
Canny est un outil de détection des bords, et s'il est correctement réglé, il fait ce qu'il dit sur l'étain.
Une fois que vous obtenez les bords, vous devez définir ce qu'est un coin. Par exemple, est-ce un virage serré dans un bord?
Vous souhaitez utiliser la fonction cv2.goodFeaturesToTrack
, qui est censée être un outil de détection de coin , mais encore une fois, qu'est-ce qu'un coin? Il utilise l'algorithme Shi-Tomasi pour trouver les N «meilleurs» coins d'une image, qui n'est qu'un seuil, et une distance minimale entre les points.
En fin de compte, il est garanti de ne presque jamais supporter les quatre coins que vous voulez. Vous devriez essayer ces alternatives et vous en tenir à la meilleure option:
essayez d'obtenir plus de coins et déterminez géométriquement les quatre "les plus éloignés".
combinez votre méthode avec une autre transformation ou correspondance d'objet. Par exemple, si vous recherchez une image rectangulaire, essayez de la faire correspondre à un modèle, calculez la matrice de transformation et résolvez les bords après la transformation.
utilisez une autre méthode de détection des contours ou une combinaison de méthodes.
Notez qu'une carte n'a pas de coins pointus comme un morceau de papier, vous finirez donc par rogner la carte ou l'incliner si vous utilisez un "coin" sur les bords arrondis ou si vous essayez de localiser un bord en dehors du "blanc" réel "de la carte, pour éviter le biais (essayez d'inscrire la carte dans un rectangle aux bords nets) - notez que Canny n'est pas efficace dans ce cas.
Mise à jour: Ajout de la transformation de perspective en quatre points.
J'ai sauté la transformation de perspective car la question est de trouver les bons coins.
Vous pouvez sauter la boucle en obtenant un contour avec maximum area
puis en le traitant. Un peu de flou peut l'aider davantage. Appuyez sur le bouton Esc
pour obtenir la sortie d'image suivante.
Une autre méthode utile, comment trouver les coins des coins d'une forme dans une image dans opencv?
""" Task: Detect card corners and fix perspective """ import cv2 import numpy as np img = cv2.imread('resources/KSuVq.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(gray,127,255,0) cv2.imshow('Thresholded original',thresh) cv2.waitKey(0) ## Get contours contours,h = cv2.findContours(thresh,cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) ## only draw contour that have big areas imx = img.shape[0] imy = img.shape[1] lp_area = (imx * imy) / 10 ################################################################# # Four point perspective transform # https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/ ################################################################# def order_points(pts): # initialzie a list of coordinates that will be ordered # such that the first entry in the list is the top-left, # the second entry is the top-right, the third is the # bottom-right, and the fourth is the bottom-left rect = np.zeros((4, 2), dtype = "float32") # the top-left point will have the smallest sum, whereas # the bottom-right point will have the largest sum s = pts.sum(axis = 1) rect[0] = pts[np.argmin(s)] rect[2] = pts[np.argmax(s)] # now, compute the difference between the points, the # top-right point will have the smallest difference, # whereas the bottom-left will have the largest difference diff = np.diff(pts, axis = 1) rect[1] = pts[np.argmin(diff)] rect[3] = pts[np.argmax(diff)] # return the ordered coordinates return rect def four_point_transform(image, pts): # obtain a consistent order of the points and unpack them # individually rect = order_points(pts) (tl, tr, br, bl) = rect # compute the width of the new image, which will be the # maximum distance between bottom-right and bottom-left # x-coordiates or the top-right and top-left x-coordinates widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2)) widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2)) maxWidth = max(int(widthA), int(widthB)) # compute the height of the new image, which will be the # maximum distance between the top-right and bottom-right # y-coordinates or the top-left and bottom-left y-coordinates heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2)) heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2)) maxHeight = max(int(heightA), int(heightB)) # now that we have the dimensions of the new image, construct # the set of destination points to obtain a "birds eye view", # (i.e. top-down view) of the image, again specifying points # in the top-left, top-right, bottom-right, and bottom-left # order dst = np.array([ [0, 0], [maxWidth - 1, 0], [maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtype = "float32") # compute the perspective transform matrix and then apply it M = cv2.getPerspectiveTransform(rect, dst) warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight)) # return the warped image return warped ################################################################# ## Get only rectangles given exceeding area for cnt in contours: approx = cv2.approxPolyDP(cnt,0.01 * cv2.arcLength(cnt, True), True) ## calculate number of vertices #print(len(approx)) if len(approx) == 4 and cv2.contourArea(cnt) > lp_area: print("rectangle") tmp_img = img.copy() cv2.drawContours(tmp_img, [cnt], 0, (0, 255, 255), 6) cv2.imshow('Contour Borders', tmp_img) cv2.waitKey(0) tmp_img = img.copy() cv2.drawContours(tmp_img, [cnt], 0, (255, 0, 255), -1) cv2.imshow('Contour Filled', tmp_img) cv2.waitKey(0) # Make a hull arround the contour and draw it on the original image tmp_img = img.copy() mask = np.zeros((img.shape[:2]), np.uint8) hull = cv2.convexHull(cnt) cv2.drawContours(mask, [hull], 0, (255, 255, 255), -1) cv2.imshow('Convex Hull Mask', mask) cv2.waitKey(0) # Draw minimum area rectangle tmp_img = img.copy() rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) box = np.int0(box) cv2.drawContours(tmp_img, [box], 0, (0, 0, 255), 2) cv2.imshow('Minimum Area Rectangle', tmp_img) cv2.waitKey(0) # Draw bounding rectangle tmp_img = img.copy() x, y, w, h = cv2.boundingRect(cnt) cv2.rectangle(tmp_img, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.imshow('Bounding Rectangle', tmp_img) cv2.waitKey(0) # Bounding Rectangle and Minimum Area Rectangle tmp_img = img.copy() rect = cv2.minAreaRect(cnt) box = cv2.boxPoints(rect) box = np.int0(box) cv2.drawContours(tmp_img, [box], 0, (0, 0, 255), 2) x, y, w, h = cv2.boundingRect(cnt) cv2.rectangle(tmp_img, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.imshow('Bounding Rectangle', tmp_img) cv2.waitKey(0) # determine the most extreme points along the contour # https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/ tmp_img = img.copy() extLeft = tuple(cnt[cnt[:, :, 0].argmin()][0]) extRight = tuple(cnt[cnt[:, :, 0].argmax()][0]) extTop = tuple(cnt[cnt[:, :, 1].argmin()][0]) extBot = tuple(cnt[cnt[:, :, 1].argmax()][0]) cv2.drawContours(tmp_img, [cnt], -1, (0, 255, 255), 2) cv2.circle(tmp_img, extLeft, 8, (0, 0, 255), -1) cv2.circle(tmp_img, extRight, 8, (0, 255, 0), -1) cv2.circle(tmp_img, extTop, 8, (255, 0, 0), -1) cv2.circle(tmp_img, extBot, 8, (255, 255, 0), -1) print("Corner Points: ", extLeft, extRight, extTop, extBot) cv2.imshow('img contour drawn', tmp_img) cv2.waitKey(0) #cv2.destroyAllWindows() ## Perspective Transform tmp_img = img.copy() pts = np.array([extLeft, extRight, extTop, extBot]) warped = four_point_transform(tmp_img, pts) cv2.imshow("Warped", warped) cv2.waitKey(0) cv2.destroyAllWindows()
https://docs.opencv.org/4.5.0/dd/d49/tutorial_py_contour_features.html
https://www.pyimagesearch.com/2016/04/11/finding-extreme-points-in-contours-with-opencv/
https://www.pyimagesearch.com/2014/08/25/4-point-opencv-getperspective-transform-example/
Voici une façon de trouver les coins dans Python OpenCV. Je note que c'est plus compliqué car les points verts sur l'entrée compliquent le problème et ils ne seraient probablement pas dans l'image d'entrée. On pourrait simplement limiter les points verts en utilisant cv2.inRange () pour trouver les points verts. Mais je suppose que ce n'est pas vraiment ce que vous voulez.
306 167 42 149 114 283 227 69
Contribution:
227 69 41 149 114 284 307 167 228 70
Contours et polygone sur l'image d'entrée:
Contours et polygone sur fond noir:
Sommets du polygone:
import cv2 import numpy as np import time # load image img = cv2.imread("hello.png") # convert to gray gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # threshold thresh = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)[1] # get the largest contour contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours = contours[0] if len(contours) == 2 else contours[1] big_contour = max(contours, key=cv2.contourArea) peri = cv2.arcLength(big_contour, True) # draw contour on input in red result = img.copy() result2 = np.zeros_like(img) cv2.drawContours(result, [big_contour], 0, (0,0,255), 1) cv2.drawContours(result2, [big_contour], 0, (0,0,255), 1) # reduce to fewer vertices on polygon poly = cv2.approxPolyDP(big_contour, 0.1 * peri, False) # draw polygon on input in green cv2.polylines(result, [poly], False, (0,255,0), 1) cv2.polylines(result2, [poly], False, (0,255,0), 1) # list polygon points print("Polygon Points:") for p in poly: px = p[0][0] py = p[0][1] print(px,py) print('') # draw white filled polygon on black background result3 = np.zeros_like(thresh) cv2.fillPoly(result3,[poly],255) # get corners corners = cv2.goodFeaturesToTrack(result3,4,0.01,50,useHarrisDetector=True,k=0.04) # print corner coords and draw circles result3 = cv2.merge([result3,result3,result3]) print("Corners:") for c in corners: x,y = c.ravel() print(int(x), int(y)) cv2.circle(result3,(x,y),3,(0,0,255),-1) # save result cv2.imwrite("hello_contours.png", result) cv2.imwrite("hello_polygon.png", result2) cv2.imwrite("hello_corners.png", result3) # display it cv2.imshow("thresh", thresh) cv2.imshow("result", result) cv2.imshow("result2", result2) cv2.imshow("result3", result3) cv2.waitKey(0)
Notez que les premier et dernier sommets sont à moins d'un pixel l'un de l'autre
Coins sur polygone blanc sur fond noir:
Sommets d'angle:
- Read the input - Convert to gray - Threshold - Get the largest contour and draw it on the input - Reduce the number of vertices in the contour as a polygon and draw the polygon on the input. - The polygon has 5 vertices and two are virtually the same. Normally, one would get 4 verices if the green dots were not there. So draw a white filled polygon on a black background. - Get the corners from the white polygon on black background and draw on these vertices - Save the results
Pourquoi le détecteur goodFeaturesToTrack devinerait-il que vous voulez les quarts de cercle?
Veuillez ne pas publier de captures d'écran. Publiez des images originales sans bordures, etc. et séparément.