正如评论中许多人所暗示的那样,最好的方法是反转图像,使黑色文本变为白色,找到图像中所有非零点,然后确定最小跨度边界框将是什么。您可以使用此边界框最终裁剪图像。在这里找轮廓非常昂贵,并且不需要 - 特别是因为您的文本是轴对齐的。您可以使用cv2.findNonZero
和cv2.boundingRect
的组合来完成所需操作。
因此,类似以下内容会起作用:
import numpy as np
import cv2
img = cv2.imread('ws.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255*(gray < 128).astype(np.uint8)
coords = cv2.findNonZero(gray)
x, y, w, h = cv2.boundingRect(coords)
rect = img[y:y+h, x:x+w]
cv2.imshow("Cropped", rect)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite("rect.png", rect)
上述代码恰好阐述了我在开头谈论的内容。我们读取图像,但由于某种原因图像是彩色的,因此我们也将其转换为灰度。其中棘手的部分是代码的第三行,在此我们将低于128强度的像素阈值化,以使暗文本变为白色。然而,这会产生二进制图像,因此我转换为uint8
,然后缩放255。这实质上翻转了文本。
接下来,给定此图像,我们使用cv2.findNonZero
找到所有非零坐标,最后将其输入到cv2.boundingRect
中,它将为您提供边界框的左上角以及宽度和高度。我们最终可以使用这个来裁剪图像。请注意,我们是在原始图像上而不是翻转后的图像上进行操作。我们使用简单的NumPy数组索引来完成裁剪。
最后,我们展示图像以表明其有效性,并将其保存到磁盘。
现在我得到了这张图片:
![enter image description here](https://istack.dev59.com/MP3kk.webp)
对于第二张图片,一个好的方法是先裁剪掉右边框和底部边框。我们可以通过将图像裁剪到该位置来实现。接下来,该图像包含一些非常小的噪点像素,建议使用非常小的内核进行形态学开操作,然后重新执行上述逻辑。
因此:
import numpy as np
import cv2
img = cv2.imread('pg13_gau_preview.png')
img = img[:-20,:-20]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255*(gray < 128).astype(np.uint8)
gray = cv2.morphologyEx(gray, cv2.MORPH_OPEN, np.ones((2, 2), dtype=np.uint8))
coords = cv2.findNonZero(gray)
x, y, w, h = cv2.boundingRect(coords)
rect = img[y:y+h, x:x+w]
cv2.imshow("Cropped", rect)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.imwrite("rect.png", rect)
注意:由于隐私原因,输出图像已被移除
boundingRect
接受轮廓,我需要使用findContour
来找到轮廓吗?如何获取左上角和右下角的黑色像素? - Anthonystd::vector<cv::Point> pts; cv::findNonZero(~gray); cv::Rect roi = cv::boundingRect(pts); cv::Mat1b crop = img(roi);
Python代码也差不多。 - Mikicv2.boundingRect()
。 - Jeru Lukeimg = cv2.imread("ws.png"); gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY); coords = cv2.findNonZero(gray); rekt = cv2.boundingRect(coords) cv2.imwrite("rekt.png",rekt)
- Anthonycv2.boundingRect
返回的是边界框坐标,而不是裁剪后的图像。 - rayryeng