首页 > 解决方案 > OpenCV - 计算图像中两个边缘之间的距离

问题描述

我正在尝试计算图像中两个边缘之间的距离(以像素为单位)。我已经使用cv2.warpPerspective方法校正了图像透视,并将生成的图像转换为灰度,然后使用高斯模糊进行过滤。我尝试了各种阈值方法,发现cv2.ADAPTIVE_THRESH_GAUSSIAN效果最好。如自适应高斯阈值处理的结果所示,其他方法噪声太大或错过对象左侧的第二条边缘。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Load the image
imgRoadvR10 = cv2.imread('sampleimage.jpg') # image is already corrected for perspective warp using cv2.warpPerspective

# convert to grayscale
imgRoadvR10_GrayPersp = cv2.cvtColor(imgRoadvR10, cv2.COLOR_BGR2GRAY)

# gaussian blur
a10lvR10_gblur = cv2.GaussianBlur(imgRoadvR10_GrayPersp,(5,5),0)

# Try different thresholding methods
ret,a10lvR10_th1 = cv2.threshold(a10lvR10_gblur,127,255,cv2.THRESH_BINARY)
a10lvR10_th2 = cv2.adaptiveThreshold(a10lvR10_gblur,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)
a10lvR10_th3 = cv2.adaptiveThreshold(a10lvR10_gblur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY_INV,11,2)

# Otsu's thresholding
ret2,a10lvR10_th4 = cv2.threshold(a10lvR10_gblur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
print(ret2)

# Plot results
plt.figure()
titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding','OTSU Thresholding']
images = [a10lvR10_gblur, a10lvR10_th1, a10lvR10_th2, a10lvR10_th3, a10lvR10_th4]

for i in range(5):
    plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

不同阈值的结果

仔细看看自适应高斯阈值的结果: 自适应高斯阈值

我想找到这个矩形对象的宽度。宽度是从左侧的第二条边缘到右侧的边缘测量的(见下图): 在此处输入图像描述

如何测量宽度?我一直在阅读形态学操作和边缘检测,但不知道下一步如何进行。任何建议将不胜感激

标签: image-processingedge-detectionopencv-python

解决方案


这不是最好的主意,我认为可以获得更合乎逻辑和更简单的解决方案。但是,这个想法可能会对您有所帮助。

import cv2
import numpy as np

#load image
im = cv2.imread("test3.jpg", 1)

#Convert to gray
mask = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

#convert to black and white
mask = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)[1]

#try to remove noise
#you can just use median blur or any other method
mask = cv2.erode(mask, np.ones((8, 0), "uint8"))
mask = cv2.dilate(mask, np.ones((32, 0), "uint8"))
mask = cv2.medianBlur(mask, 9)

#save cleaned image
cv2.imwrite("out1.jpg", mask)

输出图像的更简洁版本:

输出1:

在此处输入图像描述


接下来我们可以得到线条的坐标。我得到了左边第一行的坐标。我认为您必须稍微更改代码才能获得侧边栏的坐标。

h = len(mask) - 1


def count(row):
    counter = 0
    for i in range(0, len(row)):
        if row[i] == 255:
            break
        counter += 1
    return counter


def line(im, pt1, pt2, color, thickness):
    im = cv2.line(
        img=im,
        pt1=pt1,
        pt2=pt2,
        color=color,
        thickness=thickness,
        lineType=cv2.LINE_AA,
    )
    return im


def center(x1, y1, x2, y2):
    return (int((x1 + x2) / 2), int((y1 + y2) / 2))


topLeft = count(mask[0])
bottomLeft = count(mask[h])
# to shadow and hide the old left line
mask = line(mask, (topLeft, 0), (bottomLeft, h), (0, 0, 0), 80)

topRight = count(mask[0])
bottomRight = count(mask[h])
# to shadow and hide the old right line
mask = line(mask, (topRight, 0), (bottomRight, h), (0, 0, 0), 80)

mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)

# to draw new clean left line
mask = line(mask, (topLeft, 0), (bottomLeft, h), (128, 0, 255), 25)
# to draw new clean right line
mask = line(mask, (topRight, 0), (bottomRight, h), (128, 0, 255), 25)

a = center(topLeft, 0, bottomLeft, h)
b = center(topRight, 0, bottomRight, h)
mask = line(mask, a, b, (128, 0, 255), 25)

cv2.imwrite("out2.jpg", mask)

输出2:

在此处输入图像描述


现在您可以计算“a”和“b”之间的距离。


推荐阅读