删除图像中的水平线(OpenCV、Python、Matplotlib)
问题描述
使用以下代码,我可以删除图像中的水平线.见下面的结果.
导入 cv2从 matplotlib 导入 pyplot 作为 pltimg = cv2.imread('image.png',0)拉普拉斯= cv2.拉普拉斯(img,cv2.CV_64F)sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)plt.subplot(2,2,1),plt.imshow(img,cmap = '灰色')plt.title('Original'), plt.xticks([]), plt.yticks([])plt.subplot(2,2,2),plt.imshow(拉普拉斯,cmap = '灰色')plt.title('拉普拉斯'), plt.xticks([]), plt.yticks([])plt.subplot(2,2,3),plt.imshow(sobelx,cmap = '灰色')plt.title('Sobel X'), plt.xticks([]), plt.yticks([])plt.show()
结果还不错,不是很完美,但是很好.我想要实现的是
我的一个问题是:如何在不应用灰色效果的情况下保存 Sobel X
?作为原始但经过处理..
另外,有没有更好的方法呢?
编辑
对源图像使用以下代码很好.效果很好.
导入 cv2将 numpy 导入为 npimg = cv2.imread("image.png")img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)img = cv2.bitwise_not(img)th2 = cv2.adaptiveThreshold(img,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,-2)cv2.imshow("th2", th2)cv2.imwrite("th2.jpg", th2)cv2.waitKey(0)cv2.destroyAllWindows()水平 = th2垂直 = th2行,列 = 水平形状#反转图像,使线条为黑色以进行遮罩Horizontal_inv = cv2.bitwise_not(水平)#perform bitwise_and 用提供的掩码掩码行masked_img = cv2.bitwise_and(img, img, mask=horizontal_inv)#反转图像恢复正常masked_img_inv = cv2.bitwise_not(masked_img)cv2.imshow("屏蔽的图像", masked_img_inv)cv2.imwrite("result2.jpg", masked_img_inv)cv2.waitKey(0)cv2.destroyAllWindows()水平尺寸 = int(cols/30)水平结构 = cv2.getStructuringElement(cv2.MORPH_RECT, (horizontalsize,1))水平= cv2.erode(水平,水平结构,(-1,-1))水平 = cv2.扩张(水平,水平结构,(-1,-1))cv2.imshow(水平",水平)cv2.imwrite("horizontal.jpg", 水平)cv2.waitKey(0)cv2.destroyAllWindows()垂直尺寸 = int(行数/30)verticalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (1, verticalsize))垂直= cv2.erode(垂直,垂直结构,(-1,-1))垂直= cv2.dilate(垂直,垂直结构,(-1,-1))cv2.imshow(垂直",垂直)cv2.imwrite("vertical.jpg", 垂直)cv2.waitKey(0)cv2.destroyAllWindows()垂直 = cv2.bitwise_not(垂直)cv2.imshow("vertical_bitwise_not", 垂直)cv2.imwrite("vertical_bitwise_not.jpg", 垂直)cv2.waitKey(0)cv2.destroyAllWindows()#步骤1边缘 = cv2.adaptiveThreshold(垂直,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,-2)cv2.imshow(边缘",边缘)cv2.imwrite("edges.jpg", 边缘)cv2.waitKey(0)cv2.destroyAllWindows()#第2步kernel = np.ones((2, 2), dtype = "uint8")扩张= cv2.扩张(边缘,内核)cv2.imshow(扩张",扩张)cv2.imwrite(扩张的.jpg",扩张)cv2.waitKey(0)cv2.destroyAllWindows()# 第三步平滑 = vertical.copy()#步骤4平滑 = cv2.blur(平滑,(4,4))cv2.imshow("平滑", 平滑)cv2.imwrite("smooth.jpg", 平滑)cv2.waitKey(0)cv2.destroyAllWindows()#步骤 5(行,列)= np.where(img == 0)垂直[行,列] = 平滑[行,列]cv2.imshow("vertical_final", 垂直)cv2.imwrite("vertical_final.jpg", 垂直)cv2.waitKey(0)cv2.destroyAllWindows()
但是如果我有这张图片呢?
我尝试执行上面的代码,结果真的很差……
我正在处理的其他图像是这些......
解决方案这是一种方法
将图像转换为
image = cv2.imread('1.png')灰色 = cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY)thresh = cv2.threshold(灰色, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
接下来我们创建一个特殊的水平内核来检测水平线.我们将这些线条绘制到蒙版上,然后在蒙版上找到轮廓.为了去除线条,我们用白色填充轮廓
检测到的线
面具
填充轮廓
# 删除水平水平内核 = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))检测到的线= cv2.morphologyEx(thresh,cv2.MORPH_OPEN,horizontal_kernel,迭代=2)cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] 如果 len(cnts) == 2 否则 cnts[1]对于 cnts 中的 c:cv2.drawContours(图像,[c],-1,(255,255,255),2)
图像当前有间隙.为了解决这个问题,我们构建了一个垂直内核来修复图像
# 修复图片repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,6))结果 = 255 - cv2.morphologyEx(255 - 图像,cv2.MORPH_CLOSE,repair_kernel,迭代 = 1)
<块引用>
注意根据映像,内核的大小会有所变化.例如,为了检测更长的行,我们可以使用
(50,1)
内核.如果我们想要更粗的线条,我们可以增加第二个参数为(50,2)
.这是其他图片的结果
检测到的线
原始(左),删除(右)
检测到的线
原始(左),删除(右)
完整代码
导入 cv2图像 = cv2.imread('1.png')灰色 = cv2.cvtColor(图像,cv2.COLOR_BGR2GRAY)thresh = cv2.threshold(灰色, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]# 删除水平水平内核 = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))检测到的线= cv2.morphologyEx(thresh,cv2.MORPH_OPEN,horizontal_kernel,迭代=2)cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = cnts[0] 如果 len(cnts) == 2 否则 cnts[1]对于 cnts 中的 c:cv2.drawContours(图像,[c],-1,(255,255,255),2)# 修复图像repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,6))结果 = 255 - cv2.morphologyEx(255 - 图像,cv2.MORPH_CLOSE,repair_kernel,迭代 = 1)cv2.imshow('thresh', thresh)cv2.imshow('detected_lines', detected_lines)cv2.imshow('图像', 图像)cv2.imshow('结果', 结果)cv2.waitKey()
Using the following code I can remove horizontal lines in images. See result below.
import cv2 from matplotlib import pyplot as plt img = cv2.imread('image.png',0) laplacian = cv2.Laplacian(img,cv2.CV_64F) sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5) plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray') plt.title('Original'), plt.xticks([]), plt.yticks([]) plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray') plt.title('Laplacian'), plt.xticks([]), plt.yticks([]) plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray') plt.title('Sobel X'), plt.xticks([]), plt.yticks([]) plt.show()
The result is pretty good, not perfect but good. What I want to achieve is the one showed here. I am using this code.
Source image..
One of my questions is: how to save the
Sobel X
without that grey effect applied ? As original but processed..Also, is there a better way to do it ?
EDIT
Using the following code for the source image is good. Works pretty well.
import cv2 import numpy as np img = cv2.imread("image.png") img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) img = cv2.bitwise_not(img) th2 = cv2.adaptiveThreshold(img,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,15,-2) cv2.imshow("th2", th2) cv2.imwrite("th2.jpg", th2) cv2.waitKey(0) cv2.destroyAllWindows() horizontal = th2 vertical = th2 rows,cols = horizontal.shape #inverse the image, so that lines are black for masking horizontal_inv = cv2.bitwise_not(horizontal) #perform bitwise_and to mask the lines with provided mask masked_img = cv2.bitwise_and(img, img, mask=horizontal_inv) #reverse the image back to normal masked_img_inv = cv2.bitwise_not(masked_img) cv2.imshow("masked img", masked_img_inv) cv2.imwrite("result2.jpg", masked_img_inv) cv2.waitKey(0) cv2.destroyAllWindows() horizontalsize = int(cols / 30) horizontalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (horizontalsize,1)) horizontal = cv2.erode(horizontal, horizontalStructure, (-1, -1)) horizontal = cv2.dilate(horizontal, horizontalStructure, (-1, -1)) cv2.imshow("horizontal", horizontal) cv2.imwrite("horizontal.jpg", horizontal) cv2.waitKey(0) cv2.destroyAllWindows() verticalsize = int(rows / 30) verticalStructure = cv2.getStructuringElement(cv2.MORPH_RECT, (1, verticalsize)) vertical = cv2.erode(vertical, verticalStructure, (-1, -1)) vertical = cv2.dilate(vertical, verticalStructure, (-1, -1)) cv2.imshow("vertical", vertical) cv2.imwrite("vertical.jpg", vertical) cv2.waitKey(0) cv2.destroyAllWindows() vertical = cv2.bitwise_not(vertical) cv2.imshow("vertical_bitwise_not", vertical) cv2.imwrite("vertical_bitwise_not.jpg", vertical) cv2.waitKey(0) cv2.destroyAllWindows() #step1 edges = cv2.adaptiveThreshold(vertical,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,-2) cv2.imshow("edges", edges) cv2.imwrite("edges.jpg", edges) cv2.waitKey(0) cv2.destroyAllWindows() #step2 kernel = np.ones((2, 2), dtype = "uint8") dilated = cv2.dilate(edges, kernel) cv2.imshow("dilated", dilated) cv2.imwrite("dilated.jpg", dilated) cv2.waitKey(0) cv2.destroyAllWindows() # step3 smooth = vertical.copy() #step 4 smooth = cv2.blur(smooth, (4,4)) cv2.imshow("smooth", smooth) cv2.imwrite("smooth.jpg", smooth) cv2.waitKey(0) cv2.destroyAllWindows() #step 5 (rows, cols) = np.where(img == 0) vertical[rows, cols] = smooth[rows, cols] cv2.imshow("vertical_final", vertical) cv2.imwrite("vertical_final.jpg", vertical) cv2.waitKey(0) cv2.destroyAllWindows()
But if I have this image ?
I tried to execute the code above and the result is really poor...
Other images which I am working on are these...
解决方案Here's an approach
Convert image to grayscale
Otsu's threshold to get binary image
Create special horizontal kernel and morph open to detect horizontal lines
Find contours on mask and "fill in" the detected horizontal lines with white to effectively remove horizontal lines
Create vertical kernel and repair image with morph close
After converting to grayscale, we Otsu's threshold to obtain a binary image
image = cv2.imread('1.png') gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
Next we create a special horizontal kernel to detect horizontal lines. We draw these lines onto a mask and then find contours on the mask. To remove the lines, we fill in the contours with white
Detected lines
Mask
Filled in contours
# Remove horizontal horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1)) detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: cv2.drawContours(image, [c], -1, (255,255,255), 2)
The image currently has gaps. To fix this, we construct a vertical kernel to repair the image
# Repair image repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,6)) result = 255 - cv2.morphologyEx(255 - image, cv2.MORPH_CLOSE, repair_kernel, iterations=1)
Note depending on the image, the size of the kernel will change. For instance, to detect longer lines, we could use a
(50,1)
kernel instead. If we wanted thicker lines, we could increase the 2nd parameter to say(50,2)
.Here's the results with the other images
Detected lines
Original (left), removed (right)
Detected lines
Original (left), removed (right)
Full code
import cv2 image = cv2.imread('1.png') gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # Remove horizontal horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1)) detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: cv2.drawContours(image, [c], -1, (255,255,255), 2) # Repair image repair_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1,6)) result = 255 - cv2.morphologyEx(255 - image, cv2.MORPH_CLOSE, repair_kernel, iterations=1) cv2.imshow('thresh', thresh) cv2.imshow('detected_lines', detected_lines) cv2.imshow('image', image) cv2.imshow('result', result) cv2.waitKey()
相关文章