From c76036cd5c2fa1827e7431159be21491113fbb8c Mon Sep 17 00:00:00 2001 From: KoyoNoguchi Date: Tue, 29 Sep 2026 15:31:00 +0900 Subject: [PATCH] =?UTF-8?q?ROI=E3=82=92=E9=A0=AD=E9=83=A8=E3=81=A0?= =?UTF-8?q?=E3=81=91=E3=81=AB=E7=B5=9E=E3=81=A3=E3=81=A6=E3=82=A2=E3=83=83?= =?UTF-8?q?=E3=83=97=E3=82=B9=E3=82=B1=E3=83=BC=E3=83=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/default.yaml | 4 +++- src/config_loader.py | 4 ++++ src/face_geometry.py | 9 +++++++-- src/face_processor.py | 5 +++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/config/default.yaml b/config/default.yaml index 3b1f8b2..b6a0cf2 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -72,8 +72,10 @@ face: max_persons_per_frame: 3 require_confirmed_track: true process_only_inside_region: false - roi_height_ratio: 0.60 + roi_height_ratio: 0.25 roi_expand_ratio: 0.20 + roi_square: true + roi_upscale_target: 384 min_roi_width: 40 min_roi_height: 40 static_image_mode: false diff --git a/src/config_loader.py b/src/config_loader.py index b66cbd7..3e10be0 100644 --- a/src/config_loader.py +++ b/src/config_loader.py @@ -181,6 +181,8 @@ class FaceSettings: process_only_inside_region: bool roi_height_ratio: float roi_expand_ratio: float + roi_square: bool + roi_upscale_target: int min_roi_width: int min_roi_height: int static_image_mode: bool @@ -574,6 +576,8 @@ def _validate(config: AppConfig) -> None: raise ConfigurationError("face ROI ratios are outside their valid range") if face.min_roi_width <= 0 or face.min_roi_height <= 0: raise ConfigurationError("face minimum ROI dimensions must be positive") + if face.roi_upscale_target < 0 or not isinstance(face.roi_square, bool): + raise ConfigurationError("face roi_square/roi_upscale_target is invalid") if not 0.0 <= face.min_detection_confidence <= 1.0 or not 0.0 <= face.min_tracking_confidence <= 1.0: raise ConfigurationError("face confidence thresholds must be in [0, 1]") pose = config.head_pose diff --git a/src/face_geometry.py b/src/face_geometry.py index f6e7c01..377518b 100644 --- a/src/face_geometry.py +++ b/src/face_geometry.py @@ -14,10 +14,15 @@ def create_face_roi(person: TrackedPerson, frame_width: int, frame_height: int, candidate_height = bbox.height * config.roi_height_ratio expand_x = bbox.width * config.roi_expand_ratio expand_y = candidate_height * config.roi_expand_ratio - x1 = max(0, round(bbox.x1 - expand_x)) y1 = max(0, round(bbox.y1 - expand_y)) - x2 = min(frame_width, round(bbox.x2 + expand_x)) y2 = min(frame_height, round(bbox.y1 + candidate_height + expand_y)) + if config.roi_square: + half = (y2 - y1) / 2.0 # 縦幅と同じ幅の正方形 + x1 = max(0, round(bbox.center_x - half)) + x2 = min(frame_width, round(bbox.center_x + half)) + else: + x1 = max(0, round(bbox.x1 - expand_x)) + x2 = min(frame_width, round(bbox.x2 + expand_x)) if x2 - x1 < config.min_roi_width or y2 - y1 < config.min_roi_height: return None return FaceROI(person.track_id, x1, y1, x2, y2, bbox, person.confidence) diff --git a/src/face_processor.py b/src/face_processor.py index 97c7e2b..a3920c2 100644 --- a/src/face_processor.py +++ b/src/face_processor.py @@ -71,6 +71,11 @@ class FaceProcessor: image = frame[roi.y1:roi.y2, roi.x1:roi.x2] import cv2 + target = self.config.roi_upscale_target + longest = max(image.shape[:2]) + if target > 0 and longest < target: + scale = target / longest + image = cv2.resize(image, None, fx=scale, fy=scale, interpolation=cv2.INTER_CUBIC) output = self._mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) faces = getattr(output, "multi_face_landmarks", None) or [] if not faces: