【问题标题】:Python - How to process a binary image to align sparse letters in a rowPython - 如何处理二进制图像以对齐一行中的稀疏字母
【发布时间】:2022-02-19 06:24:56
【问题描述】:

我正在尝试对齐图像中的字母,以便使用 tesseract OCR 获得完整的单词:

import cv2
import numpy as np

img = cv2.imread("captcha.png", 0)
h1, w1 = img.shape
img = cv2.resize(img, (w1*5, h1*5))
# Threshold the image and find the contours
_, thresh = cv2.threshold(img, 123, 255, cv2.THRESH_BINARY_INV)
contours, hierarchy = cv2.findContours(
    thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Create a white background iamge to paste the letters on
bg = np.zeros((200, 200), np.uint8)
bg[:] = 255
left = 5

# Iterate through the contours
for contour, h in zip(contours, hierarchy[0]):
    # Ignore inside parts (circle in a 'p' or 'b')
    if h[3] == -1:
        # Get the bounding rectangle
        x, y, w, h = cv2.boundingRect(contour)
        # Paste it onto the background
        bg[5:5+h, left:left+w] = img[y:y+h, x:x+w]
        left += (w + 5)
cv2.imshow('thresh', bg)
cv2.waitKey()

而我要处理的图片就是这张

但是,我收到了这条消息:

>Traceback (most recent call last):
  File ".\img.py", line 24, in <module>
    bg[5:5+h, left:left+w] = img[y:y+h, x:x+w]
ValueError: could not broadcast input array from shape (72,750) into shape (72,195)  

仅使用 tesseract OCR 我得到了没有零和四的“acba”,所以我需要重新排序字母才能获得它。有什么建议吗?

【问题讨论】:

  • 您收到此错误是因为左侧和右侧和侧面的形状不同。这肯定是因为二维切片超出了数组的边界。
  • 首先您可以使用print() 来检查形状bg[5:5+h, left:left+w].shapeimg[y:y+h, x:x+w].shape。它们必须相同。您可能必须为wh 获取min() 并获取min_w, min_h 并在bg[5:5+min_h, left:left+min_w] = img[y:y+min_h, x:x+min_w] 中使用

标签: python numpy opencv captcha python-tesseract


【解决方案1】:

您尝试将更大的图像放在更小的区域 - 但它们必须相同。

您可以获得两个对象的形状,并获得 min() 的宽度和高度并使用它

        h1, w1 = bg[5:5+h, left:left+w].shape
        h2, w2 = img[y:y+h, x:x+w].shape
        
        min_h = min(h1, h2)
        min_w = min(w1, w2)
        
        bg[5:5+min_h, left:left+min_w] = img[y:y+min_h, x:x+min_w]

编辑:

或者也许您应该使用x,y 而不是5left(也可以使用5

        bg[y:y+h, x:x+w] = img[y:y+h, x:x+w]

也许您应该创建与img 相同大小的bg(调整大小后)

h1, w1 = img.shape

bg = np.zeros((h1, w1), np.uint8)

编辑:

包含其他更改的完整工作代码。

我以 RGB 格式读取图像以查看它发现了什么轮廓,因为它似乎发现了一些与您预期不同的东西。

import cv2
import numpy as np

print('CV:', cv2.__version__)

img_color = cv2.imread("ZzSgt.png", cv2.IMREAD_UNCHANGED)
h, w = img_color.shape[:2]
print('original shape (W,H):', w, h)

img_color = cv2.resize(img_color, (w*5, h*5))
h, w = img_color.shape[:2]
print('resized shape (W,H) :', w, h)

img = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
                       
# Threshold the image and find the contours
_, thresh = cv2.threshold(img, 123, 255, cv2.THRESH_BINARY_INV)

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Create a white background image to paste the letters on
bg = np.full((h, w), 255, np.uint8)

# Create image to display contours 
img_contours = np.full((h, w, 3), 255, np.uint8)

left = 5

# Iterate through the contours
for contour, h in zip(contours, hierarchy[0]):
    # Ignore inside parts (circle in a 'p' or 'b')
    if h[3] == -1:

        # Get the bounding rectangle
        x, y, w, h = cv2.boundingRect(contour)
        print('contour (X,Y,W,H):', x, y, w, h)

        # Paste it onto the background
        h1, w1 = bg[5:5+h, left:left+w].shape
        h2, w2 = img[y:y+h, x:x+w].shape
        
        min_h = min(h1, h2)
        min_w = min(w1, w2)
        
        bg[5:5+min_h, left:left+min_w] = img[y:y+min_h, x:x+min_w]
        
        left += (w + 5)

        # Copy color regions and draw contours        
        img_contours[y:y+h, x:x+w] = img_color[y:y+h, x:x+w]
        img_contours = cv2.drawContours(img_contours, [contour], 0, (0,0,255))

cv2.imshow('contours', img_contours)
cv2.imshow('background', bg)
cv2.waitKey()

cv2.destroyAllWindows()

轮廓

背景


编辑:

如果我修改图像img = ~img 并将阈值从123 更改为30,我会得到更好的结果

阈值

轮廓

背景(现在我发现它的大小甚至可以达到 (75, 255) 或更安全的 (100, 300)

import cv2
import numpy as np

print('CV:', cv2.__version__)

#img_color = cv2.imread("captcha.png", cv2.IMREAD_UNCHANGED)
img_color = cv2.imread("ZzSgt.png", cv2.IMREAD_UNCHANGED)
h, w = img_color.shape[:2]
print('original shape (W,H):', w, h)

img_color = cv2.resize(img_color, (w*5, h*5))
h, w = img_color.shape[:2]
print('resized shape (W,H) :', w, h)

img = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
                       
img = ~img                       
# Threshold the image and find the contours
_, thresh = cv2.threshold(img, 30, 255, cv2.THRESH_BINARY_INV)
cv2.imshow('thresh', thresh)

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Create a white background image to paste the letters on
bg = np.full((h, w), 255, np.uint8)

# Create image to display contours 
img_contours = np.full((h, w, 3), 255, np.uint8)

left = 5

# Iterate through the contours
for contour, h in zip(contours, hierarchy[0]):
    # Ignore inside parts (circle in a 'p' or 'b')
    if h[3] == -1:

        # Get the bounding rectangle
        x, y, w, h = cv2.boundingRect(contour)
        print('contour (X,Y,W,H):', x, y, w, h)

        # Paste it onto the background
        h1, w1 = bg[5:5+h, left:left+w].shape
        h2, w2 = img[y:y+h, x:x+w].shape
        
        min_h = min(h1, h2)
        min_w = min(w1, w2)
        
        bg[5:5+min_h, left:left+min_w] = img[y:y+min_h, x:x+min_w]
        
        left += (w + 5)

        # Copy (color) region and draw contour
        img_contours[y:y+h, x:x+w] = img_color[y:y+h, x:x+w]
        img_contours = cv2.drawContours(img_contours, [contour], 0, (0,0,255))

cv2.imshow('contours', img_contours)
cv2.imshow('background', bg)
cv2.waitKey()

cv2.destroyAllWindows()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-02
    • 2015-02-28
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 2017-12-16
    • 1970-01-01
    • 2020-09-30
    相关资源
    最近更新 更多