删除图像中的水平线(OpenCV、Python、Matplotlib)

时间:2023-02-07
本文介绍了删除图像中的水平线(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行,列 = 水平形状#反转图像,使线条为黑色以进行遮罩Horizo​​ntal_inv = cv2.bitwise_not(水平)#perform bitwise_and 用提供的掩码掩码行masked_img = cv2.bitwise_and(img, img, mask=horizo​​ntal_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, (horizo​​ntalsize,1))水平= cv2.erode(水平,水平结构,(-1,-1))水平 = cv2.扩张(水平,水平结构,(-1,-1))cv2.imshow(水平",水平)cv2.imwrite("horizo​​ntal.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,horizo​​ntal_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,horizo​​ntal_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()
    

    这篇关于删除图像中的水平线(OpenCV、Python、Matplotlib)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!

上一篇:使用 pytesseract OCR 识别图像中的文本 下一篇:OpenCV 错误:(-215)size.width>0 &amp;&amp;函数i

相关文章

最新文章