python - 图像中的正方形检测
问题描述
我正在尝试检测所有方形骰子图像,以便我可以单独裁剪它们并将其用于 OCR。下面是原图:
这是我得到的代码,但它缺少一些方块。
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)
根据我的分析,由于骰子和背景之间的平滑强度过渡,由于骰子缺少精巧的边缘,一些正方形丢失了。
鉴于方形网格图案 (5*5) 中总是有 25 个骰子的限制,我们可以根据识别的正方形预测丢失的正方形位置吗?或者我们可以将上述算法修改为正方形检测算法吗?
解决方案
这是一种方法
用 锐化图像cv2.filter2D()
。我们使用通用的锐化内核,其他内核可以在这里找到
现在获取二值图像的阈值
执行形态学操作
从这里我们找到轮廓并使用cv2.contourArea()
最小/最大阈值区域进行过滤。
我们可以使用 Numpy 切片裁剪每个所需的正方形区域并像这样保存每个 ROI
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
cv2.imwrite('ROI_{}.png'.format(image_number), ROI)
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+w]
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()
推荐阅读
- r - 在 R 中不使用 PAM 创建自己的 k-medoids 算法?
- r - 为什么我的代码会得到不同的结果?
- python - Pandas groupby 分组返回值而不是索引
- css - 从底部到顶部css对图像的渐变效果
- python - 如何将用户定义的类从包导入到 Jupyter Notebook
- jq - 替换列表中的值
- .net-core - 从核心 2.1 升级后无法发布核心 3.1 独立应用程序,nuget 以某种方式失败?构建良好
- java - 多个实体连接
- java - 无法弄清楚如何解决 ArrayIndexOutOfBoundsException: 1
- html - 使图像圆形和特定尺寸而不拉伸,掩盖其余部分