[libcamera-devel,v2] utils: rkisp1: gen-csc-table: Add support for inverting the CSC
diff mbox series

Message ID 20220930190711.13834-1-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • [libcamera-devel,v2] utils: rkisp1: gen-csc-table: Add support for inverting the CSC
Related show

Commit Message

Laurent Pinchart Sept. 30, 2022, 7:07 p.m. UTC
Add a -i/--invert command line argument to invert the YCbCr encoding and
output a YCbCr to RGB matrix.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
---
Changes since v1:

- Fix inverted CSC calculation
- Perform simple rounding for inverted CSC
---
 utils/rkisp1/gen-csc-table.py | 31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)


base-commit: ed591e705c451d0ce14988ae96829a31a2ae2f9a

Comments

Kieran Bingham Sept. 30, 2022, 7:25 p.m. UTC | #1
Quoting Laurent Pinchart via libcamera-devel (2022-09-30 20:07:11)
> Add a -i/--invert command line argument to invert the YCbCr encoding and
> output a YCbCr to RGB matrix.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
> Changes since v1:
> 
> - Fix inverted CSC calculation
> - Perform simple rounding for inverted CSC
> ---
>  utils/rkisp1/gen-csc-table.py | 31 +++++++++++++++++++++----------
>  1 file changed, 21 insertions(+), 10 deletions(-)
> 
> diff --git a/utils/rkisp1/gen-csc-table.py b/utils/rkisp1/gen-csc-table.py
> index 2fb702746421..f93e7cfacab6 100755
> --- a/utils/rkisp1/gen-csc-table.py
> +++ b/utils/rkisp1/gen-csc-table.py
> @@ -7,6 +7,7 @@
>  
>  import argparse
>  import enum
> +import numpy as np
>  import sys
>  
>  
> @@ -63,9 +64,8 @@ class Quantization(enum.Enum):
>      LIMITED = 1
>  
>  
> -def scale_coeff(coeff, quantization, luma, precision):
> -    """Scale a coefficient to the output range dictated by the quantization and
> -    the precision.
> +def scale_coeff(coeff, quantization, luma):
> +    """Scale a coefficient to the output range dictated by the quantization.
>  
>      Parameters
>      ----------
> @@ -75,9 +75,6 @@ def scale_coeff(coeff, quantization, luma, precision):
>          The quantization, either FULL or LIMITED
>      luma : bool
>          True if the coefficient corresponds to a luma value, False otherwise
> -    precision : int
> -        The desired precision for the scaled coefficient as a number of
> -        fractional bits
>      """
>  
>      # Assume the input range is 8 bits. The output range is set by the
> @@ -91,7 +88,7 @@ def scale_coeff(coeff, quantization, luma, precision):
>      else:
>          out_range = 240 - 16
>  
> -    return coeff * out_range / in_range * (1 << precision)
> +    return coeff * out_range / in_range
>  
>  
>  def round_array(values):
> @@ -150,6 +147,8 @@ def main(argv):
>          description='Generate color space conversion table coefficients with '
>          'configurable fixed-point precision.'
>      )
> +    parser.add_argument('--invert', '-i', action='store_true',
> +                        help='Invert the color space conversion (YUV -> RGB)')
>      parser.add_argument('--precision', '-p', default='Q1.7',
>                          help='The output fixed point precision in Q notation (sign bit excluded)')
>      parser.add_argument('--quantization', '-q', choices=['full', 'limited'],
> @@ -171,13 +170,25 @@ def main(argv):
>      luma = True
>      scaled_coeffs = []
>      for line in encoding:
> -        line = [scale_coeff(coeff, quantization, luma, precision.fractional) for coeff in line]
> +        line = [scale_coeff(coeff, quantization, luma) for coeff in line]
>          scaled_coeffs.append(line)
>          luma = False
>  
> +    if args.invert:
> +        scaled_coeffs = np.linalg.inv(scaled_coeffs)
> +
>      rounded_coeffs = []
>      for line in scaled_coeffs:
> -        line = round_array(line)
> +        line = [coeff * (1 << precision.fractional) for coeff in line]
> +        # For the RGB to YUV conversion, use a rounding method that preserves
> +        # the rounded sum of each line to avoid biases and overflow, as the sum
> +        # of luma and chroma coefficients should be 1.0 and 0.0 respectively
> +        # (in full range). The the YUV to RGB conversion, there is no such

The the

Presumably that should be 'In the', or 'For the'.


Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

> +        # constraint, so use simple rounding.
> +        if args.invert:
> +            line = [round(coeff) for coeff in line]
> +        else:
> +            line = round_array(line)
>  
>          # Convert coefficients to the number of bits selected by the precision.
>          # Negative values will be turned into positive integers using 2's
> @@ -188,7 +199,7 @@ def main(argv):
>      # Print the result as C code.
>      nbits = 1 << (precision.total - 1).bit_length()
>      nbytes = nbits // 4
> -    print(f'static const u{nbits} rgb2yuv_{args.encoding}_{quantization.name.lower()}_coeffs[] = {{')
> +    print(f'static const u{nbits} {"yuv2rgb" if args.invert else "rgb2yuv"}_{args.encoding}_{quantization.name.lower()}_coeffs[] = {{')
>  
>      for line in rounded_coeffs:
>          line = [f'0x{coeff:0{nbytes}x}' for coeff in line]
> 
> base-commit: ed591e705c451d0ce14988ae96829a31a2ae2f9a
> -- 
> Regards,
> 
> Laurent Pinchart
>

Patch
diff mbox series

diff --git a/utils/rkisp1/gen-csc-table.py b/utils/rkisp1/gen-csc-table.py
index 2fb702746421..f93e7cfacab6 100755
--- a/utils/rkisp1/gen-csc-table.py
+++ b/utils/rkisp1/gen-csc-table.py
@@ -7,6 +7,7 @@ 
 
 import argparse
 import enum
+import numpy as np
 import sys
 
 
@@ -63,9 +64,8 @@  class Quantization(enum.Enum):
     LIMITED = 1
 
 
-def scale_coeff(coeff, quantization, luma, precision):
-    """Scale a coefficient to the output range dictated by the quantization and
-    the precision.
+def scale_coeff(coeff, quantization, luma):
+    """Scale a coefficient to the output range dictated by the quantization.
 
     Parameters
     ----------
@@ -75,9 +75,6 @@  def scale_coeff(coeff, quantization, luma, precision):
         The quantization, either FULL or LIMITED
     luma : bool
         True if the coefficient corresponds to a luma value, False otherwise
-    precision : int
-        The desired precision for the scaled coefficient as a number of
-        fractional bits
     """
 
     # Assume the input range is 8 bits. The output range is set by the
@@ -91,7 +88,7 @@  def scale_coeff(coeff, quantization, luma, precision):
     else:
         out_range = 240 - 16
 
-    return coeff * out_range / in_range * (1 << precision)
+    return coeff * out_range / in_range
 
 
 def round_array(values):
@@ -150,6 +147,8 @@  def main(argv):
         description='Generate color space conversion table coefficients with '
         'configurable fixed-point precision.'
     )
+    parser.add_argument('--invert', '-i', action='store_true',
+                        help='Invert the color space conversion (YUV -> RGB)')
     parser.add_argument('--precision', '-p', default='Q1.7',
                         help='The output fixed point precision in Q notation (sign bit excluded)')
     parser.add_argument('--quantization', '-q', choices=['full', 'limited'],
@@ -171,13 +170,25 @@  def main(argv):
     luma = True
     scaled_coeffs = []
     for line in encoding:
-        line = [scale_coeff(coeff, quantization, luma, precision.fractional) for coeff in line]
+        line = [scale_coeff(coeff, quantization, luma) for coeff in line]
         scaled_coeffs.append(line)
         luma = False
 
+    if args.invert:
+        scaled_coeffs = np.linalg.inv(scaled_coeffs)
+
     rounded_coeffs = []
     for line in scaled_coeffs:
-        line = round_array(line)
+        line = [coeff * (1 << precision.fractional) for coeff in line]
+        # For the RGB to YUV conversion, use a rounding method that preserves
+        # the rounded sum of each line to avoid biases and overflow, as the sum
+        # of luma and chroma coefficients should be 1.0 and 0.0 respectively
+        # (in full range). The the YUV to RGB conversion, there is no such
+        # constraint, so use simple rounding.
+        if args.invert:
+            line = [round(coeff) for coeff in line]
+        else:
+            line = round_array(line)
 
         # Convert coefficients to the number of bits selected by the precision.
         # Negative values will be turned into positive integers using 2's
@@ -188,7 +199,7 @@  def main(argv):
     # Print the result as C code.
     nbits = 1 << (precision.total - 1).bit_length()
     nbytes = nbits // 4
-    print(f'static const u{nbits} rgb2yuv_{args.encoding}_{quantization.name.lower()}_coeffs[] = {{')
+    print(f'static const u{nbits} {"yuv2rgb" if args.invert else "rgb2yuv"}_{args.encoding}_{quantization.name.lower()}_coeffs[] = {{')
 
     for line in rounded_coeffs:
         line = [f'0x{coeff:0{nbytes}x}' for coeff in line]