用Canny

时间:2018-07-04 08:29:53

标签: python opencv edge-detection canny-operator

我试图在一系列图像中找到倾斜角度,这些图像看起来像下面创建的示例数据。应该有一个肉眼可见的清晰边缘。但是到目前为止,我一直在努力提取边缘。 Canny是在此处找到边缘的正确方法,还是在边缘找到更好的方法?

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage.filters import gaussian_filter

# create data
xvals = np.arange(0,2000)
yvals = 10000 * np.exp((xvals - 1600)/200) + 100
yvals[1600:] = 100
blurred = gaussian_filter(yvals, sigma=20)

# create image
img = np.tile(blurred,(2000,1))
img = np.swapaxes(img,0,1)

# rotate image
rows,cols = img.shape
M = cv.getRotationMatrix2D((cols/2,rows/2),3.7,1)
img = cv.warpAffine(img,M,(cols,rows))

# convert to uint8 for Canny
img_8 = cv.convertScaleAbs(img,alpha=(255.0/65535.0))
fig,ax = plt.subplots(3)
ax[0].plot(xvals,blurred)
ax[1].imshow(img)

# find edge
ax[2].imshow(cv.Canny(img_8, 20, 100, apertureSize=5))

sample image for edge detection

4 个答案:

答案 0 :(得分:3)

您可以通过将图像转换为二进制(cv2.threshold(cv2.THRESH_BINARY))然后搜索轮廓来找到角度。

enter image description here

找到轮廓(线)时,可以在轮廓cv2.fitLine()上拟合一条线,并获得该线的两个点。我的数学不是很好,但是我认为在线性方程式中,公式变为f(x) = k*x + n,您可以从这两点(k)中得到k = (y2-y1)/(x2-x1),最后得到角度{{1} }。 (如果我错了,请更正)

您还可以使用旋转的边界矩形-phi = arctan(k)-已经返回矩形的角度(cv2.minAreaRect()-> rect = cv2.minAreaRect())。希望能帮助到你。干杯!

这是示例代码:

rect[2]

原始图片:

enter image description here

输出:

enter image description here

-3.8493663478518627

-3.7022125720977783

答案 1 :(得分:2)

tribol,

似乎可以拍摄渐变图像G = | Gx | + | Gy | (将其归一化到某个已知范围),计算其直方图,并获取其顶部的bin。它会给你大约线的遮罩。然后,您可以进行线拟合。它将给您一个很好的初步猜测。

答案 2 :(得分:0)

一种非常简单的方法如下...调整我的数字以适合您对数据的了解。

将图像规格化为0-255。

选择两个点A和B,其中A是左侧的图像宽度的10%,B是右侧的图像宽度的10%。现在,距离AB为0.8 x 2000或1600像素。

从点A往北走,对图像进行采样,直到超过某个合理的阈值为止,这意味着您已达到倾斜线。请注意,此时的Y值为YA。

做同样的事情,从B点向北走,直到遇到倾斜线。请注意此时的Y值,即YB。

您寻求的角度是:

tan-1((YB-YA)/1600) 

enter image description here

答案 3 :(得分:0)

kavko建议的阈值效果不佳,因为强度随图像的不同而变化(我当然可以考虑每个图像的直方图来改进这种方法)。我最终得到了y方向上的最大梯度:

def rotate_image(image):
    blur = ndimage.gaussian_filter(image, sigma=10)    # blur image first
    grad = np.gradient(blur, axis= 0)    # take gradient along y-axis
    grad[grad>10000]=0    # filter unreasonable high values
    idx_maxline = np.argmax(grad, axis=0)    # get y-indices of max slope = indices of edge

    mean = np.mean(idx_maxline)
    std = np.std(idx_maxline)
    idx = np.arange(idx_maxline.shape[0])
    idx_filtered = idx[(idx_maxline < mean+std) & (idx_maxline > mean - std)]    # filter positions where highest slope is at different position(blobs)
    slope, intercept, r_value, p_value, std_err = stats.linregress(idx_filtered, idx_maxline[idx_filtered])
    out = ndimage.rotate(image,slope*180/np.pi, reshape = False)
    return out
out = rotate_image(img)
plt.imshow(out)

final rotated image