【问题标题】:Convert abstract mask to geometric shape and calculate all edges将抽象蒙版转换为几何形状并计算所有边缘
【发布时间】:2021-10-23 16:40:07
【问题描述】:

我是 Python 的新手,所以我想做的是:

我已经制作了给定图像的地板蒙版:

https://i.ibb.co/0r17SnT/www.png

我想做的是用几何直线连接所有点并找到每条边的长度,就像我在这个例子中画的一样:

https://i.ibb.co/tbgyYF5/www.png

我正在使用openCV,到目前为止我试图找到一些极端点,但我猜这不是我需要的。

def getCalculatedImg():

    # Load image
    img = cv2.imread('img.jpg')
    gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Apply cv2.threshold() to get a binary image
    ret, thresh = cv2.threshold(gray_image, 50, 255, cv2.THRESH_BINARY)

    # Find contours:
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    cntrs = contours[0]
    c = max(contours, key=cv2.contourArea)

    # Obtain outer coordinates
    left_coordinates_separated = [(c[c[:, :, 0].argmin()][0])[0], (c[c[:, :, 0].argmin()][0])[1]]
    left = tuple(left_coordinates_separated)
    right_coordinates_separated = [(c[c[:, :, 0].argmax()][0])[0], (c[c[:, :, 0].argmax()][0])[1]]
    right = tuple(right_coordinates_separated)
    top_coordinates_separated = [(c[c[:, :, 1].argmin()][0])[0], (c[c[:, :, 1].argmin()][0])[1]]
    top = tuple(top_coordinates_separated)
    bottom_coordinates_separated = [(c[c[:, :, 1].argmax()][0])[0], (c[c[:, :, 1].argmax()][0])[1]]
    bottom = tuple(bottom_coordinates_separated)

    # Draw contours and dots to image:
    cv2.drawContours(img, [c], -1, (36, 255, 12), 2)
    cv2.circle(img, left, 8, (0, 50, 255), -1)
    cv2.circle(img, right, 8, (0, 255, 255), -1)
    cv2.circle(img, top, 8, (255, 50, 0), -1)
    cv2.circle(img, bottom, 8, (255, 255, 0), -1)
    print('Left point: {}'.format(left))
    print('Right point: {}'.format(right))
    print('Top point: {}'.format(top))
    print('Bottom point: {}'.format(bottom))

    # Output
    cv2.imwrite('outlined_boundered_image.jpg', img)

    return img

【问题讨论】:

  • 这不是你所需要的 :) 但也许这可以帮助你stackoverflow.com/a/68837935/2227070
  • @Shamshirsaz.Navid 谢谢你,我点击了你提供的链接。 cv2.approxPolyDP 帮了我很多!

标签: python numpy opencv cv2


【解决方案1】:

看来您想要的是边界的直线插值和线的长度。获得一个的一种方法是使用一阶样条。如果您对边界的实际长度更感兴趣,则使用 3 度插值和积分会更合适。如果你想要,请告诉我。

首先我使用模糊和索贝尔滤镜来获得清晰的边界图片。

import cv2
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import UnivariateSpline

picture = cv2.imread('area.png', cv2.IMREAD_GRAYSCALE)
picture2 = cv2.GaussianBlur(picture, (3, 3), 0, 0, cv2.BORDER_DEFAULT)
picture3 = np.abs(cv2.Sobel(picture2, cv2.CV_16S,0,1))+np.abs(cv2.Sobel(picture2,  cv2.CV_16S,0,1))
picture4 = (picture3>0.3*picture3.max()).T

plt.imshow(picture4.T, cmap='gray')

我无法将图像提供给UnivariateSpline 进行插值,因为每个 x 都有多个 y 像素。我通过将每个 x 的 y 值的平均值作为该点的函数值来解决这个问题。

x,y = np.where(picture4)
idx = np.unique(x, return_index = True)[1]
y = np.array(tuple(map(np.mean,np.split(y,idx)[1:])))

f = UnivariateSpline(x[idx],y,k=1,s=10**4)
knots = f.get_knots()
print(len(knots))

x2 = np.linspace(0,picture.shape[1])
plt.plot(x2, -f(x2))

它给了我一个带有 33 条原始边界线的直线插值。如果您认为 33 行太多,您可以增加 s。然后它使用更少的行。

最后我计算线段的长度

dx = knots[1:]-knots[:-1]
dy = f(knots[1:])-f(knots[:-1])
lengths = (dx**2+dy**2)**(1/2)
lengths

他们是

array([ 48.00108553,  24.00049131,  48.59189432,  48.00784009,
        24.00411983,  12.0353518 ,   7.45847594,  76.56726501,
        50.2062363 ,  62.97882834,  55.66753909,  59.85823117,
       192.18816002,  24.0756812 ,  12.0380576 ,   6.30271185,
        68.6638399 ,   8.91837947,   4.92632077,  11.31860656,
        68.12574347,  18.55007016,  24.08123637,  48.59346072,
        12.23820314,  18.36509318,  93.8749539 ,   8.61755003,
        15.5131074 ,  43.85394011,  56.05155661,   9.3525071 ,
        11.54485654])

编辑我认为看到几张具有不同线条数量的图片会很有趣。如果您对结果不满意,请尝试描述问题所在。

【讨论】:

    猜你喜欢
    • 2020-05-30
    • 1970-01-01
    • 2019-07-15
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    相关资源
    最近更新 更多