图像中的正方形检测

时间:2019-03-14 18:26:31

标签: python image-processing computer-vision ocr

我正在尝试检测所有方形骰子图像,以便我可以单独裁剪它们并将其用于OCR。 以下是原始图片:

image3 image4

这是我得到的代码,但是缺少一些正方形。

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)

以下是输出图像: Image1 Image2

根据我的分析,由于骰子和背景之间平滑的强度传递,由于缺少沿骰子的Canny边缘,因此缺少一些正方形。

给定约束,即正方形网格图案(5 * 5)中将始终有25个骰子,我们能否基于已识别的正方形来预测丢失的正方形位置? 还是可以将上述算法修改为平方检测算法?

2 个答案:

答案 0 :(得分:3)

这是一种方法

  • 将图像转换为灰度,将中值模糊转换为平滑图像
  • 锐化图像以增强边缘
  • 阈值
  • 进行形态转换
  • 使用最小/最大阈值区域查找轮廓并过滤
  • 裁剪并保存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()

答案 1 :(得分:0)

这些额外的信息绝对是黄金。是的,给定5x5骰子矩阵,您可以很好地固定位置。您可以识别的骰子为您提供骰子的中心,大小和方向。只需沿两个轴继续这些模式。对于第二遍,增加每个“感兴趣区域”的对比度,您希望在该区域找到笔钉的边缘(永远不要说死!)。您知道边缘会在几像素之内:只需衰减图像,直到识别出这些边缘即可。