我整理了一些代碼來從影像中提取所有字符。我從左到右對字符進行排序,并嘗試將每個字符裁剪成單獨的影像。并非所有字符都被正確裁剪,其中一些字符最終大小為零。

唯一不具有一維零的字符是 BCDEF。這是輸出的影像。

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)
uj5u.com熱心網友回復:
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)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/495777.html
