去除图像中的水平线(OpenCV、Python、Matplotlib) [英] Removing Horizontal Lines in image (OpenCV, Python, Matplotlib)

查看:92
本文介绍了去除图像中的水平线(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 = '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()

结果还不错,不完美但很好.我想要实现的是

我的一个问题是:如何在不应用灰色效果的情况下保存 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行,列 = 水平.形状#反转图像,使线条为黑色以进行遮罩水平_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.dilate(水平,水平结构,(-1,-1))cv2.imshow(水平",水平)cv2.imwrite("horizo​​ntal.jpg", 水平)cv2.waitKey(0)cv2.destroyAllWindows()垂直大小 = 整数(行数/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(vertical,255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,3,-2)cv2.imshow(边缘",边缘)cv2.imwrite("edges.jpg", 边缘)cv2.waitKey(0)cv2.destroyAllWindows()#第2步内核 = np.ones((2, 2), dtype = "uint8")扩张 = cv2.dilate(边,核)cv2.imshow(扩张",扩张)cv2.imwrite("dilated.jpg", 膨胀)cv2.waitKey(0)cv2.destroyAllWindows()# 步骤 3平滑 = 垂直.copy()#步骤4平滑 = cv2.blur(smooth, (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(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    接下来我们创建一个特殊的水平内核来检测水平线.我们将这些线绘制到蒙版上,然后在蒙版上找到轮廓.为了去除线条,我们用白色填充轮廓

    检测到的线条

    面具

    填充轮廓

    # 删除水平水平内核 = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))检测到的线 = cv2.morphologyEx(阈值,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 else cnts[1]对于 cnts 中的 c:cv2.drawContours(图像,[c],-1,(255,255,255),2)

    图像当前有间隙.为了解决这个问题,我们构建了一个垂直内核来修复图像

    #修复图片修复内核 = 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(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]# 删除水平水平内核 = cv2.getStructuringElement(cv2.MORPH_RECT, (25,1))检测到的线 = cv2.morphologyEx(阈值,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 else cnts[1]对于 cnts 中的 c:cv2.drawContours(图像,[c],-1,(255,255,255),2)# 修复图像修复内核 = 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


    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)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆