Skip to content

Commit aba0049

Browse files
committed
Enforce minimum photo quality component scores
1 parent 88e6f60 commit aba0049

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

evaluation_function/evaluation_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,22 @@ def test_image_quality_score_uses_student_friendly_threshold(self):
141141
blurry_quality["quality_accept_score"],
142142
)
143143

144+
def test_image_quality_rejects_low_single_component_score(self):
145+
gradient = np.tile(np.linspace(30, 230, 160, dtype=np.uint8), (120, 1))
146+
image = cv2.cvtColor(gradient, cv2.COLOR_GRAY2BGR)
147+
148+
quality = compute_image_quality_metrics(image)
149+
150+
self.assertGreaterEqual(
151+
quality["quality_score"],
152+
quality["quality_accept_score"],
153+
)
154+
self.assertLessEqual(
155+
quality["sharpness_score_100"],
156+
quality["quality_min_component_score"],
157+
)
158+
self.assertFalse(quality["quality_pass"])
159+
144160

145161
if __name__ == "__main__":
146162
unittest.main()

evaluation_function/yolo_pipeline.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
# The fail threshold is intentionally permissive so borderline usable photos are
7171
# not rejected while obviously dark/blurry/noisy ones are sent back for retake.
7272
QUALITY_ACCEPT_SCORE: int = int(os.environ.get("QUALITY_ACCEPT_SCORE", "40"))
73+
QUALITY_MIN_COMPONENT_SCORE: int = int(os.environ.get("QUALITY_MIN_COMPONENT_SCORE", "20"))
7374
QUALITY_BRIGHTNESS_USABLE_MIN: float = 35.0
7475
QUALITY_BRIGHTNESS_IDEAL_MIN: float = 60.0
7576
QUALITY_BRIGHTNESS_IDEAL_MAX: float = 210.0
@@ -833,6 +834,19 @@ def compute_image_quality_metrics(img_bgr: np.ndarray) -> Dict[str, Any]:
833834
)))
834835
if contrast_component <= 0.0 and sharpness_component <= 0.0:
835836
quality_score = min(quality_score, QUALITY_ACCEPT_SCORE - 1)
837+
brightness_score_100 = _score100(brightness_component)
838+
contrast_score_100 = _score100(contrast_component)
839+
sharpness_score_100 = _score100(sharpness_component)
840+
noise_score_100 = _score100(noise_component)
841+
component_pass = all(
842+
score > QUALITY_MIN_COMPONENT_SCORE
843+
for score in (
844+
brightness_score_100,
845+
contrast_score_100,
846+
sharpness_score_100,
847+
noise_score_100,
848+
)
849+
)
836850
advice = _quality_advice(
837851
brightness_mean=brightness_mean,
838852
contrast_component=contrast_component,
@@ -845,14 +859,15 @@ def compute_image_quality_metrics(img_bgr: np.ndarray) -> Dict[str, Any]:
845859
"contrast_std": contrast_std,
846860
"sharpness_score": sharpness_score,
847861
"noise_score": noise_score,
848-
"brightness_score": _score100(brightness_component),
849-
"contrast_score": _score100(contrast_component),
850-
"sharpness_score_100": _score100(sharpness_component),
851-
"noise_score_100": _score100(noise_component),
862+
"brightness_score": brightness_score_100,
863+
"contrast_score": contrast_score_100,
864+
"sharpness_score_100": sharpness_score_100,
865+
"noise_score_100": noise_score_100,
852866
"quality_score": quality_score,
853867
"quality_score_max": 100,
854868
"quality_accept_score": QUALITY_ACCEPT_SCORE,
855-
"quality_pass": quality_score >= QUALITY_ACCEPT_SCORE,
869+
"quality_min_component_score": QUALITY_MIN_COMPONENT_SCORE,
870+
"quality_pass": quality_score >= QUALITY_ACCEPT_SCORE and component_pass,
856871
"quality_advice": advice,
857872
}
858873

0 commit comments

Comments
 (0)