具有粗略轮廓的近似边缘 - OpenCV

Approximating edge with rough outline - OpenCV

我一直在研究并尝试一些功能来获得我想要的东西,我觉得我可能想得太多了。 我的代码的一个版本如下。示例图像是 here.

我的最终目标是找到近似线相对于框架(绿线)的角度(黄色)Final 我什至还没有进入程序的角度部分。

我从下面的代码中获得的结果如下。 Canny Closed Small Removed

有人有更好的方法来创建差异和建立估计线吗? 感谢任何帮助。

import cv2
import numpy as np

pX = int(512)
pY = int(768)

img = cv2.imread('IMAGE LOCATION', cv2.IMREAD_COLOR)
imgS = cv2.resize(img, (pX, pY))
aimg = cv2.imread('IMAGE LOCATION', cv2.IMREAD_GRAYSCALE)

# Blur image to reduce noise and resize for viewing
blur = cv2.medianBlur(aimg, 5)
rblur = cv2.resize(blur, (384, 512))

canny = cv2.Canny(rblur, 120, 255, 1)
cv2.imshow('canny', canny)
kernel = np.ones((2, 2), np.uint8)
#fringeMesh = cv2.dilate(canny, kernel, iterations=2)
#fringeMesh2 = cv2.dilate(fringeMesh, None, iterations=1)
#cv2.imshow('fringeMesh', fringeMesh2)
closing = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel)
cv2.imshow('Closed', closing)

nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(closing, connectivity=8)
#connectedComponentswithStats yields every separated component with information on each of them, such as size
sizes = stats[1:, -1]; nb_components = nb_components - 1

min_size = 200  #num_pixels

fringeMesh3 = np.zeros((output.shape))
for i in range(0, nb_components):
    if sizes[i] >= min_size:
        fringeMesh3[output == i + 1] = 255


#contours, _ = cv2.findContours(fringeMesh3, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
#cv2.drawContours(fringeMesh3, contours, -1, (0, 255, 0), 1)


cv2.imshow('final', fringeMesh3)

#cv2.imshow("Natural", imgS)
#cv2.imshow("img", img)
cv2.imshow("aimg", aimg)
cv2.imshow("Blur", rblur)
cv2.waitKey()
cv2.destroyAllWindows()

您的 'Closed' 图像似乎很清楚地划分了两个区域,因此我建议您着重于将该边界变成一条您可以用来做某事的线。连通分量分析和轮廓检测在这里并没有真正提供任何有用的信息,因此没有必要。

找到线角度的一种非常简单的方法是找到每行中的第一个白色像素。要仅获取属于对角线一部分的行,请不要包含该像素太靠近任一侧(例如在 5% 以内)的行。这为您提供了两种草边界上的一组点(像素位置)。

从那里你可以做一个线性回归来得到直线的方程,或者你可以通过对行的上半部分和下半部分的 x 值求平均得到两个点,然后计算梯度角度从那个。

另一种方法是使用非常大的内核进行另一种形态学闭合,最终得到纯白色区域和纯黑色区域,您可以使用 canny 或 findContours 将其变成一条线。从那里你可以通过平均得到一些点,使用端点,或者从足够大的内核给出足够平滑的结果,你可以用霍夫线检测线。

您可以在每列中遇到的第一个白色像素上画一条直线,从底部开始。

我不得不 trim 你的图片,因为你用 window 装饰、标题和框架分享了它的屏幕截图,而不是你的实际图片:

import cv2
import math
import numpy as np

# Load image as greyscale
im = cv2.imread('trimmed.jpg', cv2.IMREAD_GRAYSCALE)

# Get index of first white pixel in each column, starting at the bottom
yvals = (im[::-1,:]>200).argmax(axis=0)

# Make the x values 0, 1, 2, 3...
xvals = np.arange(0,im.shape[1])

# Fit a line of the form y = mx + c
z = np.polyfit(xvals, yvals, 1)

# Convert the slope to an angle
angle = np.arctan(z[0]) * 180/math.pi

注1z(拟合的结果)的值为:

array([ -0.74002694, 428.01463745])

这意味着你正在寻找的直线方程是:

y = -0.74002694 * x + 428.01463745

即y-intercept 位于图像底部的第 428 行。

注意 2:尽量避免将 JPEG 格式作为图像处理中的中间格式 - 它有损并会改变你的像素值 - 所以在你设置阈值并完成形态学的地方期望值为 255 和 0,JPEG 将有损地更改这些值,您最终将再次测试范围或阈值。