web-dev-qa-db-fra.com

Détection de carré dans l'image

J'essaie de détecter toutes les images de dés de forme carrée afin de pouvoir les recadrer individuellement et les utiliser pour l'OCR. Ci-dessous est l'image originale:

image3image4

Voici le code que j'ai, mais il manque quelques carrés.

def find_squares(img):
    img = cv2.GaussianBlur(img, (5, 5), 0)
    squares = []
    for gray in cv2.split(img):
        for thrs in range(0, 255, 26):
            if thrs == 0:
                bin = cv2.Canny(gray, 0, 50, apertureSize=5)
                bin = cv2.dilate(bin, None)
            else:
                _retval, bin = cv2.threshold(gray, thrs, 255, cv2.THRESH_BINARY)
            bin, contours, _hierarchy = cv2.findContours(bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
            for cnt in contours:
                cnt_len = cv2.arcLength(cnt, True)
                cnt = cv2.approxPolyDP(cnt, 0.02*cnt_len, True)
                if len(cnt) == 4 and cv2.contourArea(cnt) > 1000 and cv2.isContourConvex(cnt):
                    cnt = cnt.reshape(-1, 2)
                    max_cos = np.max([angle_cos( cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4] ) for i in range(4)])
                    #print(cnt)
                    a = (cnt[1][1] - cnt[0][1])

                    if max_cos < 0.1 and a < img.shape[0]*0.8:

                        squares.append(cnt)
    return squares

dice = cv2.imread('img1.png')
squares = find_squares(dice)
cv2.drawContours(dice, squares, -1, (0, 255, 0), 3)

Voici les images de sortie: Image1Image2

Selon mon analyse, certains carrés manquent en raison de bords ronds manquants le long des dés en raison de la transition d'intensité en douceur entre les dés et l'arrière-plan.

Étant donné la contrainte qu'il y aura toujours 25 dés dans un motif de grille carré (5 * 5), pouvons-nous prédire les positions carrées manquantes sur la base des carrés reconnus? Ou pouvons-nous modifier l'algorithme ci-dessus pour l'algorithme de détection carré?

8
flamelite

Voici une approche

  • Convertir l'image en niveaux de gris et flou médian pour une image fluide
  • Affinez l'image pour améliorer les bords
  • Seuil
  • Effectuer des transformations morphologiques
  • Trouver les contours et filtrer en utilisant la zone de seuil minimum/maximum
  • Recadrer et économiser le ROI

Accentuer l'image avec cv2.filter2D(). Nous utilisons un noyau de netteté générique, d'autres noyaux peuvent être trouvés ici

enter image description here

Maintenant seuil pour obtenir une image binaire

enter image description here

Effectuer des opérations morphologiques

enter image description here

De là, nous trouvons les contours et filtrons en utilisant cv2.contourArea() avec des zones de seuil minimum/maximum.

enter image description here

Nous pouvons recadrer chaque région carrée souhaitée en utilisant la découpe Numpy et enregistrer chaque ROI comme ceci

x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+h]
cv2.imwrite('ROI_{}.png'.format(image_number), ROI)

enter image description here

import cv2
import numpy as np

image = cv2.imread('1.png')

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray, 5)
sharpen_kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
sharpen = cv2.filter2D(blur, -1, sharpen_kernel)

thresh = cv2.threshold(sharpen,160,255, cv2.THRESH_BINARY_INV)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

min_area = 100
max_area = 1500
image_number = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > min_area and area < max_area:
        x,y,w,h = cv2.boundingRect(c)
        ROI = image[y:y+h, x:x+h]
        cv2.imwrite('ROI_{}.png'.format(image_number), ROI)
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
        image_number += 1

cv2.imshow('sharpen', sharpen)
cv2.imshow('close', close)
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
6
nathancy

Cette information supplémentaire est absolument dorée. Oui, étant donné la matrice de dés 5x5, vous pouvez très bien définir les positions. Les dés que vous pouvez identifier vous donnent le centre, la taille et l'orientation des dés. Continuez simplement ces motifs le long des deux axes. Pour votre deuxième passe, augmentez le contraste dans chaque "région d'intérêt" où vous vous attendez à trouver le bord d'une souris (ne dites jamais mourir!). Vous savez en quelques pixels où seront les bords: atténuez simplement l'image jusqu'à ce que vous identifiiez ces bords.

0
Prune