问题描述
拥有如上图所示的图像,我可以将其裁剪成四个方形框,使用 OpenCV 形态学操作(基本膨胀、腐蚀)去除边框并得到如下结果:
Having an image such as one above, I am able to crop it into four square boxes, remove the borders using OpenCV morphological operations (basic dilation, erosion) and get a result such as:
这在大多数情况下效果很好,但如果有人越界写,这可能会被预测为 7 而不是 2.
Which works great in most cases, but if someone writes over the line, this may get predicted as 7 instead of 2.
我无法找到一种解决方案,该解决方案可以在删除边框的同时恢复写在线条上的字符部分.我拥有的图像已经转换为灰度,因此我无法根据颜**分书写数字.解决这个问题的最佳方法是什么?
I am having trouble finding a solution that would recover the parts of the character written over the line while removing the borders. Images I have are already converted to grayscale so I can't distinguish written digits based on the color. What would be the best way to approach this problem?
推荐答案
这是一个管道
- 将图像转换为灰度
- Otsu 获取二值图像的阈值
- 去除竖线
- 去除水平线
- 构建修复内核和修复镜像
- 反转图像
转为灰度后,我们大津的阈值
After converting to grayscale, we Otsu's threshold
从这里我们删除垂直线
然后去掉水平线
这给我们留下了字符间隙,为了解决这个问题,我们创建了一个修复内核来扩大图像
This leaves us with a gap in the characters, to fix this, we create a repair kernel to dilate the image
接下来我们使用阈值图像来保持我们的角色细节
Next we bitwise-and with the thresholded image to maintain our character detail
差距仍然存在,但要好一些.我们执行 morph close 以缩小差距
The gap is still there but a little better. We perform morph close to close the gap
它现在已经关闭,但我们丢失了角色细节.我们使用阈值图像执行最终的逐位与运算以恢复我们的细节
It's now closed but we lost character detail. We perform a final bitwise-and with the thresholded image to recover our detail
为了得到想要的结果,我们反转图像
To get the desired result, we invert the image
import cv2 image = cv2.imread('1.png') removed = image.copy() gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # Remove vertical lines vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,40)) remove_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) cnts = cv2.findContours(remove_vertical, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: cv2.drawContours(removed, [c], -1, (255,255,255), 15) # Remove horizontal lines horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40,1)) remove_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) cnts = cv2.findContours(remove_horizontal, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: cv2.drawContours(removed, [c], -1, (255,255,255), 5) # Repair kernel repair_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) removed = 255 - removed dilate = cv2.dilate(removed, repair_kernel, iterations=5) dilate = cv2.cvtColor(dilate, cv2.COLOR_BGR2GRAY) pre_result = cv2.bitwise_and(dilate, thresh) result = cv2.morphologyEx(pre_result, cv2.MORPH_CLOSE, repair_kernel, iterations=5) final = cv2.bitwise_and(result, thresh) invert_final = 255 - final cv2.imshow('thresh', thresh) cv2.imshow('removed', removed) cv2.imshow('dilate', dilate) cv2.imshow('pre_result', pre_result) cv2.imshow('result', result) cv2.imshow('final', final) cv2.imshow('invert_final', invert_final) cv2.waitKey()