当前位置: 首页 > 知识库问答 >
问题:

裁剪图像中的所有字符

柳墨一
2023-03-14

我整理了一些代码来从图像中提取所有字符。我从左到右对字符进行排序,并尝试将每个字符裁剪到单独的图像中。并非所有字符都被正确裁剪,其中一些最终大小为零。

import cv2
import numpy as np

def crop_minAreaRect(img, rect):
# https://stackoverflow.com/questions/37177811/crop-rectangle-returned-by-minarearect-opencv-python
    # rotate img
    center = rect[0]
    size = rect[1]
    print("size[0]: " + str(int(size[0])) + ", size[1]: " + str(int(size[1])))
    angle = rect[2]
    print("angle: " + str(angle))
    rows,cols = img.shape[0], img.shape[1]
    M = cv2.getRotationMatrix2D((cols/2,rows/2),angle,1)
    img_rot = cv2.warpAffine(img,M,(cols,rows))

    # rotate bounding box
    rect0 = (rect[0], rect[1], angle) 
    box = cv2.boxPoints(rect0)
    pts = np.int0(cv2.transform(np.array([box]), M))[0]    
    pts[pts < 0] = 0

    # crop
    img_crop = img_rot[pts[1][1]:pts[0][1], pts[1][0]:pts[2][0]]

    w, h = img_crop.shape[0], img_crop.shape[1]
    print("w_cropped: " + str(w) + ", h_cropped: " + str(h))
    return img_crop

def sort_contours(cnts, method="left-to-right"):
# from https://pyimagesearch.com/2015/04/20/sorting-contours-using-python-and-opencv/    
    reverse = False
    i = 0
    if method == "right-to-left" or method == "bottom-to-top":
        reverse = True
    if method == "top-to-bottom" or method == "bottom-to-top":
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),   key=lambda b:b[1][i], reverse=reverse))
    return (cnts, boundingBoxes)    
    
im_name = 'letters.png'
im = cv2.imread(im_name)
im_copy = im.copy()

imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

#cv2.drawContours(im_copy, contours, -1, (0,255,0), 2)
#cv2.imshow("contours", im_copy)

print("num contours: " + str(len(contours)))
i = 0

sorted_cnts, bounding_boxes = sort_contours(contours, method="left-to-right")

for cnt in sorted_cnts:
  size = cv2.contourArea(cnt)
  x,y,w,h = cv2.boundingRect(cnt)
  rect = cv2.minAreaRect(cnt)
#  print(str(rect))
#  if rect[1][0] > 0 and rect[1][1]>0:
  im_cropped = crop_minAreaRect(im, rect)
    
  h,w = im_cropped.shape[0], im_cropped.shape[1]
  if w > h:
    im_cropped = cv2.rotate(im_cropped, cv2.ROTATE_90_CLOCKWISE)  
    
  print("w: " + str(w) + ", h: " + str(h))
  if w>0 and h>0:
    cv2.imshow("cropped" + str(i), im_cropped)
  i += 1
#    cv2.waitKey(0)

cv2.waitKey(0)

共有1个答案

益英逸
2023-03-14

您的crop_minAreaRect函数中似乎存在错误。除了返回crop_minAreaRect之外,我没有进一步调试您的代码,因此根据您的方法可能会或可能不会正确旋转字母,但此更改修复了根本问题。
建议的功能取自以下问题并进行了修改:如何在Python中使用OpenCV拉直图像的旋转矩形区域?

import cv2
import numpy as np


def subimage(image, center, theta, width, height):
    '''
   Rotates OpenCV image around center with angle theta (in deg)
   then crops the image according to width and height.
   '''
    width = int(width)
    height = int(height)
    # Uncomment for theta in radians
    # theta *= 180/np.pi

    shape = (image.shape[1], image.shape[0])  # cv2.warpAffine expects shape in (length, height)

    matrix = cv2.getRotationMatrix2D(center=center, angle=theta, scale=1)
    image = cv2.warpAffine(src=image, M=matrix, dsize=shape)

    x = int(center[0] - width / 2)
    y = int(center[1] - height / 2)

    image = image[y:y + height, x:x + width]

    return image


def sort_contours(cnts, method="left-to-right"):
    # from https://pyimagesearch.com/2015/04/20/sorting-contours-using-python-and-opencv/
    reverse = False
    i = 0
    if method == "right-to-left" or method == "bottom-to-top":
        reverse = True
    if method == "top-to-bottom" or method == "bottom-to-top":
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][i], reverse=reverse))
    return (cnts, boundingBoxes)


im_name = 'letters.png'
im = cv2.imread(im_name)
im_copy = im.copy()

imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cv2.drawContours(im_copy, contours, -1, (0, 255, 0), 2)
cv2.imshow("contours", im_copy)

# print("num contours: " + str(len(contours)))
i = 0

sorted_cnts, bounding_boxes = sort_contours(contours, method="left-to-right")

for cnt in sorted_cnts:
    size = cv2.contourArea(cnt)
    x, y, w, h = cv2.boundingRect(cnt)
    rect = cv2.minAreaRect(cnt)


    im_cropped = subimage(im, center=rect[0], theta=rect[2], width=rect[1][0], height=rect[1][1])

    h, w = im_cropped.shape[0], im_cropped.shape[1]
    if w > h:
        im_cropped = cv2.rotate(im_cropped, cv2.ROTATE_90_CLOCKWISE)

    # print("w: " + str(w) + ", h: " + str(h))
    if w > 0 and h > 0:
        cv2.imshow("cropped" + str(i), im_cropped)
    i += 1
#    cv2.waitKey(0)

cv2.waitKey(0)
 类似资料:
  • 我试图在从图库中选择图像后使用intent来裁剪图像。以下是我的代码片段 在这里,我使用PICK_IMAGE_REQUEST意图句柄调用上面的代码段 由于我在裁剪后使用了相同的意图,即PICK_IMAGE_REQUEST,可能会出现什么问题

  • 我将<code>背景 1.back_xml: 2.瓷砖.xml 现在,我将back.xml设置为< code >背景以< code>LinearLayout工作正常。 我需要有一个圆角,以及它的边框。但是我只有圆角的边框,而不是图像,我的代码中有什么问题吗? 这是我的照片:

  • 本节,我们将裁剪图像的一部分,然后把其结果绘制到画布上。 图3-2 裁剪图像 绘制步骤 按照以下步骤,裁剪图像的一部分,再把结果绘制到画布: 1. 定义画布上下文: window.onload  = function(){ var canvas  = document.getElementById("myCanvas"); var context  = canvas.getContext

  • 问题内容: 如何使用JavaFX 完成Android ? 我有图像视图: 问题答案: 感谢@TravisF的发布,我实现了最后一个解决方案,以使图像始终具有相同的高度,宽度和位置(中心)。

  • 我需要对matlab中的图像执行以下操作: 加载图像 计算图像的FFT(快速傅立叶变换) 将频率分量移到中心 像follow一样裁剪图像(如果图像分辨率为1000x1000,则图像所需的部分类似于以下坐标:100100800800。这是一个较小的图像。(应用过滤器去除高频的想法) 反向移位 傅里叶逆变换 . . . 我的代码如下所示: 问题是,当我想裁剪图像时,我的功能无法裁剪类型为“复杂双”的图

  • 使用 Illustrator 中的“图像裁剪”功能裁剪链接或嵌入的图像。 裁剪图像 您可以在 Illustrator 中裁剪链接或嵌入的图像。在裁剪时,您可以使用直观的构件控件处理选定的图像。“图像裁剪”功能只对当前选定的图像有效。此外,链接的图像在裁剪后会变为嵌入的图像。 注意: 裁剪掉的图像部分会被丢弃,且无法恢复。 在裁剪图像时,无法变换图像。在选择“裁剪图像”选项后,如果您尝试变换图像,则