有什么办法可以找到多张图片的边界并分别裁剪掉它们吗?
Is there any way we can find boundaries of multiple images and crop them out individually?
有什么方法可以找到多张图片的边界并分别裁剪掉它们。当可以在矩形框中对称裁剪单个图像时,我能够裁剪单个图像,但是当要裁剪的图像不对称时,它变得具有挑战性。在所附的图像中有两个图像,即 "detail B" 和 "detail C"。我只是想将它们裁剪成两个单独的图像。谁能建议如何使用 Python 获取这些图像?
一般方法很简单:
- 逆二进制阈值图像的灰度版本,例如使用大津的方法。因为你有 all-white 背景,这应该没问题。
- 到 "merge" 所有相邻部分,即 "detail" 本身、线条和标题,扩大阈值处理得到的蒙版。
- 找到所有外部轮廓,过滤最大的,然后一个接一个:在单独的蒙版上绘制填充轮廓,并设置原始图像的线性组合,蒙版为白色,all-white 图片,其中mask为黑色;通过找到轮廓的边界矩形来裁剪正确的部分。
下面是一些 Python 使用 OpenCV 和 NumPy 的代码:
import cv2
import numpy as np
from skimage import io # Only needed for web grabbing images
# Read image from web
image = cv2.cvtColor(io.imread('https://i.stack.imgur.com/rq12v.jpg'), cv2.COLOR_RGB2BGR)
# Inverse binary threshold grayscale version of image using Otsu's
thres = cv2.threshold(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Dilate to merge all neighbouring parts
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
thres = cv2.dilate(thres, kernel)
# Find external contours with respect to OpenCV version
cnts = cv2.findContours(thres, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# Iterate all contours...
area_thr = 10000
k = 0
for c in cnts:
# Filter large contours
if cv2.contourArea(c) > area_thr:
k = k + 1
# Get bounding rectangle of contour
rect = cv2.boundingRect(c)
x1 = rect[0]
y1 = rect[1]
x2 = x1 + rect[2]
y2 = y1 + rect[3]
# Generate filled contour mask
mask = np.zeros((thres.shape[0], thres.shape[1], 3), np.uint8)
mask = cv2.drawContours(mask, [c], -1, (1, 1, 1), cv2.FILLED)
# Generate and save cropped image
crop = 255 * np.ones((thres.shape[0], thres.shape[1], 3), np.uint8)
crop = (1 - mask) * crop + mask * image
crop = crop[y1:y2, x1:x2]
cv2.imwrite('crop' + str(k) + '.png', crop)
阈值化和扩张后的初始掩码如下所示:
我们看到六个部分,而两个 "details" 明显更大。
裁剪的两个 "details" 是:
希望对您有所帮助!
------------------
System information
------------------
Python: 3.8.1
NumPy: 1.18.1
OpenCV: 4.1.2
------------------
有什么方法可以找到多张图片的边界并分别裁剪掉它们。当可以在矩形框中对称裁剪单个图像时,我能够裁剪单个图像,但是当要裁剪的图像不对称时,它变得具有挑战性。在所附的图像中有两个图像,即 "detail B" 和 "detail C"。我只是想将它们裁剪成两个单独的图像。谁能建议如何使用 Python 获取这些图像?
一般方法很简单:
- 逆二进制阈值图像的灰度版本,例如使用大津的方法。因为你有 all-white 背景,这应该没问题。
- 到 "merge" 所有相邻部分,即 "detail" 本身、线条和标题,扩大阈值处理得到的蒙版。
- 找到所有外部轮廓,过滤最大的,然后一个接一个:在单独的蒙版上绘制填充轮廓,并设置原始图像的线性组合,蒙版为白色,all-white 图片,其中mask为黑色;通过找到轮廓的边界矩形来裁剪正确的部分。
下面是一些 Python 使用 OpenCV 和 NumPy 的代码:
import cv2
import numpy as np
from skimage import io # Only needed for web grabbing images
# Read image from web
image = cv2.cvtColor(io.imread('https://i.stack.imgur.com/rq12v.jpg'), cv2.COLOR_RGB2BGR)
# Inverse binary threshold grayscale version of image using Otsu's
thres = cv2.threshold(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Dilate to merge all neighbouring parts
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
thres = cv2.dilate(thres, kernel)
# Find external contours with respect to OpenCV version
cnts = cv2.findContours(thres, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# Iterate all contours...
area_thr = 10000
k = 0
for c in cnts:
# Filter large contours
if cv2.contourArea(c) > area_thr:
k = k + 1
# Get bounding rectangle of contour
rect = cv2.boundingRect(c)
x1 = rect[0]
y1 = rect[1]
x2 = x1 + rect[2]
y2 = y1 + rect[3]
# Generate filled contour mask
mask = np.zeros((thres.shape[0], thres.shape[1], 3), np.uint8)
mask = cv2.drawContours(mask, [c], -1, (1, 1, 1), cv2.FILLED)
# Generate and save cropped image
crop = 255 * np.ones((thres.shape[0], thres.shape[1], 3), np.uint8)
crop = (1 - mask) * crop + mask * image
crop = crop[y1:y2, x1:x2]
cv2.imwrite('crop' + str(k) + '.png', crop)
阈值化和扩张后的初始掩码如下所示:
我们看到六个部分,而两个 "details" 明显更大。
裁剪的两个 "details" 是:
希望对您有所帮助!
------------------
System information
------------------
Python: 3.8.1
NumPy: 1.18.1
OpenCV: 4.1.2
------------------