From 8cc0b39e28e5225de3d83ef7b5e754e839b2de06 Mon Sep 17 00:00:00 2001 From: Fernando Bravo Date: Wed, 11 Oct 2023 15:52:10 +0200 Subject: [PATCH] Add camera quality test New camera quality test using brisque algorithm included in "camera-cert-automated" --- providers/base/bin/camera_quality_test.py | 86 +++++++++++++++++++++++ providers/base/units/camera/jobs.pxu | 26 +++++-- providers/base/units/camera/test-plan.pxu | 2 + 3 files changed, 110 insertions(+), 4 deletions(-) create mode 100755 providers/base/bin/camera_quality_test.py diff --git a/providers/base/bin/camera_quality_test.py b/providers/base/bin/camera_quality_test.py new file mode 100755 index 0000000000..58c48aa114 --- /dev/null +++ b/providers/base/bin/camera_quality_test.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# +# This file is part of Checkbox. +# +# Copyright 2008-2023 Canonical Ltd. +# Written by: +# Fernando Bravo +# +# Checkbox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# +# Checkbox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Checkbox. If not, see . +# + +import argparse +import sys + +from cv2 import VideoCapture, imwrite +from numpy import isnan + +from checkbox_support.vendor.brisque import BRISQUE +from tempfile import NamedTemporaryFile + +THRESHOLD = 60 + + +def brisque(device: str = "video0"): + """ + Captures an image to a file and computes the quality using the + Blinded/Unreferenced Spatial Image Quality Evaluator (BRISQUE). If the + score is below a certain threshold, the test passes. + """ + + brisque = BRISQUE() + + # Set the video device + cam = VideoCapture(f"/dev/{device}") + if not cam.isOpened(): + print("Cannot open the selected device", file=sys.stderr) + return 1 + + # Discard the first frames + for i in range(15): + if not cam.grab(): + print("Cannot read from the selected device", file=sys.stderr) + return 1 + + # Get the image + result, image = cam.read() + if not result: + print("Cannot read from the selected device", file=sys.stderr) + return 1 + + # Save it in a temporary file + f = NamedTemporaryFile(prefix=f'camera_test_brisque_{device}_', + suffix='.jpg', delete=False) + imwrite(f.name, image) + print("Image saved to %s" % f.name) + + # Compute the BRISQUE score + score = brisque.score(f.name) + if isnan(score): + print("Unable to compute BRISQUE score", file=sys.stderr) + return 1 + elif score > THRESHOLD: + print("The BRISQUE score is too high: %s" % score, file=sys.stderr) + return 1 + + print("BRISQUE score: %s" % score) + return 0 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Run the image quality test") + parser.add_argument("-d", "--device", default="video0", + help="Device for the webcam to use") + args = parser.parse_args() + + sys.exit(brisque(args.device)) diff --git a/providers/base/units/camera/jobs.pxu b/providers/base/units/camera/jobs.pxu index 00a1826a9a..b9c977ed0a 100644 --- a/providers/base/units/camera/jobs.pxu +++ b/providers/base/units/camera/jobs.pxu @@ -109,16 +109,34 @@ estimated_duration: 1.2 depends: camera/detect requires: {%- if __on_ubuntucore__ %} - executable.name == 'fswebcam' - {%- else %} - package.name == 'fswebcam' or package.name == 'gir1.2-gst-plugins-base-1.0' - {% endif -%} + executable.name == 'fswebcam' + {%- else %} + package.name == 'fswebcam' or package.name == 'gir1.2-gst-plugins-base-1.0' + {% endif -%} command: camera_test.py resolutions -d /dev/{{ name }} _description: Takes multiple pictures based on the resolutions supported by the camera and validates their size and that they are of a valid format. +unit: template +template-resource: device +template-filter: device.category == 'CAPTURE' and device.name != '' +template-unit: job +plugin: shell +template-engine: jinja2 +category_id: com.canonical.plainbox::camera +id: camera/camera-quality_{{ name }} +flags: also-after-suspend +_summary: Webcam brisque score for {{ product_slug }} +estimated_duration: 20s +depends: camera/detect +command: + camera_quality_test.py -d {{ name }} +_description: + Takes multiple pictures and computes the quality based on a No-Reference image + quality assessment algorithm called BRISQUE. + unit: template template-resource: device template-filter: device.category == 'MMAL' and device.name != '' diff --git a/providers/base/units/camera/test-plan.pxu b/providers/base/units/camera/test-plan.pxu index db75da7052..ce0f93d5d6 100644 --- a/providers/base/units/camera/test-plan.pxu +++ b/providers/base/units/camera/test-plan.pxu @@ -36,6 +36,7 @@ _description: Camera tests (automated) include: camera/detect certification-status=blocker camera/multiple-resolution-images_.* certification-status=blocker + camera/camera-quality_.* certification-status=non-blocker bootstrap_include: device @@ -68,6 +69,7 @@ _description: Camera tests After Suspend (automated) include: after-suspend-camera/detect certification-status=blocker after-suspend-camera/multiple-resolution-images_.* certification-status=blocker + camera/camera-quality_* certification-status=non-blocker bootstrap_include: device