You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用cv2.findContours定位轮廓斜率突变的背鳍起始点

轮廓斜率突变点(背鳍起始点)定位方案

核心逻辑

背鳍起始点是轮廓走向从平缓(躯干部分)突然转向陡峭(背鳍部分)的位置,通过计算相邻轮廓点的斜率变化率,就能定位这个突变节点。

分步实现

1. 轮廓预处理(降噪+精简)

先对提取到的轮廓做精简,去掉冗余点,避免噪声干扰斜率计算:

import cv2
import numpy as np

# 假设已通过cv2.findContours获取目标轮廓(取面积最大的轮廓)
contours, _ = cv2.findContours(thresh_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
target_contour = max(contours, key=cv2.contourArea)

# 多边形近似降采样,减少冗余点
epsilon = 0.002 * cv2.arcLength(target_contour, True)
approx_points = [p[0] for p in cv2.approxPolyDP(target_contour, epsilon, True)]

# 只保留上半部分轮廓(背鳍在目标上方,缩小计算范围)
x, y, w, h = cv2.boundingRect(target_contour)
mid_y = y + h // 2
upper_points = [p for p in approx_points if p[1] < mid_y]

2. 计算斜率与突变值

用角度表示斜率(避免垂直线段的除零问题),再计算相邻斜率的差值绝对值:

# 计算每段轮廓的角度(替代斜率,更稳定)
slopes = []
for i in range(1, len(upper_points)):
    dx = upper_points[i][0] - upper_points[i-1][0]
    dy = upper_points[i][1] - upper_points[i-1][1]
    # arctan2返回[-π, π]区间的角度,规避垂直段的除零异常
    slopes.append(np.arctan2(dy, dx))

# 计算相邻斜率的变化幅度
slope_changes = [abs(slopes[i] - slopes[i-1]) for i in range(1, len(slopes))]

3. 定位背鳍起始点

通过阈值筛选出变化幅度最大的点,就是斜率突变的位置:

# 用90分位数作为突变阈值,过滤小波动干扰
threshold = np.percentile(slope_changes, 90)
# 找到最大变化幅度的索引,对应upper_points中的位置
max_change_idx = np.argmax(slope_changes)
fin_start_point = upper_points[max_change_idx + 1]

# 在原图标记结果
cv2.circle(input_img, fin_start_point, 6, (0, 0, 255), -1)
cv2.imshow("Fin Start Point", input_img)
cv2.waitKey(0)

优化技巧

  • 若阈值处理后的图像有细碎噪声,先执行形态学闭运算:kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)),thresh_img = cv2.morphologyEx(thresh_img, cv2.MORPH_CLOSE, kernel),再提取轮廓。
  • 若轮廓是闭合的,可先找到最左侧点作为遍历起点,确保从目标头部开始计算,避免遍历方向错误。

内容的提问来源于stack exchange,提问作者Mirote

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:45:45