automated: linux: add video output comparison test
The test takes a screenshot from video output and compares to the
reference image. It is intended to test HDMI output from DUT.
Signed-off-by: Milosz Wasilewski <mwasilew@quicinc.com>
diff --git a/automated/linux/video/Dockerfile b/automated/linux/video/Dockerfile
new file mode 100644
index 0000000..c7dd02d
--- /dev/null
+++ b/automated/linux/video/Dockerfile
@@ -0,0 +1,4 @@
+FROM python:3
+
+COPY requirements.txt /home/
+RUN python3 -m pip install opencv-python scikit-image requests
diff --git a/automated/linux/video/compare.py b/automated/linux/video/compare.py
new file mode 100644
index 0000000..ec2d77e
--- /dev/null
+++ b/automated/linux/video/compare.py
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2024 Qualcomm Inc.
+
+import cv2
+import numpy as np
+import requests
+import sys
+from argparse import ArgumentParser
+from skimage.metrics import structural_similarity
+
+parser = ArgumentParser()
+parser.add_argument("--reference", required=True, help="Reference image path")
+auth_group = parser.add_mutually_exclusive_group()
+auth_group.add_argument(
+ "--reference-auth-user", help="Username required to download reference image"
+)
+parser.add_argument(
+ "--reference-auth-password", help="Password required to download reference image"
+)
+auth_group.add_argument(
+ "--reference-auth-token", help="Token required to download reference image"
+)
+parser.add_argument(
+ "--threshold",
+ required=True,
+ type=float,
+ help="Minimal threshold to pass the test. Value must be between 0 and 1",
+)
+parser.add_argument(
+ "--lava",
+ default=True,
+ action="store_true",
+ help="Print results in LAVA friendly format",
+)
+parser.add_argument("--no-lava", dest="lava", action="store_false")
+group = parser.add_mutually_exclusive_group(required=True)
+group.add_argument("--device", help="Video device to capture image from")
+group.add_argument("--image", help="Compared image path")
+
+args = parser.parse_args()
+
+if args.threshold < 0 or args.threshold > 1:
+ print(f"Invalid threshold: {args.threshold}")
+ sys.exit(1)
+
+first = None
+
+if args.reference.startswith("http"):
+ # download reference image
+ s = requests.Session()
+ if args.reference_auth_user and args.reference_auth_password:
+ s.auth = (args.reference_auth_user, args.reference_auth_password)
+ if args.reference_auth_token:
+ s.headers.update({"Authorization": f"Token {args.reference_auth_token}"})
+ s.stream = True
+ print(f"Retrieving reference from: {args.reference}")
+ first_resp = s.get(args.reference)
+ data = first_resp.raw.read()
+ first = cv2.imdecode(np.frombuffer(data, dtype=np.uint8), cv2.IMREAD_COLOR)
+
+else:
+ first = cv2.imread(args.reference)
+
+second = None
+
+if args.device is not None:
+ cam = cv2.VideoCapture(args.device)
+
+ if not (cam.isOpened()):
+ print(f"Could not open video device {args.device}")
+ sys.exit(1)
+
+ cam.set(cv2.CAP_PROP_FRAME_WIDTH, first.shape[1])
+ cam.set(cv2.CAP_PROP_FRAME_HEIGHT, first.shape[0])
+ ret, second = cam.read()
+ cam.release()
+ cv2.destroyAllWindows()
+
+if args.image:
+ second = cv2.imread(args.image)
+
+first_gray = cv2.cvtColor(first, cv2.COLOR_BGR2GRAY)
+second_gray = cv2.cvtColor(second, cv2.COLOR_BGR2GRAY)
+
+score, diff = structural_similarity(first_gray, second_gray, full=True)
+print("Similarity Score: {:.3f}%".format(score * 100))
+print("Required threshold: {:.3f}%".format(args.threshold * 100))
+if score < args.threshold:
+ print("Test fail")
+ if args.lava:
+ print("<LAVA_SIGNAL_TESTCASE TEST_CASE_ID=video_output RESULT=fail>")
+else:
+ print("Test pass")
+ if args.lava:
+ print("<LAVA_SIGNAL_TESTCASE TEST_CASE_ID=video_output RESULT=pass>")
diff --git a/automated/linux/video/requirements.txt b/automated/linux/video/requirements.txt
new file mode 100644
index 0000000..108d324
--- /dev/null
+++ b/automated/linux/video/requirements.txt
@@ -0,0 +1,3 @@
+opencv-python
+requests
+scikit-image
diff --git a/automated/linux/video/video.sh b/automated/linux/video/video.sh
new file mode 100755
index 0000000..6c62e12
--- /dev/null
+++ b/automated/linux/video/video.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2024 Qualcomm Inc.
+
+# shellcheck disable=SC1091
+. ../../lib/sh-test-lib
+OUTPUT="$(pwd)/output"
+RESULT_FILE="${OUTPUT}/result.txt"
+export RESULT_FILE
+REFERENCE_IMAGE=""
+REFERENCE_IMAGE_USER=""
+REFERENCE_IMAGE_PASSWORD=""
+REFERENCE_IMAGE_TOKEN=""
+THRESHOLD=0.99
+DEVICE="/dev/video0"
+IMAGE=""
+
+usage() {
+ echo "\
+ Usage: $0 [-p <pkcs11-tool>] [-t <true|false>] [-s <true|false>] [-l <true|false>]
+
+ -r <reference image>
+ -t <threshold>
+ -d <device>
+ -u <reference download username>
+ -p <reference download password>
+ -T <reference download token>
+ -i <image>
+ "
+}
+
+while getopts "p:t:d:u:r:T:i:h" opts; do
+ case "$opts" in
+ p) REFERENCE_IMAGE_PASSWORD="${OPTARG}";;
+ t) THRESHOLD="${OPTARG}";;
+ d) DEVICE="${OPTARG}";;
+ u) REFERENCE_IMAGE_USER="${OPTARG}";;
+ r) REFERENCE_IMAGE="${OPTARG}";;
+ T) REFERENCE_IMAGE_TOKEN="${OPTARG}";;
+ i) IMAGE="${OPTARG}";;
+ h|*) usage ; exit 1 ;;
+ esac
+done
+
+! check_root && error_msg "You need to be root to run this script."
+
+# Test run.
+create_out_dir "${OUTPUT}"
+
+if [ -z "${REFERENCE_IMAGE}" ]; then
+ error_msg "Reference image missing"
+fi
+
+ARGS="--lava --threshold ${THRESHOLD} --reference ${REFERENCE_IMAGE}"
+
+if [ -n "${IMAGE}" ]; then
+ ARGS="${ARGS} --image ${IMAGE}"
+fi
+
+if [ -n "${DEVICE}" ]; then
+ ARGS="${ARGS} --device ${DEVICE}"
+fi
+
+if [ -n "${REFERENCE_IMAGE_USER}" ] && [ -n "${REFERENCE_IMAGE_PASSWORD}" ]; then
+ ARGS="${ARGS} --reference-auth-user ${REFERENCE_IMAGE_USER} --reference-auth-password ${REFERENCE_IMAGE_PASSWORD}"
+elif [ -n "${REFERENCE_IMAGE_TOKEN}" ]; then
+ ARGS="${ARGS} --reference-auth-token ${REFERENCE_IMAGE_TOKEN}"
+fi
+
+# shellcheck disable=SC2086
+python3 compare.py ${ARGS}
diff --git a/automated/linux/video/video.yaml b/automated/linux/video/video.yaml
new file mode 100644
index 0000000..ff59c22
--- /dev/null
+++ b/automated/linux/video/video.yaml
@@ -0,0 +1,43 @@
+metadata:
+ format: Lava-Test Test Definition 1.0
+ name: video-compare
+ description: |
+ The test compares two images. The second image
+ can be either captured from v4l2 device by the script
+ or delivered to the script from outside.
+
+ Main purpose of the test is to verify video output
+ using a capture device connected to DUT
+
+ The test script should run on host, where the capture device is connected.
+
+ maintainer:
+ - mwasilew@quicinc.com
+ os:
+ - debian
+ - ubuntu
+ - centos
+ - fedora
+ - openembedded
+ scope:
+ - functional
+ devices:
+ - imx8mm
+ - imx6ull
+
+params:
+ # https://example.com/image.jpg
+ REFERENCE_IMAGE: ""
+ REFERENCE_IMAGE_USER: ""
+ REFERENCE_IMAGE_PASSWORD: ""
+ REFERENCE_IMAGE_TOKEN: ""
+ THRESHOLD: 0.99
+ DEVICE: "/dev/video0"
+ # /home/user/image.jpg
+ IMAGE: ""
+
+run:
+ steps:
+ - cd ./automated/linux/video/
+ - ./video.sh -r "${REFERENCE_IMAGE}" -t "${THRESHOLD}" -d "${DEVICE}" -u "${REFERENCE_IMAGE_USER}" -p "${REFERENCE_IMAGE_PASSWORD}" -T "${REFERENCE_IMAGE_TOKEN}" -i "${IMAGE}"
+ - ../../utils/send-to-lava.sh ./output/result.txt