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
相关产品推荐
相关产品推荐

