【问题标题】:How to sharpen the edges in opencv python如何在opencv python中锐化边缘
【发布时间】:2020-03-27 21:52:22
【问题描述】:

我正在学习图像处理,我试图在 python 中使用 opencv 锐化图像的边缘,我已经尽可能地减少了噪点,但现在我想让图像的边缘更清晰,我尝试过cv2.Canny(),但效果不佳。

这是图片

应用 c2.Canny() 后

但我正在尝试使单词边框或边缘更加清晰

这是我的代码

import cv2
import matplotlib.pyplot as plt
img_1 = cv2.imread('noise/1.png',cv2.IMREAD_GRAYSCALE)
edges = cv2.Canny(img_1,200,200)
plt.imshow(edges)

【问题讨论】:

  • 锐化边框是什么意思?由于图像尺寸,您可能无法获得更清晰的图像,它看起来很奇怪,因为您可以看到像素。

标签: python python-3.x opencv image-processing


【解决方案1】:

这是在 Python/OpenCV 中处理该问题的一种方法。

  • 将输入读取为灰度
  • 设置阈值以确保它是二进制的
  • 应用形态关闭
  • 通过在输入中绘制黑色来查找轮廓并移除所有小区域
  • 应用 Canny 边缘检测
  • 保存结果

输入:

import cv2
import numpy as np

# read image as grayscale
img = cv2.imread('K.png', cv2.IMREAD_GRAYSCALE)

# threshold to binary
thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY)[1]

# apply morphology
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

# find contours - write black over all small contours
letter = morph.copy()
cntrs = cv2.findContours(morph, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
for c in cntrs:
    area = cv2.contourArea(c)
    if area < 100:
        cv2.drawContours(letter,[c],0,(0,0,0),-1)

# do canny edge detection
edges = cv2.Canny(letter, 200, 200)

# write results
cv2.imwrite("K_thresh.png", thresh)
cv2.imwrite("K_morph.png", morph)
cv2.imwrite("K_letter.png", letter)
cv2.imwrite("K_edges.png", edges)

# show results
cv2.imshow("K_thresh", thresh)
cv2.imshow("K_morph", morph)
cv2.imshow("K_letter", letter)
cv2.imshow("K_edges", edges)
cv2.waitKey(0)


阈值图像:

已应用形态学公开:

小区域被移除:

精巧的边缘:

【讨论】:

    【解决方案2】:

    首先使用Gaussian blur 去除图像噪声,然后使用自动阈值canny,如下代码:

    def auto_canny(image, sigma=0.33):
        v = np.median(image)
        lower = int(max(0, (1.0 - sigma) * v))
        upper = int(min(255, (1.0 + sigma) * v))
        edged = cv2.Canny(image, lower, upper)
        return edged
    
    def main():
        img_1 = cv2.imread('noise/1.png',cv2.IMREAD_GRAYSCALE)
        blurred = cv2.GaussianBlur(img_1, (3, 3), 0)
        auto_edge = auto_canny(blurred)
        plt.imshow(auto_edge)
    

    希望对你有帮助

    【讨论】:

    • 您的意思是img_1 而不是gray?另外,您为什么要在图像中添加噪点以再次将其去除?
    • 是的,我修好了。图像有噪声,高斯模糊可以去除噪声,有助于边缘检测过程。
    【解决方案3】:

    我查看了接受的答案,觉得这是一个很好的过程,但不需要很多步骤。例如,Canny 在二值图像中不添加任何值。这是一个复杂的过程,旨在检测具有软梯度的图像中的锐利边缘。对于二值图像,Sobel/Laplacian 将给出与 Canny 相同的结果。

    此外,这并不完全是锐化边缘,更像是精炼。

    我的步骤如下:

    1. 图像二值化阈值

    2. 单独应用 erode 和 dilate,因为如果您使用 C/C++ 编写,您可以更好地控制诸如就地与否、内存管理之类的事情。当您进行多次迭代以处理更多噪音时,这一点很重要。

    3. 寻找轮廓。 根据用例,如果你没有循环(比如字母P中的循环),你可以使用find唯一的外部轮廓来优化代码。

    4. 遍历轮廓并从轮廓列表中删除任何低于阈值的轮廓。

    5. 您已经在此处以点列表的形式获得了整个边缘。如果可以,请按原样使用边缘或仅创建一个空白图像并绘制所有厚度为 1 的有效轮廓(仅边缘)

       import cv2
       import numpy as np
      
       # read image as grayscale
       img = cv2.imread('K.png', cv2.IMREAD_GRAYSCALE)
      
       # threshold to binary
       thresh = cv2.threshold(img, 1, 255, cv2.THRESH_BINARY)[1]
      
       # apply morphology.
       kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
       morph = cv2.erode(thresh, kernel)
       morph = cv2.dilate(morph, kernel)
      
       # find contours & draw only valid contour edges on a black image
       letter = np.zeros_like(img)
       cntrs, hier = cv2.findContours(morph, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
       for idx, c in enumerate(cntrs):
           area = cv2.contourArea(c)
           if area > 100:
               cv2.drawContours(letter, cntrs, idx, 255, 1, 8, hier)
      
       # write results
       cv2.imwrite("K_thresh.png", thresh)
       cv2.imwrite("K_morph.png", morph)
       cv2.imwrite("K_letter.png", letter)
      
       # show results
       cv2.imshow("K_thresh", thresh)
       cv2.imshow("K_morph", morph)
       cv2.imshow("K_letter", letter)
       cv2.waitKey(0)
      

    【讨论】:

    • 感谢您提供示例代码。我测试并得到以下错误:----&gt; morph = cv2.erode(thresh, kernel)TypeError: Expected Ptr&lt;cv::UMat&gt; for argument 'src' 调试显示 cv2.threshold 方法返回的不仅仅是图像,所以我可以通过更改“阈值到二进制”行来修复它:r, thresh = cv2.threshold(img, 1, 255, cv2.THRESH_BINARY)
    • 谢谢。我没有在IDE中编写。我刚刚修改了现有的答案,所以我一定错过了。感谢您纠正我的错误。
    • 解决问题后你得到了你想要的吗?........如果我们没有在drawcontour中填充轮廓,我认为甚至不需要层次结构但我只是将它添加安全起见(因为我不知道应用程序)
    猜你喜欢
    • 2017-07-06
    • 2017-08-29
    • 2011-06-26
    • 2013-11-22
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    相关资源
    最近更新 更多