|
@@ -60,7 +60,7 @@ def to_json_serializable(obj):
|
|
|
if isinstance(obj, (np.floating,)): return float(obj)
|
|
if isinstance(obj, (np.floating,)): return float(obj)
|
|
|
if hasattr(obj, 'to_dict'): return obj.to_dict()
|
|
if hasattr(obj, 'to_dict'): return obj.to_dict()
|
|
|
try:
|
|
try:
|
|
|
- return json.dumps(obj)
|
|
|
|
|
|
|
+ return json.dumps(obj, indent=2)
|
|
|
except TypeError:
|
|
except TypeError:
|
|
|
return str(obj)
|
|
return str(obj)
|
|
|
|
|
|
|
@@ -82,7 +82,7 @@ class DefectInfo:
|
|
|
"actual_area": self.actual_area,
|
|
"actual_area": self.actual_area,
|
|
|
"width": self.width,
|
|
"width": self.width,
|
|
|
"height": self.height,
|
|
"height": self.height,
|
|
|
- "contour": self.contour,
|
|
|
|
|
|
|
+ "points": self.contour,
|
|
|
"min_rect": self.min_rect
|
|
"min_rect": self.min_rect
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -92,7 +92,7 @@ class AnalysisResult:
|
|
|
"""封装单次分析的所有结果,包括缺陷列表和统计信息"""
|
|
"""封装单次分析的所有结果,包括缺陷列表和统计信息"""
|
|
|
defects: List[DefectInfo] = field(default_factory=list)
|
|
defects: List[DefectInfo] = field(default_factory=list)
|
|
|
total_defect_count: int = 0
|
|
total_defect_count: int = 0
|
|
|
- total_pixel_area = float = 0.0
|
|
|
|
|
|
|
+ total_pixel_area: float = 0.0
|
|
|
total_defect_area: float = 0.0 # 所有缺陷的总面积 (mm^2)
|
|
total_defect_area: float = 0.0 # 所有缺陷的总面积 (mm^2)
|
|
|
area_by_label: Dict[str, float] = field(default_factory=lambda: defaultdict(float))
|
|
area_by_label: Dict[str, float] = field(default_factory=lambda: defaultdict(float))
|
|
|
count_by_label: Dict[str, int] = field(default_factory=lambda: defaultdict(int))
|
|
count_by_label: Dict[str, int] = field(default_factory=lambda: defaultdict(int))
|
|
@@ -144,8 +144,9 @@ class DefectVisualizer:
|
|
|
box = np.intp(cv2.boxPoints(defect.min_rect))
|
|
box = np.intp(cv2.boxPoints(defect.min_rect))
|
|
|
cv2.drawContours(image, [box], 0, self.params.rect_color, self.params.rect_thickness)
|
|
cv2.drawContours(image, [box], 0, self.params.rect_color, self.params.rect_thickness)
|
|
|
info_text = [
|
|
info_text = [
|
|
|
- f"L: {defect.label}", f"A: {defect.actual_area:.3f} mm2",
|
|
|
|
|
- f"W: {defect.width:.3f} mm", f"H: {defect.height:.3f} mm"
|
|
|
|
|
|
|
+ # f"L: {defect.label}",
|
|
|
|
|
+ f"A: {defect.actual_area:.3f} mm2",
|
|
|
|
|
+ # f"W: {defect.width:.3f} mm", f"H: {defect.height:.3f} mm"
|
|
|
]
|
|
]
|
|
|
M = cv2.moments(contour)
|
|
M = cv2.moments(contour)
|
|
|
cx = int(M["m10"] / M["m00"]) if M["m00"] != 0 else contour[0][0][0]
|
|
cx = int(M["m10"] / M["m00"]) if M["m00"] != 0 else contour[0][0][0]
|
|
@@ -199,7 +200,8 @@ class DefectProcessor:
|
|
|
width, height = width_pixels * pixel_to_mm, height_pixels * pixel_to_mm
|
|
width, height = width_pixels * pixel_to_mm, height_pixels * pixel_to_mm
|
|
|
return pixel_area, actual_area, width, height, min_rect
|
|
return pixel_area, actual_area, width, height, min_rect
|
|
|
|
|
|
|
|
- def analyze_from_json(self, json_data: Dict[str, Any]) -> AnalysisResult:
|
|
|
|
|
|
|
+ def analyze_from_json(self, json_data: Dict[str, Any],
|
|
|
|
|
+ is_return_obj = False) -> dict|AnalysisResult:
|
|
|
"""
|
|
"""
|
|
|
[需求 1] 仅根据JSON数据计算缺陷面积并统计,返回包含详细信息的JSON友好对象。
|
|
[需求 1] 仅根据JSON数据计算缺陷面积并统计,返回包含详细信息的JSON友好对象。
|
|
|
|
|
|
|
@@ -241,10 +243,16 @@ class DefectProcessor:
|
|
|
result.count_by_label[label] += 1
|
|
result.count_by_label[label] += 1
|
|
|
result.area_by_label[label] += actual_area
|
|
result.area_by_label[label] += actual_area
|
|
|
|
|
|
|
|
- return result
|
|
|
|
|
|
|
+ if is_return_obj:
|
|
|
|
|
+ return result
|
|
|
|
|
+
|
|
|
|
|
+ result_json = to_json_serializable(result.to_dict())
|
|
|
|
|
+ result_json = json.loads(result_json)
|
|
|
|
|
+
|
|
|
|
|
+ return result_json
|
|
|
|
|
|
|
|
def analyze_and_draw(self, image: np.ndarray, json_data: Dict[str, Any], drawing_params: DrawingParams) -> Tuple[
|
|
def analyze_and_draw(self, image: np.ndarray, json_data: Dict[str, Any], drawing_params: DrawingParams) -> Tuple[
|
|
|
- np.ndarray, AnalysisResult]:
|
|
|
|
|
|
|
+ np.ndarray, dict]:
|
|
|
"""
|
|
"""
|
|
|
[需求 2] 输入图片和JSON数据,返回绘制好的图片和分析结果。
|
|
[需求 2] 输入图片和JSON数据,返回绘制好的图片和分析结果。
|
|
|
|
|
|
|
@@ -259,7 +267,7 @@ class DefectProcessor:
|
|
|
- 包含所有缺陷信息和统计结果的数据对象。
|
|
- 包含所有缺陷信息和统计结果的数据对象。
|
|
|
"""
|
|
"""
|
|
|
# 1. 首先,执行纯JSON分析以获取所有计算结果
|
|
# 1. 首先,执行纯JSON分析以获取所有计算结果
|
|
|
- analysis_result = self.analyze_from_json(json_data)
|
|
|
|
|
|
|
+ analysis_result = self.analyze_from_json(json_data, is_return_obj=True)
|
|
|
|
|
|
|
|
# 2. 如果没有缺陷,直接返回原图和分析结果
|
|
# 2. 如果没有缺陷,直接返回原图和分析结果
|
|
|
if not analysis_result.defects:
|
|
if not analysis_result.defects:
|
|
@@ -269,7 +277,10 @@ class DefectProcessor:
|
|
|
visualizer = DefectVisualizer(drawing_params)
|
|
visualizer = DefectVisualizer(drawing_params)
|
|
|
drawn_image = visualizer.draw_defects_on_image(image, analysis_result.defects)
|
|
drawn_image = visualizer.draw_defects_on_image(image, analysis_result.defects)
|
|
|
|
|
|
|
|
- return drawn_image, analysis_result
|
|
|
|
|
|
|
+ result_json = to_json_serializable(analysis_result.to_dict())
|
|
|
|
|
+ result_json = json.loads(result_json)
|
|
|
|
|
+
|
|
|
|
|
+ return drawn_image, result_json
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_json_only_analysis_example(json_path: str, output_json_path: str):
|
|
def run_json_only_analysis_example(json_path: str, output_json_path: str):
|
|
@@ -369,10 +380,10 @@ if __name__ == "__main__":
|
|
|
# print("\n" + "=" * 50 + "\n")
|
|
# print("\n" + "=" * 50 + "\n")
|
|
|
|
|
|
|
|
# 2. 图像和JSON结合分析
|
|
# 2. 图像和JSON结合分析
|
|
|
- run_image_and_json_analysis_example(
|
|
|
|
|
- image_path=image_file_path,
|
|
|
|
|
- json_path=json_file_path,
|
|
|
|
|
- output_dir=output_dir
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- fry_algo_print("重要", "所有示例运行完毕!")
|
|
|
|
|
|
|
+ # run_image_and_json_analysis_example(
|
|
|
|
|
+ # image_path=image_file_path,
|
|
|
|
|
+ # json_path=json_file_path,
|
|
|
|
|
+ # output_dir=output_dir
|
|
|
|
|
+ # )
|
|
|
|
|
+ #
|
|
|
|
|
+ # fry_algo_print("重要", "所有示例运行完毕!")
|