[v4,5/6] libtuning: Add initial AWB module
diff mbox series

Message ID 20240813084451.44099-6-stefan.klug@ideasonboard.com
State Superseded
Headers show
Series
  • rkisp1: Add manual colour temperature control
Related show

Commit Message

Stefan Klug Aug. 13, 2024, 8:44 a.m. UTC
This AWB modules uses the awb function from Raspberry Pi to calculate
the needed white balance gains per colour temperature. It stores these
gains in the tuning file. Currently they are only used for the manual
colour temperature control. It is likely that they will be used with
more complex awb algorithms.

Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 .../tuning/libtuning/modules/awb/__init__.py  |  6 +++
 utils/tuning/libtuning/modules/awb/awb.py     | 42 +++++++++++++++++++
 utils/tuning/libtuning/modules/awb/rkisp1.py  | 27 ++++++++++++
 3 files changed, 75 insertions(+)
 create mode 100644 utils/tuning/libtuning/modules/awb/__init__.py
 create mode 100644 utils/tuning/libtuning/modules/awb/awb.py
 create mode 100644 utils/tuning/libtuning/modules/awb/rkisp1.py

Comments

Paul Elder Aug. 28, 2024, 7:21 a.m. UTC | #1
On Tue, Aug 13, 2024 at 10:44:22AM +0200, Stefan Klug wrote:
> This AWB modules uses the awb function from Raspberry Pi to calculate
> the needed white balance gains per colour temperature. It stores these
> gains in the tuning file. Currently they are only used for the manual
> colour temperature control. It is likely that they will be used with
> more complex awb algorithms.
> 
> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>

> ---
>  .../tuning/libtuning/modules/awb/__init__.py  |  6 +++
>  utils/tuning/libtuning/modules/awb/awb.py     | 42 +++++++++++++++++++
>  utils/tuning/libtuning/modules/awb/rkisp1.py  | 27 ++++++++++++
>  3 files changed, 75 insertions(+)
>  create mode 100644 utils/tuning/libtuning/modules/awb/__init__.py
>  create mode 100644 utils/tuning/libtuning/modules/awb/awb.py
>  create mode 100644 utils/tuning/libtuning/modules/awb/rkisp1.py
> 
> diff --git a/utils/tuning/libtuning/modules/awb/__init__.py b/utils/tuning/libtuning/modules/awb/__init__.py
> new file mode 100644
> index 000000000000..2d67f10cfc4f
> --- /dev/null
> +++ b/utils/tuning/libtuning/modules/awb/__init__.py
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2024, Ideas On Board
> +
> +from libtuning.modules.awb.awb import AWB
> +from libtuning.modules.awb.rkisp1 import AWBRkISP1
> diff --git a/utils/tuning/libtuning/modules/awb/awb.py b/utils/tuning/libtuning/modules/awb/awb.py
> new file mode 100644
> index 000000000000..5680a44fd3e3
> --- /dev/null
> +++ b/utils/tuning/libtuning/modules/awb/awb.py
> @@ -0,0 +1,42 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2024, Ideas On Board
> +
> +import logging
> +
> +from ..module import Module
> +
> +from libtuning.ctt_awb import awb
> +import numpy as np
> +
> +logger = logging.getLogger(__name__)
> +
> +
> +class AWB(Module):
> +    type = 'awb'
> +    hr_name = 'AWB (Base)'
> +    out_name = 'GenericAWB'
> +
> +    def __init__(self, *,
> +                 debug: list):
> +        super().__init__()
> +
> +        self.debug = debug
> +
> +    def do_calculation(self, images):
> +        logger.info('Starting AWB calculation')
> +
> +        imgs = [img for img in images if img.macbeth is not None]
> +
> +        gains, _, _ = awb(imgs, None, None, False)
> +        gains = np.array(gains)
> +        gains = gains.reshape(-1, 3)
> +
> +        res = []
> +        for v in gains:
> +            res.append({
> +                'ct': int(v[0]),
> +                'gains': [float(1.0 / v[1]), float(1.0 / v[2])]
> +            })
> +
> +        return res
> diff --git a/utils/tuning/libtuning/modules/awb/rkisp1.py b/utils/tuning/libtuning/modules/awb/rkisp1.py
> new file mode 100644
> index 000000000000..e3ddeb50c9a1
> --- /dev/null
> +++ b/utils/tuning/libtuning/modules/awb/rkisp1.py
> @@ -0,0 +1,27 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2024, Ideas On Board
> +#
> +# AWB module for tuning rkisp1
> +
> +from .awb import AWB
> +
> +import libtuning as lt
> +
> +
> +class AWBRkISP1(AWB):
> +    hr_name = 'AWB (RkISP1)'
> +    out_name = 'Awb'
> +
> +    def __init__(self, **kwargs):
> +        super().__init__(**kwargs)
> +
> +    def validate_config(self, config: dict) -> bool:
> +        return True
> +
> +    def process(self, config: dict, images: list, outputs: dict) -> dict:
> +        output = {}
> +
> +        output['gains'] = self.do_calculation(images)
> +
> +        return output
> -- 
> 2.43.0
>
Laurent Pinchart Aug. 29, 2024, 11:31 p.m. UTC | #2
Hi Stefan,

Thank you for the patch.

On Tue, Aug 13, 2024 at 10:44:22AM +0200, Stefan Klug wrote:
> This AWB modules uses the awb function from Raspberry Pi to calculate

s/modules/module/

> the needed white balance gains per colour temperature. It stores these
> gains in the tuning file. Currently they are only used for the manual
> colour temperature control. It is likely that they will be used with
> more complex awb algorithms.

I would drop the last two sentences as they are not relevant to the
tuning tool (unless I'm missing something).

> 
> Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> ---
>  .../tuning/libtuning/modules/awb/__init__.py  |  6 +++
>  utils/tuning/libtuning/modules/awb/awb.py     | 42 +++++++++++++++++++
>  utils/tuning/libtuning/modules/awb/rkisp1.py  | 27 ++++++++++++
>  3 files changed, 75 insertions(+)
>  create mode 100644 utils/tuning/libtuning/modules/awb/__init__.py
>  create mode 100644 utils/tuning/libtuning/modules/awb/awb.py
>  create mode 100644 utils/tuning/libtuning/modules/awb/rkisp1.py
> 
> diff --git a/utils/tuning/libtuning/modules/awb/__init__.py b/utils/tuning/libtuning/modules/awb/__init__.py
> new file mode 100644
> index 000000000000..2d67f10cfc4f
> --- /dev/null
> +++ b/utils/tuning/libtuning/modules/awb/__init__.py
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2024, Ideas On Board
> +
> +from libtuning.modules.awb.awb import AWB
> +from libtuning.modules.awb.rkisp1 import AWBRkISP1
> diff --git a/utils/tuning/libtuning/modules/awb/awb.py b/utils/tuning/libtuning/modules/awb/awb.py
> new file mode 100644
> index 000000000000..5680a44fd3e3
> --- /dev/null
> +++ b/utils/tuning/libtuning/modules/awb/awb.py
> @@ -0,0 +1,42 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2024, Ideas On Board
> +
> +import logging
> +
> +from ..module import Module
> +
> +from libtuning.ctt_awb import awb
> +import numpy as np
> +
> +logger = logging.getLogger(__name__)
> +
> +
> +class AWB(Module):
> +    type = 'awb'
> +    hr_name = 'AWB (Base)'
> +    out_name = 'GenericAWB'
> +
> +    def __init__(self, *,
> +                 debug: list):

Is the line break necessary ?

> +        super().__init__()
> +
> +        self.debug = debug
> +
> +    def do_calculation(self, images):
> +        logger.info('Starting AWB calculation')
> +
> +        imgs = [img for img in images if img.macbeth is not None]
> +
> +        gains, _, _ = awb(imgs, None, None, False)
> +        gains = np.array(gains)
> +        gains = gains.reshape(-1, 3)

Do we really need numpy for this, can you write

        res = []
        for i in range(len(gains) // 3):
            res.append({
                'ct': int(v[i*3]),
                'gains': [float(1.0 / v[i*3+1]), float(1.0 / v[i*3+2])]
            })

I suppose numpy may make it clearer, and shouldn't be a performance
issue... In that case, maybe

        return [{'ct': int(v[0]), 'gains': [float(1.0 / v[1]), float(1.0 / v[2])]} for v in gains]

or maybe that's too long. Up to you.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> +
> +        res = []
> +        for v in gains:
> +            res.append({
> +                'ct': int(v[0]),
> +                'gains': [float(1.0 / v[1]), float(1.0 / v[2])]
> +            })
> +
> +        return res
> diff --git a/utils/tuning/libtuning/modules/awb/rkisp1.py b/utils/tuning/libtuning/modules/awb/rkisp1.py
> new file mode 100644
> index 000000000000..e3ddeb50c9a1
> --- /dev/null
> +++ b/utils/tuning/libtuning/modules/awb/rkisp1.py
> @@ -0,0 +1,27 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +# Copyright (C) 2024, Ideas On Board
> +#
> +# AWB module for tuning rkisp1
> +
> +from .awb import AWB
> +
> +import libtuning as lt
> +
> +
> +class AWBRkISP1(AWB):
> +    hr_name = 'AWB (RkISP1)'
> +    out_name = 'Awb'
> +
> +    def __init__(self, **kwargs):
> +        super().__init__(**kwargs)
> +
> +    def validate_config(self, config: dict) -> bool:
> +        return True
> +
> +    def process(self, config: dict, images: list, outputs: dict) -> dict:
> +        output = {}
> +
> +        output['gains'] = self.do_calculation(images)
> +
> +        return output
Stefan Klug Aug. 30, 2024, 7:59 a.m. UTC | #3
Hi Laurent,

Thank you for the patch.

On Fri, Aug 30, 2024 at 02:31:15AM +0300, Laurent Pinchart wrote:
> Hi Stefan,
> 
> Thank you for the patch.
> 
> On Tue, Aug 13, 2024 at 10:44:22AM +0200, Stefan Klug wrote:
> > This AWB modules uses the awb function from Raspberry Pi to calculate
> 
> s/modules/module/
> 
> > the needed white balance gains per colour temperature. It stores these
> > gains in the tuning file. Currently they are only used for the manual
> > colour temperature control. It is likely that they will be used with
> > more complex awb algorithms.
> 
> I would drop the last two sentences as they are not relevant to the
> tuning tool (unless I'm missing something).
> 
> > 
> > Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > ---
> >  .../tuning/libtuning/modules/awb/__init__.py  |  6 +++
> >  utils/tuning/libtuning/modules/awb/awb.py     | 42 +++++++++++++++++++
> >  utils/tuning/libtuning/modules/awb/rkisp1.py  | 27 ++++++++++++
> >  3 files changed, 75 insertions(+)
> >  create mode 100644 utils/tuning/libtuning/modules/awb/__init__.py
> >  create mode 100644 utils/tuning/libtuning/modules/awb/awb.py
> >  create mode 100644 utils/tuning/libtuning/modules/awb/rkisp1.py
> > 
> > diff --git a/utils/tuning/libtuning/modules/awb/__init__.py b/utils/tuning/libtuning/modules/awb/__init__.py
> > new file mode 100644
> > index 000000000000..2d67f10cfc4f
> > --- /dev/null
> > +++ b/utils/tuning/libtuning/modules/awb/__init__.py
> > @@ -0,0 +1,6 @@
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +#
> > +# Copyright (C) 2024, Ideas On Board
> > +
> > +from libtuning.modules.awb.awb import AWB
> > +from libtuning.modules.awb.rkisp1 import AWBRkISP1
> > diff --git a/utils/tuning/libtuning/modules/awb/awb.py b/utils/tuning/libtuning/modules/awb/awb.py
> > new file mode 100644
> > index 000000000000..5680a44fd3e3
> > --- /dev/null
> > +++ b/utils/tuning/libtuning/modules/awb/awb.py
> > @@ -0,0 +1,42 @@
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +#
> > +# Copyright (C) 2024, Ideas On Board
> > +
> > +import logging
> > +
> > +from ..module import Module
> > +
> > +from libtuning.ctt_awb import awb
> > +import numpy as np
> > +
> > +logger = logging.getLogger(__name__)
> > +
> > +
> > +class AWB(Module):
> > +    type = 'awb'
> > +    hr_name = 'AWB (Base)'
> > +    out_name = 'GenericAWB'
> > +
> > +    def __init__(self, *,
> > +                 debug: list):
> 
> Is the line break necessary ?

Nope, that was a copy paste remnant.

> 
> > +        super().__init__()
> > +
> > +        self.debug = debug
> > +
> > +    def do_calculation(self, images):
> > +        logger.info('Starting AWB calculation')
> > +
> > +        imgs = [img for img in images if img.macbeth is not None]
> > +
> > +        gains, _, _ = awb(imgs, None, None, False)
> > +        gains = np.array(gains)
> > +        gains = gains.reshape(-1, 3)
> 
> Do we really need numpy for this, can you write
> 
>         res = []
>         for i in range(len(gains) // 3):
>             res.append({
>                 'ct': int(v[i*3]),
>                 'gains': [float(1.0 / v[i*3+1]), float(1.0 / v[i*3+2])]
>             })
> 
> I suppose numpy may make it clearer, and shouldn't be a performance
> issue... In that case, maybe
> 
>         return [{'ct': int(v[0]), 'gains': [float(1.0 / v[1]), float(1.0 / v[2])]} for v in gains]
> 
> or maybe that's too long. Up to you.

I like the expressiveness of numpy. I changed it to 

        gains = np.reshape(gains, (-1, 3))

        return [{
                    'ct': int(v[0]),
                    'gains': [float(1.0 / v[1]), float(1.0 / v[2])]
                } for v in gains]


which (to me) is still readable but more compact.

> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Thanks. 
Stefan

> 
> > +
> > +        res = []
> > +        for v in gains:
> > +            res.append({
> > +                'ct': int(v[0]),
> > +                'gains': [float(1.0 / v[1]), float(1.0 / v[2])]
> > +            })
> > +
> > +        return res
> > diff --git a/utils/tuning/libtuning/modules/awb/rkisp1.py b/utils/tuning/libtuning/modules/awb/rkisp1.py
> > new file mode 100644
> > index 000000000000..e3ddeb50c9a1
> > --- /dev/null
> > +++ b/utils/tuning/libtuning/modules/awb/rkisp1.py
> > @@ -0,0 +1,27 @@
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +#
> > +# Copyright (C) 2024, Ideas On Board
> > +#
> > +# AWB module for tuning rkisp1
> > +
> > +from .awb import AWB
> > +
> > +import libtuning as lt
> > +
> > +
> > +class AWBRkISP1(AWB):
> > +    hr_name = 'AWB (RkISP1)'
> > +    out_name = 'Awb'
> > +
> > +    def __init__(self, **kwargs):
> > +        super().__init__(**kwargs)
> > +
> > +    def validate_config(self, config: dict) -> bool:
> > +        return True
> > +
> > +    def process(self, config: dict, images: list, outputs: dict) -> dict:
> > +        output = {}
> > +
> > +        output['gains'] = self.do_calculation(images)
> > +
> > +        return output
> 
> -- 
> Regards,
> 
> Laurent Pinchart

Patch
diff mbox series

diff --git a/utils/tuning/libtuning/modules/awb/__init__.py b/utils/tuning/libtuning/modules/awb/__init__.py
new file mode 100644
index 000000000000..2d67f10cfc4f
--- /dev/null
+++ b/utils/tuning/libtuning/modules/awb/__init__.py
@@ -0,0 +1,6 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Ideas On Board
+
+from libtuning.modules.awb.awb import AWB
+from libtuning.modules.awb.rkisp1 import AWBRkISP1
diff --git a/utils/tuning/libtuning/modules/awb/awb.py b/utils/tuning/libtuning/modules/awb/awb.py
new file mode 100644
index 000000000000..5680a44fd3e3
--- /dev/null
+++ b/utils/tuning/libtuning/modules/awb/awb.py
@@ -0,0 +1,42 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Ideas On Board
+
+import logging
+
+from ..module import Module
+
+from libtuning.ctt_awb import awb
+import numpy as np
+
+logger = logging.getLogger(__name__)
+
+
+class AWB(Module):
+    type = 'awb'
+    hr_name = 'AWB (Base)'
+    out_name = 'GenericAWB'
+
+    def __init__(self, *,
+                 debug: list):
+        super().__init__()
+
+        self.debug = debug
+
+    def do_calculation(self, images):
+        logger.info('Starting AWB calculation')
+
+        imgs = [img for img in images if img.macbeth is not None]
+
+        gains, _, _ = awb(imgs, None, None, False)
+        gains = np.array(gains)
+        gains = gains.reshape(-1, 3)
+
+        res = []
+        for v in gains:
+            res.append({
+                'ct': int(v[0]),
+                'gains': [float(1.0 / v[1]), float(1.0 / v[2])]
+            })
+
+        return res
diff --git a/utils/tuning/libtuning/modules/awb/rkisp1.py b/utils/tuning/libtuning/modules/awb/rkisp1.py
new file mode 100644
index 000000000000..e3ddeb50c9a1
--- /dev/null
+++ b/utils/tuning/libtuning/modules/awb/rkisp1.py
@@ -0,0 +1,27 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Ideas On Board
+#
+# AWB module for tuning rkisp1
+
+from .awb import AWB
+
+import libtuning as lt
+
+
+class AWBRkISP1(AWB):
+    hr_name = 'AWB (RkISP1)'
+    out_name = 'Awb'
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+
+    def validate_config(self, config: dict) -> bool:
+        return True
+
+    def process(self, config: dict, images: list, outputs: dict) -> dict:
+        output = {}
+
+        output['gains'] = self.do_calculation(images)
+
+        return output