[{"id":24386,"web_url":"https://patchwork.libcamera.org/comment/24386/","msgid":"<YuxuKqZZpKl8rZF8@pendragon.ideasonboard.com>","date":"2022-08-05T01:11:06","subject":"Re: [libcamera-devel] [PATCH 3/3] ipa: rkisp1: Add support of\n\tDe-noise Pre-Filter control","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Florian,\n\nThank you for the patch.\n\nOn Thu, Aug 04, 2022 at 04:12:28PM +0200, Florian Sylvestre via libcamera-devel wrote:\n> The De-noise pre-filter algorithm is a bilateral filter which combines a range\n\nI would write \"de-noise\" without a capital D, and probably \"denoise\"\nactually. Same below where applicable.\n\n> filter and a domain filter. The De-noise pre-filter is applied before\n> demosaicing.\n> \n> Signed-off-by: Florian Sylvestre <fsylvestre@baylibre.com>\n> ---\n>  src/ipa/rkisp1/algorithms/dpf.cpp     | 279 ++++++++++++++++++++++++++\n>  src/ipa/rkisp1/algorithms/dpf.h       |  36 ++++\n>  src/ipa/rkisp1/algorithms/meson.build |   1 +\n>  src/ipa/rkisp1/data/ov5640.yaml       |  11 +\n>  src/ipa/rkisp1/ipa_context.cpp        |  11 +\n>  src/ipa/rkisp1/ipa_context.h          |   5 +\n>  6 files changed, 343 insertions(+)\n>  create mode 100644 src/ipa/rkisp1/algorithms/dpf.cpp\n>  create mode 100644 src/ipa/rkisp1/algorithms/dpf.h\n> \n> diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp\n> new file mode 100644\n> index 00000000..d99bb728\n> --- /dev/null\n> +++ b/src/ipa/rkisp1/algorithms/dpf.cpp\n> @@ -0,0 +1,279 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021-2022, Ideas On Board\n> + *\n> + * dpf.cpp - RkISP1 De-noise Pre-Filter control\n> + */\n> +\n> +#include \"dpf.h\"\n> +\n> +#include <cmath>\n> +\n> +#include <libcamera/base/log.h>\n> +\n> +#include <libcamera/control_ids.h>\n> +#include \"linux/rkisp1-config.h\"\n> +\n> +/**\n> + * \\file dpf.h\n> + */\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa::rkisp1::algorithms {\n> +\n> +/**\n> + * \\class Dpf\n> + * \\brief RkISP1 De-noise Pre-Filter control\n> + *\n> + * The De-noise pre-filter algorithm is a bilateral filter which combines a\n> + * range filter and a domain filter. The De-noise pre-filter is applied before\n> + * demosaicing.\n> + */\n> +\n> +LOG_DEFINE_CATEGORY(RkISP1Dpf)\n> +\n> +Dpf::Dpf()\n> +\t: initialized_(false), config_({}), strength_config_({})\n> +{\n> +}\n> +\n> +/**\n> + * \\copydoc libcamera::ipa::Algorithm::init\n> + */\n> +int Dpf::init([[maybe_unused]] IPAContext &context,\n> +\t      const YamlObject &tuningData)\n> +{\n> +\tstd::vector<double> values;\n> +\n> +\t/*\n> +\t * The domain kernel is configured with a 9x9 kernel for the green\n> +\t * pixels, and a 13x9 or 9x9 kernel for red and blue pixels.\n> +\t */\n> +\tconst YamlObject &dFObject = tuningData[\"DomainFilter\"];\n> +\tif (!dFObject.isDictionary()) {\n> +\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t<< \"Issue while parsing 'DomainFilter' in tuning \"\n> +\t\t\t<< \"file: entry must be a dictionary\";\n> +\t\treturn -EINVAL;\n> +\t}\n\nI think you could drop the error handling here. If dFObject isn't\ncorrect, then the check on dFObject[\"g\"] below will fail, and that\nshould be good enough.\n\n> +\n> +\t/*\n> +\t * For the green component, we have the 9x9 kernel specified\n> +\t * as 6 coefficients:\n> +\t *    Y\n> +\t *    ^\n> +\t *  4 | 6   5   4   5   6\n> +\t *  3 |   5   3   3   5\n> +\t *  2 | 5   3   2   3   5\n> +\t *  1 |   3   1   1   3\n> +\t *  0 - 4   2   0   2   4\n> +\t * -1 |   3   1   1   3\n> +\t * -2 | 5   3   2   3   5\n> +\t * -3 |   5   3   3   5\n> +\t * -4 | 6   5   4   5   6\n> +\t *    +---------|--------> X\n> +\t *     -4....-1 0 1 2 3 4\n> +\t */\n> +\tvalues = dFObject[\"g\"].getList<double>().value_or(utils::defopt);\n> +\tif (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) {\n> +\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t<< \"Invalid 'DomainFilter:g': expected \"\n> +\t\t\t<< RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS\n> +\t\t\t<< \" elements, got \" << values.size();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tfor (unsigned int i = 0; i < values.size(); ++i) {\n> +\t\tconfig_.g_flt.spatial_coeff[i] = std::round(values[i] * 16);\n> +\t}\n\nNo need for curly braces.\n\nI wonder if we should store the values as integers in the config file ?\nThat would simplify the code here, you could then even write it as\n\n\tstd::copy_n(values.begin(), values.size(),\n\t\t    std::begin(config_.g_flt.spatial_coeff));\n\n> +\n> +\tconfig_.g_flt.gr_enable = true;\n> +\tconfig_.g_flt.gb_enable = true;\n> +\n> +\t/*\n> +\t * For the red and blue components, we have the 13x9 kernel specified\n> +\t * as 6 coefficients:\n> +\t *\n> +\t *    Y\n> +\t *    ^\n> +\t *  4 | 6   5   4   3   4   5   6\n> +\t *    |\n> +\t *  2 | 5   4   2   1   2   4   5\n> +\t *    |\n> +\t *  0 - 5   3   1   0   1   3   5\n> +\t *    |\n> +\t * -2 | 5   4   2   1   2   4   5\n> +\t *    |\n> +\t * -4 | 6   5   4   3   4   5   6\n> +\t *    +-------------|------------> X\n> +\t *     -6  -4  -2   0   2   4   6\n> +\t *\n> +\t * For a 9x9 kernel, columns -6 and -6 are dropped, so coefficient\n\n\"-6 and 6\"\n\n> +\t * number 6 is not used.\n> +\t */\n> +\tvalues = dFObject[\"rb\"].getList<double>().value_or(utils::defopt);\n> +\tif (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS &&\n> +\t    values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1) {\n> +\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t<< \"Invalid 'DomainFilter:rb': expected \"\n> +\t\t\t<< RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1\n> +\t\t\t<< \" or \" << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS\n> +\t\t\t<< \" elements, got \" << values.size();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tconfig_.rb_flt.fltsize = values.size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS\n> +\t\t\t       ? RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9\n> +\t\t\t       : RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9;\n\nI wonder if there would ever be a use case for switching between two\ndifferent filter sizes at runtime. Not something we need to bother with\nfor now, this looks nice.\n\n> +\n> +\tfor (unsigned int i = 0; i < values.size(); ++i) {\n> +\t\tconfig_.rb_flt.spatial_coeff[i] = std::round(values[i] * 16);\n> +\t}\n\nSame as above.\n\n> +\n> +\tconfig_.rb_flt.r_enable = true;\n> +\tconfig_.rb_flt.b_enable = true;\n> +\n> +\t/*\n> +\t * The range kernel is configured with a noise level lookup table (NLL)\n> +\t * which stores a piecewise linear function that characterizes the\n> +\t * sensor noise profile as a noise level function curve (NLF).\n> +\t */\n> +\tconst YamlObject &rFObject = tuningData[\"RangeFilter\"];\n\nThe data in the tuning file describe the noise level function, so I'd\nname the element \"NoiseLevelFunction\" or something similar.\n\n> +\tif (!rFObject.isDictionary()) {\n> +\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t<< \"Issue while parsing 'RangeFilter' in tuning \"\n> +\t\t\t<< \"file: entry must be a dictionary\";\n> +\t\treturn -EINVAL;\n> +\t}\n\nSame as above for the error check.\n\n> +\n> +\tvalues = rFObject[\"coeff\"].getList<double>().value_or(utils::defopt);\n> +\tif (values.size() != RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) {\n> +\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t<< \"Invalid 'RangeFilter:coeff': expected \"\n> +\t\t\t<< RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS\n> +\t\t\t<< \" elements, got \" << values.size();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tfor (unsigned int i = 0; i < values.size(); ++i) {\n> +\t\tconfig_.nll.coeff[i] = std::round(values[i] * 1024);\n> +\t}\n> +\n> +\tstd::string scaleMode = rFObject[\"scale-mode\"].get<std::string>(\"\");\n> +\tif (scaleMode != \"linear\" && scaleMode != \"logarithmic\") {\n> +\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t<< \"Invalid 'RangeFilter:scale-mode': expected \"\n> +\t\t\t<< \"'linear' or 'logarithmic' value, got \"\n> +\t\t\t<< scaleMode;\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tconfig_.nll.scale_mode = scaleMode == \"linear\"\n> +\t\t\t       ? RKISP1_CIF_ISP_NLL_SCALE_LINEAR\n> +\t\t\t       : RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC;\n\nYou could avoid comparing to \"linear\" twice:\n\n\tif (scaleMode == \"linear\") {\n\t\tconfig_.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LINEAR;\n\t} else if (scaleMode == \"logarithmic\") {\n\t\tconfig_.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC;\n\t} else {\n\t\tLOG(RkISP1Dpf, Error)\n\t\t\t<< \"Invalid 'RangeFilter:scale-mode': expected \"\n\t\t\t<< \"'linear' or 'logarithmic' value, got \"\n\t\t\t<< scaleMode;\n\t\treturn -EINVAL;\n\t}\n\n(I wish a switch/case on a string would be possible)\n\n> +\n> +\tconst YamlObject &fSObject = tuningData[\"FilterStrength\"];\n> +\tif (!fSObject.isDictionary()) {\n> +\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t<< \"Issue while parsing 'FilterStrength' in tuning \"\n> +\t\t\t<< \"file: entry must be a dictionary\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tstrength_config_.r = fSObject[\"r\"].get<uint16_t>(64);\n> +\tstrength_config_.g = fSObject[\"g\"].get<uint16_t>(64);\n> +\tstrength_config_.b = fSObject[\"b\"].get<uint16_t>(64);\n> +\n> +\tinitialized_ = true;\n> +\n> +\treturn 0;\n> +}\n> +\n> +/**\n> + * \\copydoc libcamera::ipa::Algorithm::queueRequest\n> + */\n> +void Dpf::queueRequest(IPAContext &context,\n> +\t\t       [[maybe_unused]] const uint32_t frame,\n> +\t\t       const ControlList &controls)\n> +{\n> +\tauto &dpf = context.frameContext.dpf;\n> +\n> +\tconst auto &denoise = controls.get(controls::draft::NoiseReductionMode);\n> +\tif (denoise) {\n> +\t\tLOG(RkISP1Dpf, Debug) << \"Set denoise to \" << *denoise;\n> +\n> +\t\tswitch (*denoise) {\n> +\t\tcase controls::draft::NoiseReductionModeOff:\n> +\t\t\tdpf.denoise = false;\n> +\t\t\tdpf.updateParams = true;\n> +\t\t\tbreak;\n> +\t\tcase controls::draft::NoiseReductionModeMinimal:\n> +\t\tcase controls::draft::NoiseReductionModeHighQuality:\n> +\t\tcase controls::draft::NoiseReductionModeFast:\n> +\t\t\tdpf.denoise = true;\n> +\t\t\tdpf.updateParams = true;\n> +\t\t\tbreak;\n> +\t\tdefault:\n> +\t\t\tLOG(RkISP1Dpf, Error)\n> +\t\t\t\t<< \"Unsupported denoise value \"\n> +\t\t\t\t<< *denoise;\n> +\t\t}\n> +\t}\n> +}\n> +\n> +/**\n> + * \\copydoc libcamera::ipa::Algorithm::prepare\n> + */\n> +void Dpf::prepare(IPAContext &context, rkisp1_params_cfg *params)\n> +{\n> +\tauto &dpf = context.frameContext.dpf;\n> +\tauto &awb = context.configuration.awb;\n> +\tauto &lsc = context.configuration.lsc;\n> +\tauto &dpf_config = params->others.dpf_config;\n> +\tauto &dpf_strength_config = params->others.dpf_strength_config;\n> +\n> +\tif ((context.frameContext.frameCount > 0) && (!dpf.updateParams))\n\nNo need for the inner parentheses.\n\n> +\t\treturn;\n> +\n> +\tif (!initialized_)\n> +\t\treturn;\n\nMove this to the very beginning, before the variables.\n\n> +\n> +\t/*\n> +\t * We must copy the static configuration each time we modify a\n> +\t * parameter in the config because the strucure is zeroed between each\n> +\t * call.\n> +\t */\n> +\tdpf_config = config_;\n> +\tdpf_strength_config = strength_config_;\n> +\n> +\tif (dpf.updateParams) {\n> +\t\tif (!dpf.denoise || (!awb.enabled && !lsc.enabled)) {\n> +\t\t\tdpf_config.gain.mode =\n> +\t\t\t\tRKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED;\n> +\t\t} else if (awb.enabled && lsc.enabled) {\n> +\t\t\tdpf_config.gain.mode =\n> +\t\t\t\tRKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS;\n> +\t\t} else if (awb.enabled) {\n> +\t\t\tdpf_config.gain.mode =\n> +\t\t\t\tRKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS;\n> +\t\t} else { /* lsc.enabled only */\n> +\t\t\tdpf_config.gain.mode =\n> +\t\t\t\tRKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS;\n> +\t\t}\n> +\t}\n> +\n> +\tdpf.updateParams = false;\n> +\n> +\tuint32_t flags = RKISP1_CIF_ISP_MODULE_DPF |\n> +\t\t\t RKISP1_CIF_ISP_MODULE_DPF_STRENGTH;\n> +\tparams->module_en_update |= flags;\n> +\tparams->module_ens |= flags;\n> +\tparams->module_cfg_update |= flags;\n\nI don't think this is right. When denoising is disabled, you should\nclear RKISP1_CIF_ISP_MODULE_DPF in module_ens to disable it.\n\nThe module_cfg_update field indicates which ISP configuration parameters\nneed to be changed, so it should only be set for the very first frame. I\nthink the following should do.\n\n\tif (context.frameContext.frameCount == 0) {\n\t\tdpf_config = config_;\n\t\tdpf_strength_config = strength_config_;\n\n\t\tif (awb.enabled && lsc.enabled) {\n\t\t\tdpf_config.gain.mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS;\n\t\telse if (awb.enabled)\n\t\t\tdpf_config.gain.mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS;\n\t\telse if (lsc.enabled)\n\t\t\tdpf_config.gain.mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS;\n\t\telse\n\t\t\tdpf_config.gain.mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED;\n\n\t\tparams->module_cfg_update |= RKISP1_CIF_ISP_MODULE_DPF\n\t\t\t\t\t  |  RKISP1_CIF_ISP_MODULE_DPF_STRENGTH;\n\t}\n\n\tif (dpf.updateParams) {\n\t\tparams->module_en_update |= RKISP1_CIF_ISP_MODULE_DPF;\n\t\tif (dpf.denoise)\n\t\t\tparams->module_ens |= RKISP1_CIF_ISP_MODULE_DPF;\n\n\t\tdpf.updateParams = false;\n\t}\n\n> +}\n> +\n> +REGISTER_IPA_ALGORITHM(Dpf, \"Dpf\")\n> +\n> +} /* namespace ipa::rkisp1::algorithms */\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h\n> new file mode 100644\n> index 00000000..c8b8419a\n> --- /dev/null\n> +++ b/src/ipa/rkisp1/algorithms/dpf.h\n> @@ -0,0 +1,36 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021-2022, Ideas On Board\n> + *\n> + * dpf.h - RkISP1 De-noise Pre-Filter control\n> + */\n> +\n> +#pragma once\n> +\n> +#include <sys/types.h>\n> +\n> +#include \"algorithm.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace ipa::rkisp1::algorithms {\n> +\n> +class Dpf : public Algorithm\n> +{\n> +public:\n> +\tDpf();\n> +\t~Dpf() = default;\n> +\n> +\tint init(IPAContext &context, const YamlObject &tuningData) override;\n> +\tvoid queueRequest(IPAContext &context, const uint32_t frame,\n> +\t\t\t  const ControlList &controls) override;\n> +\tvoid prepare(IPAContext &context, rkisp1_params_cfg *params) override;\n> +\n> +private:\n> +\tbool initialized_;\n> +\tstruct rkisp1_cif_isp_dpf_config config_;\n> +\tstruct rkisp1_cif_isp_dpf_strength_config strength_config_;\n\nstrengthConfig_\n\n> +};\n> +\n> +} /* namespace ipa::rkisp1::algorithms */\n> +} /* namespace libcamera */\n> diff --git a/src/ipa/rkisp1/algorithms/meson.build b/src/ipa/rkisp1/algorithms/meson.build\n> index e48974b4..e1492dd5 100644\n> --- a/src/ipa/rkisp1/algorithms/meson.build\n> +++ b/src/ipa/rkisp1/algorithms/meson.build\n> @@ -5,6 +5,7 @@ rkisp1_ipa_algorithms = files([\n>      'awb.cpp',\n>      'blc.cpp',\n>      'cproc.cpp',\n> +    'dpf.cpp',\n>      'dpcc.cpp',\n\nYou nearly got the alphabetical order right :-)\n\n>      'filter.cpp',\n>      'gsl.cpp',\n> diff --git a/src/ipa/rkisp1/data/ov5640.yaml b/src/ipa/rkisp1/data/ov5640.yaml\n> index 93d7d1e7..69c6ad97 100644\n> --- a/src/ipa/rkisp1/data/ov5640.yaml\n> +++ b/src/ipa/rkisp1/data/ov5640.yaml\n> @@ -11,6 +11,17 @@ algorithms:\n>        Gb: 256\n>        B:  256\n>    - ColorProcessing:\n> +  - Dpf:\n> +      DomainFilter:\n> +        g: [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ]\n> +        rb: [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ]\n> +      RangeFilter:\n> +        coeff: [ 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999 ]\n> +        scale-mode: \"linear\"\n> +      FilterStrength:\n> +        r: 64\n> +        g: 64\n> +        b: 64\n\nIt won't make a difference for now, but I'd move this after LSC as the\nDPF depends on the LSC gains. Actually, I think it would make sense to\nsort the algorithms according to the hardware order, with exceptions\nwhere needed.\n\n>    - GammaSensorLinearization:\n>        x-intervals: [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ]\n>        y:\n> diff --git a/src/ipa/rkisp1/ipa_context.cpp b/src/ipa/rkisp1/ipa_context.cpp\n> index c90bf992..3b92e95e 100644\n> --- a/src/ipa/rkisp1/ipa_context.cpp\n> +++ b/src/ipa/rkisp1/ipa_context.cpp\n> @@ -165,6 +165,17 @@ namespace libcamera::ipa::rkisp1 {\n>   * \\brief Indicates if ISP parameters need to be updated\n>   */\n>  \n> +/**\n> + * \\var IPAFrameContext::dpf\n> + * \\brief Context for the De-noise Pre-Filter algorithm\n> + *\n> + * \\var IPAFrameContext::dpf.denoise\n> + * \\brief Indicates if de-noise is activated\n> + *\n> + * \\var IPAFrameContext::dpf.updateParams\n> + * \\brief Indicates if ISP parameters need to be updated\n> + */\n> +\n>  /**\n>   * \\var IPAFrameContext::filter\n>   * \\brief Context for the Filter algorithm\n> diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\n> index 0cd6aadb..3a743ac3 100644\n> --- a/src/ipa/rkisp1/ipa_context.h\n> +++ b/src/ipa/rkisp1/ipa_context.h\n> @@ -69,6 +69,11 @@ struct IPAFrameContext {\n>  \t\tbool updateParams;\n>  \t} cproc;\n>  \n> +\tstruct {\n> +\t\tbool denoise;\n> +\t\tbool updateParams;\n> +\t} dpf;\n> +\n>  \tstruct {\n>  \t\tuint8_t denoise;\n>  \t\tuint8_t sharpness;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A9F08C3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  5 Aug 2022 01:11:16 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 18F626332B;\n\tFri,  5 Aug 2022 03:11:16 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9F67961FAC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  5 Aug 2022 03:11:14 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id F14B83F1;\n\tFri,  5 Aug 2022 03:11:13 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1659661876;\n\tbh=CReujY32f4Gt5N4HaU798+Xjb0oj/Cn5cc0gAaOlg1Y=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=qBQVgFBgdl4miDtC8QwNIkbC26NMptlMmGtfciPYER3S5MjOY9PEaKux2F0Fh6pC7\n\tMkrIDnX2n1do1LMK/aJpcWpDlfbPwCehpZ0Kn1kJeKNQWOighGj2lE5VsHI22q8zST\n\tc9dU4y9F4kvYvD3rgYhUdV5/vYxEGnpNBAneEbjtCCijF3dGKF3lx/YTKxl8kmeLD8\n\tkN/rPSXXu8Z/8pKRdvkQTjocOC/4HOrH5ZnxZ/XUsELhd5irQM/W1gZr8GaNE8hFBq\n\tNJdm7uvUeVHLbPhiNjtSEV6nfvkNPXOiBqm0U9nkOPzRT9odYGGe6mNYxPBDkwVUmX\n\tXCS77ihIHJDSw==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1659661874;\n\tbh=CReujY32f4Gt5N4HaU798+Xjb0oj/Cn5cc0gAaOlg1Y=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=ps+N+PF3wxchII4MYw0rGqgnrIAyJ7PR/WSPg5PweccPTmEO7dTp/OfWyB4BtfSqp\n\tkPwPluD2FSSAmUCcfwhfb9kqyTA1jZtujzEGS5ryBBkqX3HBqBqRtluRTGwf28949y\n\tZrEhyh4rjo73+H75Z0Jwv8DFSaTABI29prWYlmMU="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"ps+N+PF3\"; dkim-atps=neutral","Date":"Fri, 5 Aug 2022 04:11:06 +0300","To":"Florian Sylvestre <fsylvestre@baylibre.com>","Message-ID":"<YuxuKqZZpKl8rZF8@pendragon.ideasonboard.com>","References":"<20220804141228.417211-1-fsylvestre@baylibre.com>\n\t<20220804141228.417211-4-fsylvestre@baylibre.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220804141228.417211-4-fsylvestre@baylibre.com>","Subject":"Re: [libcamera-devel] [PATCH 3/3] ipa: rkisp1: Add support of\n\tDe-noise Pre-Filter control","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]