web-dev-qa-db-ja.com

画像内の正方形検出

私はすべての正方形のサイコロ画像を検出して、それらを個別にトリミングしてOCRに使用できるようにしています。以下は元の画像です:

image3image4

ここに私が持っているコードがありますが、いくつかの正方形がありません。

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)

これが出力画像です: Image1Image2

私の分析によると、ダイスと背景の間の強度の遷移が滑らかなため、ダイスに沿った細いエッジが欠落しているため、いくつかの正方形が欠落しています。

正方形のグリッドパターン(5 * 5)には常に25のダイスがあるという制約がある場合、認識された正方形に基づいて、欠けている正方形の位置を予測できますか?または、方形検出アルゴリズム用に上記のアルゴリズムを変更できますか?

8
flamelite

これがアプローチです

  • 画像をグレースケールに変換し、中央値のぼかしを滑らかな画像に
  • 画像をシャープにしてエッジを強調します
  • 敷居
  • 形態学的変換を実行する
  • 等高線を見つけ、最小/最大しきい値領域を使用してフィルタリングします
  • ROIの切り抜きと保存

cv2.filter2D()を使用して画像をシャープにします。汎用のシャープカーネルを使用します。他のカーネルも見つかります here

enter image description here

バイナリイメージを取得するためのしきい値

enter image description here

形態学的操作を実行する

enter image description here

ここから、輪郭を見つけ、最小/最大しきい値領域でcv2.contourArea()を使用してフィルタリングします。

enter image description here

Numpyスライスを使用して希望の各正方形領域をトリミングし、このように各ROIを保存できます

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

その余分な情報は完全に黄金です。はい、サイコロの5x5マトリックスを考えると、ポジションを非常にうまく釘付けにすることができます。あなたがサイコロcanを指定すると、サイコロの中心、サイズ、および向きがわかります。両方の軸に沿ってこれらのパターンを続けるだけです。 2番目のパスでは、ダウスのエッジが見つかると予想される各「関心領域」のコントラストを上げます(決して死ぬことはありません!)。数ピクセル以内でエッジがどこにあるかがわかります。これらのエッジを特定するまで画像を減衰させます。

0
Prune