- 图像的封闭外轮廓,将其转换为从右上边开始顺时针的点序列。
- 确定右上角的起点,以及确保点按顺时针顺序排列。
一、如何确定右上角的起点
- 图像坐标系的原点通常在左上角,y轴向下,所以右上角的点应该是x最大的,而y最小的点。
二、但如何确定轮廓的原始方向是顺时针还是逆时针?
- 可以通过计算轮廓的面积的符号来判断。
例如,使用cv2.contourArea(contour, oriented=True),如果返回的值为正,则是逆时针,否则顺时针。或者反过来?需要测试。
三、如何将轮廓点旋转到起点?
- 假设轮廓是一个循环的列表,例如,轮廓中的点按顺序排列,可以找到起点的索引,然后将该点作为起始点,后面的点依次跟随,保持顺序。例如,如果轮廓的点列表是 [A, B, C, D, A],找到C是起点,则新的顺序是 [C, D, A, B, C]
四、如何旋转数组?
- 旋转数组的方法是找到起点的索引,然后将数组分为两部分:从索引到末尾,再加上从开头到索引的部分。
例如,contour是一个numpy数组,假设contour的索引为i,则新的轮廓是 np.concatenate([contour[i:], contour[:i]])
五、步骤:
- 确定轮廓是否为顺时针,如果不是,反转。
- 找到右上角的起点。
- 找到该起点在轮廓中的索引。
- 将数组旋转,使得起点成为第一个点。
- 输出新的点序列。
六、程序
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 30 09:04:57 2025
轮廓点序列转换程序ds010.py
"""
import cv2
import numpy as np
# 读取图像并二值化处理
image = cv2.imread('d:/imgs/bak01/my_img01-B2.jpg', cv2.IMREAD_GRAYSCALE)
_, thresh = cv2.threshold(image, 50, 255, cv2.THRESH_BINARY)
# 查找轮廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
# 确保轮廓为顺时针方向
area = cv2.contourArea(contour, oriented=True)
if area > 0: # 如果面积为正表示逆时针,需要反转
contour = contour[::-1]
# 找到右上角的起点(x最大,y最小)
x_coords = contour[:, 0, 0]
max_x = x_coords.max()
mask = (x_coords == max_x)
candidates = contour[mask]
y_coords = candidates[:, 0, 1]
min_y_idx = np.argmin(y_coords)
start_pt = candidates[min_y_idx]
# 找到起点在轮廓中的索引
idx = np.where((contour[:, 0, 0] == start_pt[0, 0]) &
(contour[:, 0, 1] == start_pt[0, 1]))[0][0]
# 旋转轮廓点数组,使起点位于开头
rotated_contour = np.roll(contour, -idx, axis=0)
# 转换为二维坐标列表
point_sequence = rotated_contour.squeeze(axis=1).tolist()
# 输出结果
print("顺时针点序列(从右上角开始):")
for point in point_sequence:
print(f"({point[0]}, {point[1]})")
# 可选:可视化结果(需要OpenCV)
canvas = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
cv2.drawContours(canvas, [rotated_contour], -1, (0,255,255), 8)
zoom_xs=0.2
new_img2 = cv2.resize(canvas, None, fx=zoom_xs, fy=zoom_xs)
cv2.imshow('Result', new_img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
六、运行结果
网友评论