我的想法是获取形状的轮廓,尝试检测“角”,例如使用Harris corner detection,从轮廓中找到匹配点,使用cv2.arcLength分段计算边的长度。
以下extract_and_measure_edges 方法的输入需要一些二值化轮廓图像,例如从您的实际输入图像派生的图像:
因此,预处理必须适应输入图像,并且超出了我的回答范围!在下面的代码中,预处理是针对给定的输入图像,而不是针对其他两个示例。
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()
这是输出:
示例 #2:
输出:
示例 #3:
输出:
(我没有注意正确的颜色顺序...)
----------------------------------------
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
----------------------------------------