边缘的梯度 Python

Posted

技术标签:

【中文标题】边缘的梯度 Python【英文标题】:Gradient of edges Python 【发布时间】:2019-02-26 16:10:19 【问题描述】:

我有一个包含两类图像的数据集:城市景观和景观。我想做的是计算每个图像边缘的梯度(方向),并显示城市景观图像比风景图像具有更多的垂直/水平边缘。

我所做的是计算垂直、水平、45 度和 135 度边缘。我对图像应用了 Canny 过滤器,计算了 x,y 梯度,并对图像应用了一个阈值,表明它显示了高于该阈值的边缘。此处可以看到此阈值的结果:

这是我用于此图像处理以及计算渐变的代码:

def gradient(image):    

    # Step 1
    img = image
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    # Step 2
    bi = cv2.bilateralFilter(gray, 15, 75, 75)

    # Step 3
    dst = cv2.Canny(bi, 100, 200)
    #print(np.count_nonzero(dst))  #--> make sure it's not all zeroes

    # Step 4
    #--- create a black image to see where those edges occur ---
    mask = np.zeros_like(gray)

    #--- applying a threshold and turning those pixels above the threshold to white ---           
    mask[dst > 0.1 * dst.max()] = 255

    # Step 5
    img[dst > 0.1 * dst.max()] = [255, 0, 0]   #--- [255, 0, 0] --> Red ---

    Gx = cv2.Sobel(mask,cv2.CV_64F,1,0,ksize=5)
    Gy = cv2.Sobel(mask,cv2.CV_64F,0,1,ksize=5)

    #orientation of the edges
    theta = np.arctan2(Gy, Gx)

    #magnitude
    M = np.sqrt(Gx*Gx + Gy*Gy)

    #Vertical edges: 
    v = abs(Gy)

    #Horizontal edges: 
    h = abs(Gx)

    #45 Degree edges: 
    deg45 = M*abs(np.cos(theta - np.pi/4))

    #135 Degree edges: 
    deg135 = M*abs(np.cos(theta - 3*np.pi/4))

    print('Vertical:')
    #print(v)
    print(np.count_nonzero(v))
    print('Horizontal:')
    #print(h)
    print(np.count_nonzero(h))

我想要的是为上图中显示为红色的边缘计算v,h,deg45,deg135(第 5 步)。如果这是不可能的,那么对带有白色边缘的图像执行此操作(步骤 4)。有人可以帮忙吗?

编辑:为了避免混淆,我想做的是获取给定图像中垂直、水平等边缘的数量,以便我可以比较城市景观与景观的这些数字图片。

【问题讨论】:

你能解释一下“计算边缘的 v,h,deg45,deg135”是什么意思吗? 我有垂直、水平、45 度和 135 度角梯度的公式。我要做的是对图像中的每个红色边缘,找到边缘的梯度,然后计算每个图像的垂直、水平等的数量 垂直、水平等渐变是什么意思?梯度是一个向量,不应该随方向改变。是否要在 (0,1)、(1,0)、(1,1) 和 (1,-1) 方向上投影渐变? 你是对的。我的意思是我想计算图像中有多少垂直边缘。 (如果这样更清楚) 垂直边缘是否需要精确的水平渐变?水平在 +/-5 度以内? 15度?您是否已经定义了边缘或仅定义了像素梯度?你更关心垂直边的总长度还是垂直边的总数(总长度很容易,但总数可能需要你运行某种聚类算法)? 【参考方案1】:

如果您想要的是包含水平边缘和垂直边缘的像素总数,我建议为水平边缘和垂直边缘定义一些阈值(比如 15 度)。所以你可以计算theta的元素数量 abs(theta) < pi/12(横向) 或abs(theta) > pi-pi/12(水平) 或pi/2 - pi/12 < abs(theta) < pi/2+pi/12(垂直)

您在vh 中存储的是每个点的渐变的垂直和水平分量,您需要比较vh 的值以确定每个点如果梯度向量应计为水平或垂直。比较 theta 可能是最直观的方法。

为了获得满足特定条件的 theta 元素的数量,我建议使用generator expression:

sum(1 for i in theta if (abs(i)<pi/12) or (abs(i)>pi-pi/12))

例如,会给你水平边缘像素的数量。

【讨论】:

感谢您的回答。我将如何应用此阈值?我会使用 if 条件来应用您在上面定义的条件吗? 有很多方法可以做到这一点。您可以遍历 theta 并使用 if 语句。您可以放弃 if 语句,只需将布尔表达式的结果添加到计数器(1 表示真,0 表示假)。您也可以使用生成器表达式,我认为这是最快的方法。我编辑了答案以包含该方法的示例。 您能解释一下为什么要计算 theta 以获得水平/垂直边缘吗?此外,在您编写的生成器表达式中,如果 i 满足条件并遍历 theta 中的所有值并将这些 1 相加,您所做的是得到 1? 我正在计算属于水平或垂直边缘的像素,所以最后你会得到水平或垂直边缘的总长度(或它的一个很好的近似值)。如果您想计算边缘的数量而不管长度如何,那么您必须以某种方式将像素分组为边缘。完成此操作后,您可以按照与上述相同的方式计算它们,您只需使用每个边缘与每个像素的 theta。【参考方案2】:

如果您想计算或控制图像中有多少线性特征,我认为霍夫变换更适合您的需求,您可以计算每个特定方向(在霍夫空间中)有多少线性特征。一旦您使用 Python,this 和 this 链接可能会有所帮助!

【讨论】:

以上是关于边缘的梯度 Python的主要内容,如果未能解决你的问题,请参考以下文章

3. OpenCV-Python——图像梯度算法边缘检测图像金字塔与轮廓检测直方图与傅里叶变换

3. OpenCV-Python——图像梯度算法边缘检测图像金字塔与轮廓检测直方图与傅里叶变换

OpenCV图像处理应用(面向Python)之图像梯度与Canny边缘检测

OpenCV图像处理应用(面向Python)之图像梯度与Canny边缘检测

opencv python:图像梯度

图像分析:边缘检测中的梯度算子