1#!/usr/bin/env python3
2# SPDX-License-Identifier: Apache-2.0
3# -----------------------------------------------------------------------------
4# Copyright 2021-2022 Arm Limited
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may not
7# use this file except in compliance with the License. You may obtain a copy
8# of the License at:
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17# -----------------------------------------------------------------------------
18"""
19The ``astc_quality_test`` utility provides a tool to sweep quality settings.
20"""
21
22import numpy as np
23import re
24import subprocess as sp
25import sys
26
27
28def get_psnr_pattern():
29    return r"\s*PSNR \(LDR-RGB\):\s*([0-9.]*) dB"
30
31
32def get_coding_rate_pattern():
33    return r"\s*Coding rate:\s*([0-9.]*) MT/s"
34
35
36def parse_output(output):
37    # Regex pattern for image quality
38    patternPSNR = re.compile(get_psnr_pattern())
39    patternCRate = re.compile(get_coding_rate_pattern())
40
41    # Extract results from the log
42    runPSNR = None
43    runCRate = None
44
45    for line in output:
46        match = patternPSNR.match(line)
47        if match:
48            runPSNR = float(match.group(1))
49
50        match = patternCRate.match(line)
51        if match:
52            runCRate = float(match.group(1))
53
54    assert runPSNR is not None, "No coding PSNR found"
55    assert runCRate is not None, "No coding rate found"
56    return (runPSNR, runCRate)
57
58def execute(command):
59    """
60    Run a subprocess with the specified command.
61
62    Args:
63        command (list(str)): The list of command line arguments.
64
65    Returns:
66        list(str): The output log (stdout) split into lines.
67    """
68    try:
69        result = sp.run(command, stdout=sp.PIPE, stderr=sp.PIPE,
70                        check=True, universal_newlines=True)
71    except (OSError, sp.CalledProcessError):
72        print("ERROR: Test run failed")
73        print("  + %s" % " ".join(command))
74        qcommand = ["\"%s\"" % x for x in command]
75        print("  + %s" % ", ".join(qcommand))
76        sys.exit(1)
77
78    return result.stdout.splitlines()
79
80def main():
81    """
82    The main function.
83
84    Returns:
85        int: The process return code.
86    """
87    for block in ("4x4", "5x5", "6x6", "8x8", "10x10"):
88
89        for quality in range (0, 101, 2):
90
91            resultsQ = []
92            resultsS = []
93
94            if (quality < 40):
95                repeats = 20
96            elif (quality < 75):
97                repeats = 10
98            else:
99                repeats = 5
100
101            for _ in range(0, repeats):
102                command = [
103                    "./bin/astcenc-avx2",
104                    "-tl",
105                    "./Test/Images/Kodak/LDR-RGB/ldr-rgb-kodak23.png",
106                    "/dev/null",
107                    block,
108                    "%s" % quality,
109                    "-silent"
110                ]
111
112                stdout = execute(command)
113                psnr, mts = parse_output(stdout)
114                resultsQ.append(psnr)
115                resultsS.append(mts)
116
117            print("%s, %u, %0.3f, %0.3f" % (block, quality, np.mean(resultsS), np.mean(resultsQ)))
118
119
120    return 0
121
122
123if __name__ == "__main__":
124    sys.exit(main())
125