Python:輪廓點(diǎn)序列轉(zhuǎn)換

  • 圖像的封閉外輪廓,將其轉(zhuǎn)換為從右上邊開始順時(shí)針的點(diǎn)序列。
  • 確定右上角的起點(diǎn),以及確保點(diǎn)按順時(shí)針順序排列。

一、如何確定右上角的起點(diǎn)

  • 圖像坐標(biāo)系的原點(diǎn)通常在左上角,y軸向下,所以右上角的點(diǎn)應(yīng)該是x最大的,而y最小的點(diǎn)。

二、但如何確定輪廓的原始方向是順時(shí)針還是逆時(shí)針?

  • 可以通過計(jì)算輪廓的面積的符號(hào)來判斷。
    例如,使用cv2.contourArea(contour, oriented=True),如果返回的值為正,則是逆時(shí)針,否則順時(shí)針?;蛘叻催^來?需要測(cè)試。

三、如何將輪廓點(diǎn)旋轉(zhuǎn)到起點(diǎn)?

  • 假設(shè)輪廓是一個(gè)循環(huán)的列表,例如,輪廓中的點(diǎn)按順序排列,可以找到起點(diǎn)的索引,然后將該點(diǎn)作為起始點(diǎn),后面的點(diǎn)依次跟隨,保持順序。例如,如果輪廓的點(diǎn)列表是 [A, B, C, D, A],找到C是起點(diǎn),則新的順序是 [C, D, A, B, C]

四、如何旋轉(zhuǎn)數(shù)組?

  • 旋轉(zhuǎn)數(shù)組的方法是找到起點(diǎn)的索引,然后將數(shù)組分為兩部分:從索引到末尾,再加上從開頭到索引的部分。
    例如,contour是一個(gè)numpy數(shù)組,假設(shè)contour的索引為i,則新的輪廓是 np.concatenate([contour[i:], contour[:i]])

五、步驟:

    1. 確定輪廓是否為順時(shí)針,如果不是,反轉(zhuǎn)。
    1. 找到右上角的起點(diǎn)。
    1. 找到該起點(diǎn)在輪廓中的索引。
    1. 將數(shù)組旋轉(zhuǎn),使得起點(diǎn)成為第一個(gè)點(diǎn)。
    1. 輸出新的點(diǎn)序列。

六、程序

# -*- coding: utf-8 -*-
"""
Created on Wed Apr 30 09:04:57 2025

輪廓點(diǎn)序列轉(zhuǎn)換程序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:
    # 確保輪廓為順時(shí)針方向
    area = cv2.contourArea(contour, oriented=True)
    if area > 0:  # 如果面積為正表示逆時(shí)針,需要反轉(zhuǎn)
        contour = contour[::-1]

    # 找到右上角的起點(diǎn)(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]

    # 找到起點(diǎn)在輪廓中的索引
    idx = np.where((contour[:, 0, 0] == start_pt[0, 0]) & 
                  (contour[:, 0, 1] == start_pt[0, 1]))[0][0]

    # 旋轉(zhuǎn)輪廓點(diǎn)數(shù)組,使起點(diǎn)位于開頭
    rotated_contour = np.roll(contour, -idx, axis=0)

    # 轉(zhuǎn)換為二維坐標(biāo)列表
    point_sequence = rotated_contour.squeeze(axis=1).tolist()

    # 輸出結(jié)果
    print("順時(shí)針點(diǎn)序列(從右上角開始):")
    for point in point_sequence:
        print(f"({point[0]}, {point[1]})")

# 可選:可視化結(jié)果(需要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()

六、運(yùn)行結(jié)果

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容