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

Python中Major/Minor Axis计算代码优化及OpenCV贡献咨询

技术定义

Major-axis是可穿过物体的最长端点连线,其端点取自物体边界点,例如{(x₁,y₁),(x₂,y₂)}。通过算法计算物体边界点所有组合的像素距离,找到物体内部最长的连线即可确定Major-axis端点,其长度计算公式为:
$$\text{Sample Major-axis Length} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}$$
Minor-axis是垂直于Major-axis的、可穿过物体的最长端点连线。

现有代码及问题

本人自行编写了Python代码实现Major-axis与Minor-axis的计算及绘制(代码如下),但该代码仅在400*400及以下尺寸图像中运行正常;当图像尺寸更大、轮廓数量增多时,因多处嵌套循环导致的O(n²)时间复杂度会引发严重性能问题。

import cv2
import numpy as np
import math


from math import isclose 

import matplotlib
from matplotlib import pyplot as plt

Input_Path = """

Input_image = cv2.imread(Input_Path, cv2.IMREAD_GRAYSCALE)
RGB_image = cv2.cvtColor(Input_image, cv2.COLOR_GRAY2RGB)
Contour_image = RGB_image.copy()

Binary_Image = cv2.imread(Simple_Binarization(Input_Path), cv2.IMREAD_UNCHANGED)
Binary_Array = np.array(Binary_Image, dtype = 'uint8')


Contour, Hierarchy = cv2.findContours(Input_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

cv2.drawContours(Contour_image, Contour, len(Hierarchy[0])-1, (255, 0, 170), 1)

for l in range(len(Hierarchy[0])):
    cv2.drawContours(Contour_image, Contour, l, (0, 255, 0), 1)


List = []
  for c in range(len(Hierarchy[0])):
    for p in Contour[c]:
        point_array = np.array(p[0], dtype = 'int')
        List.append(tuple(point_array))

Major_List = []
  for p1 in range(0, len(List)):
    for p2 in range(p1+1, len(List)):

      Line_Image = np.zeros((Input_image.shape), dtype = 'uint8')
      cv2.line(Line_Image, List[p1], List[p2], (1), thickness = 1, lineType = cv2.LINE_8)
      Stencil = cv2.bitwise_and(Line_Image, Binary_Array)

      if (Stencil == Line_Image).all():
        Distance = math.sqrt(math.pow(List[p1][0] - List[p2][0], 2) + math.pow(List[p1][1] - List[p2][1], 2))
        Major_List.append([List[p1], List[p2], Distance])


Major_Axis = max(Major_List, key = lambda sublist: sublist[2])
Major_Axis_Image = cv2.arrowedLine(RGB_image, Major_Axis[0], Major_Axis[1], (255, 0, 0), thickness = 2, tipLength = 0.015)
Major_Axis_Image = cv2.arrowedLine(RGB_image, Major_Axis[1], Major_Axis[0], (255, 0, 0), thickness = 2, tipLength = 0.015)


Minor_List = []
  if (Major_Axis[1][1] - Major_Axis[0][1]) == 0:

    for p1 in range(0, len(List)):
      for p2 in range(p1+1, len(List)):

        if (List[p1][0] - List[p2][0]) == 0:

          Minor_Line_Image = np.zeros((Input_image.shape), dtype = 'uint8')
          cv2.line(Minor_Line_Image, List[p1], List[p2], (1), thickness = 1, lineType = cv2.LINE_8)
          Minor_Stencil = cv2.bitwise_and(Minor_Line_Image, Binary_Array)

          if (Minor_Stencil == Minor_Line_Image).all():

            Minor_Distance = math.sqrt(math.pow(List[p1][0] - List[p2][0], 2) + math.pow(List[p1][1] - List[p2][1], 2))
            Minor_List.append([List[p1], List[p2], Minor_Distance])

  elif (Major_Axis[1][0] - Major_Axis[0][0]) == 0:

    for p1 in range(0, len(List)):
      for p2 in range(p1+1, len(List)):

        if (List[p1][1] - List[p2][1]) == 0:

          Minor_Line_Image = np.zeros((Input_image.shape), dtype = 'uint8')
          cv2.line(Minor_Line_Image, List[p1], List[p2], (1), thickness = 1, lineType = cv2.LINE_8)
          Minor_Stencil = cv2.bitwise_and(Minor_Line_Image, Binary_Array)

          if (Minor_Stencil == Minor_Line_Image).all():

            Minor_Distance = math.sqrt(math.pow(List[p1][0] - List[p2][0], 2) + math.pow(List[p1][1] - List[p2][1], 2))
            Minor_List.append([List[p1], List[p2], Minor_Distance])

  else:
    Minor_Axis_Slope = (-1) * (Major_Axis[1][1] - Major_Axis[0][1]) / (Major_Axis[1][0] - Major_Axis[0][0])
    #Minor_Axis_Slope = (-1) * math.pow(Major_Axis_Slope, -1)

    for p1 in range(0, len(List)):
      for p2 in range(p1+1, len(List)):

        if (List[p1][0] - List[p2][0]) != 0 and (List[p1][1] - List[p2][1]) != 0 and isclose(((List[p1][0] - List[p2][0]) / (List[p1][1] - List[p2][1])), Minor_Axis_Slope, abs_tol = 1e-2):

          Minor_Line_Image = np.zeros((Input_image.shape), dtype = 'uint8')
          cv2.line(Minor_Line_Image, List[p1], List[p2], (1), thickness = 1, lineType = cv2.LINE_8)
          Minor_Stencil = cv2.bitwise_and(Minor_Line_Image, Binary_Array)

          if (Minor_Stencil == Minor_Line_Image).all():

            Minor_Distance = math.sqrt(math.pow(List[p1][0] - List[p2][0], 2) + math.pow(List[p1][1] - List[p2][1], 2))
            Minor_List.append([List[p1], List[p2], Minor_Distance])


Minor_Axis = max(Minor_List, key = lambda sublist: sublist[2])
RGB_image_2 = RGB_image.copy()

Minor_Axis_Image = cv2.arrowedLine(RGB_image_2, Minor_Axis[0], Minor_Axis[1], (0, 0, 255), thickness = 2, tipLength = 0.015)
Minor_Axis_Image = cv2.arrowedLine(RGB_image_2, Minor_Axis[1], Minor_Axis[0], (0, 0, 255), thickness = 2, tipLength = 0.015)



plt.figure(figsize=(10, 15))
plt.subplots_adjust(wspace=0.2, hspace=0.4)
matplotlib.rcParams['font.size'] = 8

plt.subplot(2, 2, 1), plt.imshow(Input_image)
plt.title('Input_image'), plt.tick_params(axis = 'both', which = 'major', labelsize = 8)

plt.subplot(2, 2, 2), plt.imshow(Contour_image)
plt.title('Input_image_&_Border'), plt.tick_params(axis = 'both', which = 'major', labelsize = 8)

plt.subplot(2, 2, 3), plt.imshow(Major_Axis_Image)
plt.title('Major_Axis_Image'), plt.tick_params(axis = 'both', which = 'major', labelsize = 8)
  
plt.subplot(2, 2, 4), plt.imshow(Minor_Axis_Image)
plt.title('Major&Minor_Axis'), plt.tick_params(axis = 'both', which = 'major', labelsize = 8)
plt.show()
需求咨询
  • 请对上述代码进行优化精简,降低时间复杂度以适配大尺寸图像及多轮廓场景;
  • 咨询如何将该代码贡献至OpenCV库的流程与方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:25:21