这是一个可能的解决方案。它涉及从输入图像的几行中选择一个样本,然后使用cv2.reduce 函数将样本减少为一个行图像。循环通过减少的行并查找从0 到255 的像素强度跳跃,因为该转换表示您用于指导裁剪的页面区域。最后,将跳转的位置存储在列表中,以进一步裁剪图像中的页面。这些是步骤:
- 从图像中获取样本 ROI
-
减少样本 ROI 为大小为
1 x width 的行图像,在MAX 模式下使用cv2.reduce 函数得到每列的最大强度值
- 遍历图像并寻找从
0 到255 的强度转换 - 这个点是垂直线所在的位置
-
在
list 中存储每个“转换位置”
-
使用“过渡位置”列表中的信息裁剪图像
让我们看看代码:
# Imports:
import numpy as np
import cv2
# Set the image path
path = "D://opencvImages//"
fileName = "mx8lW.jpg"
# Read the image in default mode:
inputImage = cv2.imread(path + fileName)
# Convert RGB to grayscale:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Set the sample ROI and crop it:
(imageHeight, imageWidth) = grayscaleImage.shape[:2]
roiX = 0
roiY = int(0.05 * imageHeight)
roiWidth = imageWidth
roiHeight = int(0.05 * imageHeight)
# Crop the image:
imageRoi = grayscaleImage[roiY:roiY+roiHeight, roiX:roiWidth]
第一位读取图像,将其从BGR 转换为grayscale 并定义样本ROI。此 ROI 用于定位垂直线。由于图像中的垂直线是恒定的,因此只需选择和裁剪一个样本就可以了,而不是处理整个图像。我定义的 ROI 选择了图像顶部正下方的区域,因为有一些暗部可能会影响 ROI 减少为一行。
此图像显示了选定的 ROI,用绿色矩形绘制:
请注意,两条(最左侧和最右侧)垂直线在 ROI 内清晰显示。如果我们裁剪它,我们将得到这个示例图像:
我们需要裁剪页面的所有信息都在那里。让我们threshold 图像来获得二进制掩码:
# Thresholding:
_, binaryImage = cv2.threshold(imageRoi, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
这是二进制掩码:
注意从0 到255 的跳转以及它们的含义。每个过渡都表示我们可以用来裁剪两个页面的起点和终点。好的,让我们将reduce 二进制掩码设置为一行。我们将使用MAX模式,其中行中的每个像素值都定义为该图像列对应的最大强度值:
# Reduce the ROI to a 1 x imageWidth row:
reducedImg = cv2.reduce(binaryImage, 0, cv2.REDUCE_MAX)
这是生成的图像,只是一行:
让我们遍历这张图片(实际上只是一个普通的numpy 数组)并寻找那些转换。此外,让我们准备一个列表并在我们找到它们时存储跳转位置:
# Store the transition positions here:
linePositions = []
# Find transitions from 0 to 255:
pastPixel = 255
for x in range(reducedImg.shape[1]):
# Get current pixel:
currentPixel = reducedImg[0,x]
# Check for the "jumps":
if currentPixel == 255 and pastPixel == 0:
# Store the jump locations in list:
print("Got Jump at:"+str(x))
linePositions.append(x)
# Set current pixel to past pixel:
pastPixel = currentPixel
酷,我们在linePositions 中准备好了跳跃位置。让我们最后裁剪图像。我已经通过位置列表实现了这种循环并设置了裁剪参数:
# Crop pages:
for i in range(len(linePositions)):
# Get top left:
cropX = linePositions[i]
# Get top left:
if i != len(linePositions)-1:
# Get point from the list:
cropWidth = linePositions[i+1]
else:
# Set point from the image's original width:
cropWidth = reducedImg.shape[1]
# Crop page:
cropY = 0
cropHeight = imageHeight
currentCrop = inputImage[cropY:cropHeight,cropX:cropWidth]
# Show current crop:
cv2.imshow("CurrentCrop", currentCrop)
cv2.waitKey(0)
生产两种作物: