针对特定形状提取几何参数(如平行四边形的倾斜度、圆柱体的顶部高度等)。 返回参数字典,例如 {"size": 0.2, "direction": "south"}
(image: np.ndarray, bbox: list, shape_type: str)
| 80 | |
| 81 | # ======================== 几何参数提取 ======================== |
| 82 | def extract_geometric_params(image: np.ndarray, bbox: list, shape_type: str) -> dict: |
| 83 | """ |
| 84 | 针对特定形状提取几何参数(如平行四边形的倾斜度、圆柱体的顶部高度等)。 |
| 85 | 返回参数字典,例如 {"size": 0.2, "direction": "south"} |
| 86 | """ |
| 87 | params = {} |
| 88 | x1, y1, x2, y2 = map(int, bbox) |
| 89 | w_box, h_box = x2 - x1, y2 - y1 |
| 90 | |
| 91 | if w_box <= 0 or h_box <= 0: |
| 92 | return params |
| 93 | |
| 94 | # 提取 ROI 用于分析 |
| 95 | roi = image[y1:y2, x1:x2] |
| 96 | gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) |
| 97 | |
| 98 | # 通用预处理:获取轮廓 |
| 99 | _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) |
| 100 | contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
| 101 | |
| 102 | main_cnt = None |
| 103 | max_area = 0 |
| 104 | for cnt in contours: |
| 105 | area = cv2.contourArea(cnt) |
| 106 | if area > max_area: |
| 107 | max_area = area |
| 108 | main_cnt = cnt |
| 109 | |
| 110 | if main_cnt is None: |
| 111 | return params |
| 112 | |
| 113 | # 针对不同形状的分析 |
| 114 | if shape_type == "parallelogram": |
| 115 | # 计算倾斜比例 size (0~1) |
| 116 | epsilon = 0.02 * cv2.arcLength(main_cnt, True) |
| 117 | approx = cv2.approxPolyDP(main_cnt, epsilon, True) |
| 118 | |
| 119 | if len(approx) == 4: |
| 120 | pts = approx.reshape(4, 2) |
| 121 | pts = pts[np.argsort(pts[:, 1])] |
| 122 | top_pts = pts[:2] |
| 123 | bottom_pts = pts[2:] |
| 124 | |
| 125 | top_pts = top_pts[np.argsort(top_pts[:, 0])] |
| 126 | bottom_pts = bottom_pts[np.argsort(bottom_pts[:, 0])] |
| 127 | |
| 128 | tl, tr = top_pts[0], top_pts[1] |
| 129 | bl, br = bottom_pts[0], bottom_pts[1] |
| 130 | |
| 131 | dx = abs(tl[0] - bl[0]) |
| 132 | size_val = dx / w_box if w_box > 0 else 0.2 |
| 133 | params["size"] = max(0.05, min(0.5, size_val)) |
| 134 | |
| 135 | elif shape_type == "cylinder": |
| 136 | params["size"] = max(10, int(w_box * 0.15)) |
| 137 | |
| 138 | elif shape_type == "triangle": |
| 139 | epsilon = 0.04 * cv2.arcLength(main_cnt, True) |
no outgoing calls
no test coverage detected