J'essaie de trouver les coins sur une image, je n'ai pas besoin des contours, seulement les 4 coins. Je vais changer la perspective en utilisant 4 coins.
J'utilise Opencv, mais j'ai besoin de connaître les étapes pour trouver les coins et la fonction que j'utiliserai.
Mes images seront comme ceci: (sans points rouges, je peindrai les points après)
ÉDITÉ:
Après les étapes suggérées, j'ai écrit le code: (Remarque: je n'utilise pas OpenCv pur, j'utilise javaCV, mais la logique est la même).
// Load two images and allocate other structures (I´m using other image)
IplImage colored = cvLoadImage(
"res/scanteste.jpg",
CV_LOAD_IMAGE_UNCHANGED);
IplImage gray = cvCreateImage(cvGetSize(colored), IPL_DEPTH_8U, 1);
IplImage smooth = cvCreateImage(cvGetSize(colored), IPL_DEPTH_8U, 1);
//Step 1 - Convert from RGB to grayscale (cvCvtColor)
cvCvtColor(colored, gray, CV_RGB2GRAY);
//2 Smooth (cvSmooth)
cvSmooth( gray, smooth, CV_BLUR, 9, 9, 2, 2);
//3 - cvThreshold - What values?
cvThreshold(gray,gray, 155, 255, CV_THRESH_BINARY);
//4 - Detect edges (cvCanny) -What values?
int N = 7;
int aperature_size = N;
double lowThresh = 20;
double highThresh = 40;
cvCanny( gray, gray, lowThresh*N*N, highThresh*N*N, aperature_size );
//5 - Find contours (cvFindContours)
int total = 0;
CvSeq contour2 = new CvSeq(null);
CvMemStorage storage2 = cvCreateMemStorage(0);
CvMemStorage storageHull = cvCreateMemStorage(0);
total = cvFindContours(gray, storage2, contour2, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
if(total > 1){
while (contour2 != null && !contour2.isNull()) {
if (contour2.elem_size() > 0) {
//6 - Approximate contours with linear features (cvApproxPoly)
CvSeq points = cvApproxPoly(contour2,Loader.sizeof(CvContour.class), storage2, CV_POLY_APPROX_DP,cvContourPerimeter(contour2)*0.005, 0);
cvDrawContours(gray, points,CvScalar.BLUE, CvScalar.BLUE, -1, 1, CV_AA);
}
contour2 = contour2.h_next();
}
}
Donc, je veux trouver les cornes, mais je ne sais pas comment utiliser les fonctions de coins comme cvCornerHarris et autres.
Tout d'abord, consultez /samples/c/squares.c dans votre distribution OpenCV. Cet exemple fournit un détecteur carré, et cela devrait être un bon début sur la façon de détecter les caractéristiques de type coin. Ensuite, jetez un œil aux fonctions orientées fonctionnalités d'OpenCV comme cvCornerHarris () et cvGoodFeaturesToTrack ().
Les méthodes ci-dessus peuvent renvoyer beaucoup des fonctionnalités de type coin - la plupart ne seront pas les "vrais coins" que vous recherchez. Dans ma demande, j'ai dû détecter des carrés qui avaient été tournés ou inclinés (en raison de la perspective). Mon pipeline de détection était composé de:
L'étape 7 était nécessaire car une image légèrement bruyante peut produire de nombreuses structures qui semblent rectangulaires après la polygonalisation. Dans ma candidature, j'ai également dû faire face à des structures de type carré apparaissant à l'intérieur ou chevauchant le carré souhaité. J'ai trouvé que la propriété de surface et le centre de gravité du contour étaient utiles pour discerner le rectangle approprié.
À première vue, pour un œil humain, il y a 4 coins. Mais en vision par ordinateur, un coin est considéré comme un point qui a un grand changement de gradient d'intensité à travers son voisinage. Le voisinage peut être un voisinage de 4 pixels ou un voisinage de 8 pixels.
Dans l'équation fournie pour trouver le gradient d'intensité, il a été considéré pour le voisinage à 4 pixels VOIR DOCUMENTATION .
Voici mon approche pour l'image en question. J'ai le code dans python aussi:
path = r'C:\Users\selwyn77\Desktop\Stack\corner'
filename = 'env.jpg'
img = cv2.imread(os.path.join(path, filename))
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #--- convert to grayscale
C'est un bon choix de toujours brouiller l'image pour supprimer le moins de changements de dégradés possibles et conserver les plus intenses. J'ai choisi de choisir le filtre bilatéral qui contrairement au filtre gaussien ne brouille pas tous les pixels du voisinage. Il brouille plutôt les pixels qui ont une intensité de pixel similaire à celle du pixel central. En bref, il préserve les bords/coins des changements de gradient élevés mais brouille les régions qui ont des changements de gradient minimaux.
bi = cv2.bilateralFilter(gray, 5, 75, 75)
cv2.imshow('bi',bi)
Pour un humain, ce n'est pas tellement une différence par rapport à l'image d'origine. Mais ça compte. Trouver maintenant les coins possibles:
dst = cv2.cornerHarris(bi, 2, 3, 0.04)
dst
renvoie un tableau (la même forme 2D de l'image) avec des valeurs propres obtenues à partir de l'équation finale mentionnée ICI .
Maintenant, un seuil doit être appliqué pour sélectionner ces coins au-delà d'une certaine valeur. J'utiliserai celui de la documentation:
#--- create a black image to see where those corners occur ---
mask = np.zeros_like(gray)
#--- applying a threshold and turning those pixels above the threshold to white ---
mask[dst>0.01*dst.max()] = 255
cv2.imshow('mask', mask)
Les pixels blancs sont des régions de coins possibles. Vous pouvez trouver de nombreux coins voisins.
Pour dessiner les coins sélectionnés sur l'image:
img[dst > 0.01 * dst.max()] = [0, 0, 255] #--- [0, 0, 255] --> Red ---
cv2.imshow('dst', img)
(Les pixels de couleur rouge sont les coins, pas si visibles)
Afin d'obtenir un tableau de tous les pixels avec des coins:
coordinates = np.argwhere(mask)
La variable coor
est un tableau de tableaux. Conversion en liste de listes
coor_list = [l.tolist() for l in list(coor)]
Conversion de ce qui précède en liste de tuples
coor_tuples = [Tuple(l) for l in coor_list]
J'ai un moyen simple et plutôt naïf de trouver les 4 coins. J'ai simplement calculé la distance de chaque coin à chaque autre coin. J'ai conservé ces coins dont la distance dépassait un certain seuil.
Voici le code:
thresh = 50
def distance(pt1, pt2):
(x1, y1), (x2, y2) = pt1, pt2
dist = math.sqrt( (x2 - x1)**2 + (y2 - y1)**2 )
return dist
coor_tuples_copy = coor_tuples
i = 1
for pt1 in coor_tuples:
print(' I :', i)
for pt2 in coor_tuples[i::1]:
print(pt1, pt2)
print('Distance :', distance(pt1, pt2))
if(distance(pt1, pt2) < thresh):
coor_tuples_copy.remove(pt2)
i+=1
Avant d'exécuter l'extrait de code ci-dessus, coor_tuples
Avait tous les points d'angle: [(4, 42), (4, 43), (5, 43), (5, 44), (6, 44), (7, 219), (133, 36), (133, 37), (133, 38), (134, 37), (135, 224), (135, 225), (136, 225), (136, 226), (137, 225), (137, 226), (137, 227), (138, 226)]
Après avoir exécuté l'extrait de code, je suis resté avec 4 coins:
[(4, 42), (7, 219), (133, 36), (135, 224)]
Il ne vous reste plus qu'à marquer ces 4 points sur une copie de l'image d'origine.
img2 = img.copy()
for pt in coor_tuples:
cv2.circle(img2, Tuple(reversed(pt)), 3, (0, 0, 255), -1)
cv2.imshow('Image with 4 corners', img2)
trouver des coins avec peu de calcul
Mat m;//image file
findContours(m, contours_, hierachy_, RETR_EXTERNAL);
auto it = max_element(contours_.begin(), contours_.end(),
[](const vector<Point> &a, const vector<Point> &b) {
return a.size() < b.size(); });
Point2f xy[4] = {{9000,9000}, {0, 1000}, {1000, 0}, {0,0}};
for(auto &[x, y] : *it) {
if(x + y < xy[0].x + xy[0].y) xy[0] = {x, y};
if(x - y > xy[1].x - xy[1].y) xy[1] = {x, y};
if(y - x > xy[2].y - xy[2].x) xy[2] = {x, y};
if(x + y > xy[3].x + xy[3].y) xy[3] = {x, y};
}
xy [4] sera les quatre coins. J'ai pu extraire quatre coins de cette façon.