如何获取图像中形状每一边的长度? [英] How to get length of each side of a shape in an image?

查看:16
本文介绍了如何获取图像中形状每一边的长度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有如下图片:

[![输入][1]][1]

我想确定边的数量,以及每边的长度.

在图像中,我们将三个边缘作为直线,而上一个是弯曲的边缘.我能够使用 Canny 边缘检测找到三个直边的长度.我们可以有四个顶点坐标,我们可以计算出三个直边/线的长度,但无法找到弯曲边的长度.

因此,预处理必须适应输入图像,并且超出了我的回答范围!在下面的代码中,预处理是针对给定的输入图像,而不是针对其他两个示例.

import cv2将 matplotlib.pyplot 导入为 plt将 numpy 导入为 npdef extract_and_measure_edges(img_bin):# 检测可能的角点,并提取候选者dst = cv2.cornerHarris(img_bin, 2, 3, 0.04)糖果= []对于 i, c in enumerate(np.argwhere(dst > 0.1 * np.max(dst)).tolist()):c = np.flip(np.array(c))如果 len(cand) == 0:cand.append(c)别的:添加=真对于 enumerate(cand) 中的 j,d:d = np.array(d)如果 np.linalg.norm(c - d) <5:添加 = 假休息如果添加:cand.append(c)# 获取实际的、最近的匹配轮廓点的索引角=排序([np.argmin(np.linalg.norm(c-cnt.squeeze(),轴=1))对于 c 中的 cand])# 从轮廓中提取边缘,并测量它们的长度输出 = cv2.cvtColor(np.zeros_like(img_bin), cv2.COLOR_GRAY2BGR)对于 i_c, c in enumerate(corners):如果 i_c == len(corners) - 1:edge = np.vstack([cnt[c:, ...], cnt[0:corners[0], ...]])别的:边缘 = cnt[c:corners[i_c + 1], ...]loc = tuple(np.mean(edge.squeeze(), axis=0, dtype=int).tolist())颜色 = 元组(np.random.randint(0, 255, 3).tolist())长度 = cv2.arcLength(边,假)cv2.polylines(输出,[边缘],假,颜色,2)cv2.putText(输出,'{:.2f}'.format(长度),loc,cv2.FONT_HERSHEY_COMPLEX,0.5,颜色,1)返回输出# 读取并预处理图像,提取形状轮廓# TODO:修改以适合您的输入图像img = cv2.imread('2B2m4.png')灰色 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)thr = cv2.threshold(灰色, 16, 255, cv2.THRESH_BINARY_INV)[1]cnts = cv2.findContours(thr, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)cnts = cnts[0] 如果 len(cnts) == 2 否则 cnts[1]cnt = max(cnts, key=cv2.contourArea)thr = cv2.drawContours(np.zeros_like(thr), [cnt], -1, 255, 1)# 提取和测量边缘,并可视化输出out = extract_and_measure_edges(thr)plt.figure(figsize=(18, 6))plt.subplot(1, 3, 1), plt.imshow(img), plt.title('原始输入图像')plt.subplot(1, 3, 2), plt.imshow(thr, cmap='gray'), plt.title('需要轮廓')plt.subplot(1, 3, 3), plt.imshow(out), plt.title('结果')plt.tight_layout(), plt.show()

这是输出:

示例 #2:

输出:

示例 #3:

输出:

(我没有注意正确的颜色顺序...)

----------------------------------------系统信息--------------------------------------平台:Windows-10-10.0.19041-SP0蟒蛇:3.9.1PyCharm:2021.1.1Matplotlib:3.4.2NumPy:1.19.5开放CV:4.5.2--------------------------------------

Suppose we have an image as below:

[![Input][1]][1]

I want to determine the number of sides, and the length of each side.

Here in the image, we have three edges as straight lines, and the upper one is a curved edge. I am able to find the length of the three straight edges using Canny edge detection. We can have four vertices coordinates, and we can calculate the length of the three straight edges/lines, but unable to find the length of the curved edge.

find number of sides and length of each side and number of vertices in image python This is a good answer for getting the number of edges in an image, and we get the coordinates of vertices through the code in the above link. Further to get the length of the sides using the coordinates, we can use below code to get the length, if the edges are straight lines:

for pt in zip(points,np.roll(points,-1,0)):
#     print( pt )
    x = pt[0][0]
    y = pt[1][0]
    d = math.sqrt((x[1]-y[1])*(x[1]-y[1]) + (x[0]-y[0])*(x[0]-y[0]))
    print('length between point:',x,'and', y,'is', d)

To simplify my question: I want to find, how many edges/sides are there for a shape in an image, and their respective lengths, if the image shape has any curved sides.

解决方案

My idea would be to get the contour of the shape, try to detect "corners", e.g. using Harris corner detection, find matching points from the contour, and piecewise calculate the length of the edges using cv2.arcLength.

The input for the below extract_and_measure_edges method needs some binarized contour image like that one derived from your actual input image:

So, the pre-processing must be adapted to the input images, and is out of scope of my answer! In the below code, the pre-processing is for the given input image, not for the two other examples.

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


def extract_and_measure_edges(img_bin):

    # Detect possible corners, and extract candidates
    dst = cv2.cornerHarris(img_bin, 2, 3, 0.04)
    cand = []
    for i, c in enumerate(np.argwhere(dst > 0.1 * np.max(dst)).tolist()):
        c = np.flip(np.array(c))
        if len(cand) == 0:
            cand.append(c)
        else:
            add = True
            for j, d in enumerate(cand):
                d = np.array(d)
                if np.linalg.norm(c - d) < 5:
                    add = False
                    break
            if add:
                cand.append(c)

    # Get indices of actual, nearest matching contour points
    corners = sorted([np.argmin(np.linalg.norm(c - cnt.squeeze(), axis=1))
                      for c in cand])

    # Extract edges from contour, and measure their lengths
    output = cv2.cvtColor(np.zeros_like(img_bin), cv2.COLOR_GRAY2BGR)
    for i_c, c in enumerate(corners):
        if i_c == len(corners) - 1:
            edge = np.vstack([cnt[c:, ...], cnt[0:corners[0], ...]])
        else:
            edge = cnt[c:corners[i_c + 1], ...]

        loc = tuple(np.mean(edge.squeeze(), axis=0, dtype=int).tolist())
        color = tuple(np.random.randint(0, 255, 3).tolist())
        length = cv2.arcLength(edge, False)
        cv2.polylines(output, [edge], False, color, 2)
        cv2.putText(output, '{:.2f}'.format(length), loc, cv2.FONT_HERSHEY_COMPLEX, 0.5, color, 1)
    return output


# Read and pre-process image, extract contour of shape
# TODO: MODIFY TO FIT YOUR INPUT IMAGES
img = cv2.imread('2B2m4.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thr = cv2.threshold(gray, 16, 255, cv2.THRESH_BINARY_INV)[1]
cnts = cv2.findContours(thr, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnt = max(cnts, key=cv2.contourArea)
thr = cv2.drawContours(np.zeros_like(thr), [cnt], -1, 255, 1)

# Extract and measure edges, and visualize output
out = extract_and_measure_edges(thr)
plt.figure(figsize=(18, 6))
plt.subplot(1, 3, 1), plt.imshow(img), plt.title('Original input image')
plt.subplot(1, 3, 2), plt.imshow(thr, cmap='gray'), plt.title('Contour needed')
plt.subplot(1, 3, 3), plt.imshow(out), plt.title('Results')
plt.tight_layout(), plt.show()

That's the output:

Example #2:

Output:

Example #3:

Output:

(I haven't paid attention to the correct color ordering...)

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19041-SP0
Python:        3.9.1
PyCharm:       2021.1.1
Matplotlib:    3.4.2
NumPy:         1.19.5
OpenCV:        4.5.2
----------------------------------------

这篇关于如何获取图像中形状每一边的长度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆