一 项目概要
在网上找图片素材时,有很多的图片是长图片,在一张图片上拼接了许多张图片,而很多时候我们需要单张图片,此时就需要将长图进行裁剪,一般可以用图片工具进行简单裁剪,高级点可以采用ps进行切片处理,如果图片数量少还好说一旦有大量的图片需要裁剪就很繁琐并且费时费力。这时就会想用自动裁剪工具进行裁剪,而网上的大多数工具都是定尺寸裁剪需要手动输入裁剪位置,这种还是没法实现自动识别图片间的分界线并裁剪的操作。而此时想起曾学习过一点机器视觉的内容,就尝试用python和opencv实现整个操作过程,来识别图片分界线并自动裁剪保存。
二 项目流程
实现这个过程的大致流程是先扫描给定文件下的所有文件,对扫描出来的文件名进行取后缀处理,将文件后缀与图片类型进行比对,如是图像文件则先将图片转换为灰度图然后去噪,再进行边缘轮廓提取,得到图像边缘轮廓后可以进行图像形态学处理使得分界线更明显,再运用霍夫直线变换进行直线检测,对直线检测的结果进行处理只留下水平直线,将直线的纵坐标提取并以升序排序,排序后进行裁剪保存,如此循环直到将文件夹下的图像文件处理完。而实现以上过程的难点就在于提取出图 片的轮廓。
三 图像边缘提取
由于需要提取图片的边缘轮廓,想到可以用Sobel算子进行处理。图像梯度计算的是图像变化的速度,对于图像的边缘部分,其灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情况下,图像梯度计算的是图像的边缘信息。Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。我们想要得到的是水平分界线,可以计算水平垂直方向的偏导数从而得到边缘轮廓。
在opencv中应用sobel算子计算计算图像梯度
import cv2
import numpy as np
# 加载图片并转换为灰度图
img = cv2.imread(r"D:\Image\lsfjlejljlkk (2).jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 对灰度图进行高斯模糊
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 使用Sobel算子计算梯度
grad_x = cv2.Sobel(blurred, cv2.CV_16S, 1, 0)
grad_y = cv2.Sobel(blurred, cv2.CV_16S, 0, 1)
# 将梯度转换为绝对值
abs_grad_x = cv2.convertScaleAbs(grad_x)
abs_grad_y = cv2.convertScaleAbs(grad_y)
# 合并梯度
grad = cv2.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)
# 对梯度进行二值化处理
thresh,binary=cv2.threshold(grad,80,255,cv2.THRESH_BINARY)
cv2.imwrite(r"D:\Image\lsfjlejljlkk (2).jpg", binary,[cv2.IMWRITE_JPEG_QUALITY,98])
图片处理后的结果
除了应用sobel算子还可以使用Canny 边缘检测
import cv2
import numpy as np
# 加载图片并转换为灰度图
img = cv2.imread(r"D:\Image\lsfjlejljlkk (2).jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#cany处理
cany=cv2.Canny(gray, 50, 150, apertureSize=3)
cv2.imwrite(r"D:\Image\lsfjlejljlkk (3).jpg", cany,[cv2.IMWRITE_JPEG_QUALITY,98])
从以上结果可以看出来不管是用sobel还是cany,处理后的图像都能明显找出分界线,但仔细观察就会发现图像中除了有分界线还有其他元素,并且分界线不是很连续有锯齿状,可以考虑使用形态学进行处理,先对图像进行膨胀后在进行腐蚀
import cv2
import numpy as np
# 加载图片并转换为灰度图
img = cv2.imread(r"D:\Image\46777cb7e3ae46d6b724b377a6dac721.jpeg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray_filtering=cv2.GaussianBlur(gray,(3,3),0,0)
cany = cv2.Canny(gray_filtering, 50, 150, apertureSize=3)
kernel = np.ones((2, 9), np.uint8)
kernel1 = np.ones((1, 40), np.uint8)
cany = cv2.dilate(cany, kernel, iterations=2)
cany = cv2.erode(cany, kernel1, iterations=3) # 腐蚀
kernel = np.ones((5, 1), np.uint8)
morphology1 = cv2.erode(cany, kernel, iterations=5)
morphology2 = cv2.subtract(cany, morphology1)#相减除去多余元素
cv2.imwrite(r"D:\Image\lsfjlejljlkk (5).jpg", morphology2,[cv2.IMWRITE_JPEG_QUALITY,98]