ソースを参照

配置边角距离和修改划分逻辑

AnlaAnla 2 週間 前
コミット
915382fb3f
2 ファイル変更37 行追加21 行削除
  1. 1 1
      app/core/config.py
  2. 36 20
      app/utils/defect_inference/ClassifyEdgeCorner.py

+ 1 - 1
app/core/config.py

@@ -24,7 +24,7 @@ class Settings:
 
     # 图片像素与真实图片缩放比例
     PIXEL_RESOLUTION = 24.54
-    CORNER_SIZE_MM = 3.0
+    CORNER_SIZE_MM = 2.0
     EDGE_SIZE_MM = 1
 
     # 使用一个字典来管理所有卡片检测模型

+ 36 - 20
app/utils/defect_inference/ClassifyEdgeCorner.py

@@ -17,7 +17,7 @@ class ClassifyEdgeCorner:
         """
         self.PIXEL_RESOLUTION_UM = PIXEL_RESOLUTION_UM
         self.CORNER_SIZE_MM = PIXEL_CENTER_UM
-        self.EDGE_SIZE_MM = EDGE_SIZE_MM  # 新增:边的宽度
+        self.EDGE_SIZE_MM = EDGE_SIZE_MM
 
     def get_rotated_rect_data(self, outer_box_data):
         """
@@ -42,7 +42,6 @@ class ClassifyEdgeCorner:
     def create_corner_regions(self, outer_box_corners, corner_size_px):
         """
         根据外框的角点和指定的尺寸(像素),创建四个角区的多边形。
-        (逻辑保持不变)
         """
         corner_regions = []
         num_corners = len(outer_box_corners)
@@ -58,7 +57,6 @@ class ClassifyEdgeCorner:
             norm1 = np.linalg.norm(vec1)
             norm2 = np.linalg.norm(vec2)
 
-            # 防止除以0的保护
             if norm1 == 0 or norm2 == 0:
                 unit_vec1 = np.array([0, 0])
                 unit_vec2 = np.array([0, 0])
@@ -71,6 +69,7 @@ class ClassifyEdgeCorner:
             q2 = p_current + corner_size_px * unit_vec2
             q3 = q1 + corner_size_px * unit_vec2
 
+            # 确保生成的点是 float32,用于相交计算
             corner_poly = np.array([q0, q1, q3, q2], dtype=np.float32)
             corner_regions.append(corner_poly)
 
@@ -86,7 +85,6 @@ class ClassifyEdgeCorner:
         inner_w = w - 2 * edge_size_px
         inner_h = h - 2 * edge_size_px
 
-        # 如果边设置得太宽,导致内框消失,则返回 None 或极小的框
         if inner_w <= 0 or inner_h <= 0:
             logger.warning("警告: EDGE_SIZE_MM 设置过大,超过了卡牌尺寸,面(Face)区域将不存在。")
             return None
@@ -96,15 +94,34 @@ class ClassifyEdgeCorner:
 
         # 获取内框的四个角点
         inner_box = cv2.boxPoints(inner_rect)
-        inner_box = np.int32(inner_box)  # 转换为整数点以便于 polygon test
+        # 修改:为了支持 intersectConvexConvex,这里转换为 float32 而不是 int32
+        inner_box = np.array(inner_box, dtype=np.float32)
         return inner_box
 
+    def check_intersection(self, poly1, poly2):
+        """
+        检测两个凸多边形是否相交(重合面积 > 0)
+        poly1, poly2: np.float32 类型的多边形点集
+        """
+        if poly1 is None or poly2 is None:
+            return False
+
+        # intersectConvexConvex 返回 (intersection_area, intersection_polygon)
+        # 我们只需要面积即可。如果面积 > 0 (考虑到浮点误差,可以用 > 0.01) 即视为相交
+        try:
+            intersection_area, _ = cv2.intersectConvexConvex(poly1, poly2)
+            return intersection_area > 0.1  # 设置一个微小的阈值防止浮点噪声
+        except Exception as e:
+            # 极少数情况下如果多边形退化可能报错,视为不相交
+            logger.debug(f"Intersection check failed: {e}")
+            return False
+
     def classify_defects_location(self, defect_data, outer_box_data):
         """
-        主函数:分类为 corner, face, edge
+        主函数:分类为 corner, face, edge (基于重合逻辑)
+        优先级:Face (只要碰到面就算面) > Corner (没碰到面但碰到角) > Edge (其余)
         """
         if not defect_data or 'defects' not in defect_data or not defect_data['defects']:
-            # logger.warn("无缺陷数据")
             return defect_data
 
         # 1. 单位转换
@@ -117,15 +134,13 @@ class ClassifyEdgeCorner:
 
         # 2. 获取外框几何信息
         try:
-            # 获取旋转矩形完整数据 ((x,y), (w,h), angle)
             rect_data = self.get_rotated_rect_data(outer_box_data)
-            # 获取外框的四个角点 (用于角区计算)
             outer_box_corners = cv2.boxPoints(rect_data)
         except ValueError as e:
             logger.error(f"外框数据错误: {e}")
             return None
 
-        # 3. 定义区域
+        # 3. 定义区域 (多边形)
         # A. 定义四个角区
         corner_regions = self.create_corner_regions(outer_box_corners, corner_size_px)
 
@@ -138,25 +153,27 @@ class ClassifyEdgeCorner:
             if 'min_rect' not in defect or not defect['min_rect']:
                 continue
 
-            # 获取缺陷中心点
-            center_point = tuple(defect['min_rect'][0])
+            # --- 步骤变更:获取缺陷的多边形轮廓 ---
+            # defect['min_rect'] 结构通常为 ((x,y), (w,h), angle)
+            defect_rect = defect['min_rect']
+            defect_box = cv2.boxPoints(defect_rect)
+            defect_poly = np.array(defect_box, dtype=np.float32)
 
             # --- 判定逻辑优先级 ---
-            # 优先级 1: 面 (Face)
-            # 如果点在内缩矩形内部,且不是角,那就是面
+
+            # 优先级 1: 面 (Face) - 只要碰到 Face 区域就算 Face
             is_face = False
             if face_region is not None:
-                if cv2.pointPolygonTest(face_region, center_point, False) >= 0:
+                if self.check_intersection(face_region, defect_poly):
                     is_face = True
 
             if is_face:
                 defect['defect_type'] = 'face'
             else:
-                # 优先级 2: 角 (Corner)
+                # 优先级 2: 角 (Corner) - 没碰到 Face,但碰到了 Corner 区域
                 is_corner = False
                 for region in corner_regions:
-                    # pointPolygonTest: >0 内部, =0 边界, <0 外部
-                    if cv2.pointPolygonTest(region, center_point, False) >= 0:
+                    if self.check_intersection(region, defect_poly):
                         is_corner = True
                         break
 
@@ -164,8 +181,7 @@ class ClassifyEdgeCorner:
                     defect['defect_type'] = 'corner'
                 else:
                     # 优先级 3: 边 (Edge)
-                    # 既不在角区,也不在面区(内框)里,但还在处理范围内,那就是边
-                    # (注:这里默认缺陷是在外框内的,如果是外框外的噪声,通常也会被算作 Edge 或需要额外过滤)
+                    # 既没碰到面,也没碰到角,说明完全处于边区域内(或者在外框外)
                     defect['defect_type'] = 'edge'
 
             processed_count += 1