【问题标题】:Approximating edge with rough outline - OpenCV具有粗糙轮廓的近似边缘 - OpenCV
【发布时间】:2021-06-13 00:42:53
【问题描述】:

我一直在研究和尝试几个函数来获得我想要的东西,但我觉得我可能想多了。 我的代码的一个版本如下。示例图片为here

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

我从下面的代码中得到的结果如下。 CannyClosedSmall 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()

【问题讨论】:

  • 在您的“小删除”图像中,获取第一列和最后一列最底部的白色像素。这近似于所需的线(但在该示例中并不理想),您可以从两个点计算所需的角度。

标签: python numpy opencv canny-operator image-thresholding


【解决方案1】:

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

我不得不修剪你的图片,因为你分享了一个带有窗口装饰、标题和框架的屏幕截图,而不是你的实际图片:

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 轴截距位于图像底部的第 428 行。

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

【讨论】:

    【解决方案2】:

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

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

    从那里您可以进行线性回归以获得直线方程,或者您可以通过平均行的上半部分和下半部分的 x 值来获得两个点,然后从中计算梯度角.

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

    【讨论】:

    • 我还不确定如何做这些事情,但感谢您的意见!我确实尝试了大内核形态关闭,它并没有真正结束只有一个白色的一面和一个黑色的一面。整个左侧也只有大的白色斑点。
    • 只有在有小的白色规格开始时,才能有大的白色规格。尝试在大关闭之前再打开一次。
    • 好的,我已经把它放在右上角白色和左下角黑色的地方。虽然由于内核大小很大,它几乎就像一个楼梯。
    • 刚刚意识到我的意思是扩张而不是关闭,忘记了我的形态。使用圆形(椭圆形)内核而不是方形内核也可能会获得更好的结果。
    猜你喜欢
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 2013-03-23
    • 2015-09-26
    • 2018-05-09
    • 1970-01-01
    相关资源
    最近更新 更多