mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
feat(isp): support ISP DPC, add tests and use it in multi pipeline example
This commit is contained in:
@@ -19,6 +19,9 @@ INPUT += \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_dma.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_crop.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_demosaic.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_dpc.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_dpc_dynamic.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_dpc_static.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_gamma.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_hist.h \
|
||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_lsc.h \
|
||||
|
||||
@@ -47,7 +47,7 @@ ISP Pipeline
|
||||
isp_chs [label = "Contrast &\n Hue & Saturation", width = 150, height = 70];
|
||||
isp_yuv [label = "YUV Limit\n YUB2RGB", width = 120, height = 70];
|
||||
|
||||
isp_header -> BLC -> BF -> LSC -> Demosaic -> WBG -> CCM -> Gamma -> RGB2YUV -> SHARP -> isp_chs -> isp_yuv -> CROP -> isp_tail;
|
||||
isp_header -> BLC -> DPC -> BF -> LSC -> Demosaic -> WBG -> CCM -> Gamma -> RGB2YUV -> SHARP -> isp_chs -> isp_yuv -> CROP -> isp_tail;
|
||||
|
||||
LSC -> HIST
|
||||
Demosaic -> WBG
|
||||
@@ -74,6 +74,7 @@ The ISP driver offers following services:
|
||||
- :ref:`isp-hist-statistics` - covers how to get histogram statistics one-shot or continuously.
|
||||
- :ref:`isp-bf` - covers how to enable and configure BF function.
|
||||
- :ref:`isp-blc` - covers how to enable and configure BLC function.
|
||||
- :ref:`isp-dpc` - covers how to configure static and dynamic dead pixel correction.
|
||||
- :ref:`isp-lsc` - covers how to enable and configure LSC function.
|
||||
- :ref:`isp-ccm-config` - covers how to configure the CCM.
|
||||
- :ref:`isp-demosaic` - covers how to configure the Demosaic function.
|
||||
@@ -589,6 +590,184 @@ Calling :cpp:func:`esp_isp_blc_set_correction_offset` to set the BLC correction
|
||||
ESP_ERROR_CHECK(esp_isp_blc_set_correction_offset(isp_proc, &blc_offset));
|
||||
|
||||
|
||||
.. _isp-dpc:
|
||||
|
||||
ISP DPC Controller
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Dead Pixel Correction (DPC) corrects defective pixels in RAW Bayer images before later ISP processing stages. Since adjacent Bayer pixels have different colors, DPC uses the eight same-color neighbors around the center pixel to form a 3×3 same-color neighborhood. When it detects a defective pixel, the hardware replaces the center pixel with the neighborhood median.
|
||||
|
||||
DPC supports two complementary correction modes:
|
||||
|
||||
- **Static correction** is intended for defects at fixed locations. Software uses a uniform white frame to calibrate dark pixels and a uniform black frame to calibrate bright pixels, then merges the results into a coordinate list; a previously calibrated list can also be supplied. During configuration, the driver writes the list to the hardware LUT, and the hardware replaces pixels at matching coordinates with the neighborhood median in every frame.
|
||||
- **Dynamic correction** is intended for transient defects or defects at unknown locations and does not require a coordinate list. Dynamic method 1 uses the same-color neighborhood minimum, maximum, and absolute thresholds to detect bright and dark defects. Dynamic method 2 first screens the center pixel with a neighborhood-maximum ratio range, then applies a second test using a neighborhood estimate and adaptive bright and dark factors.
|
||||
|
||||
Both modes can be enabled together. While DPC is disabled, call :cpp:func:`esp_isp_dpc_static_configure` and :cpp:func:`esp_isp_dpc_dynamic_configure` for the correction modes to use, call :cpp:func:`esp_isp_dpc_configure` to apply common DPC settings, then call :cpp:func:`esp_isp_dpc_enable`. To change the static coordinate list, disable DPC before configuring it again.
|
||||
|
||||
Static Correction and Calibration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Static correction accepts 0 to 512 :cpp:type:`esp_isp_dpc_pixel_coord_t` coordinates. Each coordinate contains ``x`` and ``y`` fields. The array must be in ascending y/x order, contain no duplicates, and all coordinates must be inside the input frame. :cpp:func:`esp_isp_dpc_static_configure` converts the coordinates to the hardware LUT format during the call, so the caller may release the coordinate array after the call returns.
|
||||
|
||||
To calibrate the coordinate list, use a uniform white frame to find dark pixels and a uniform black frame to find bright pixels. Each call to a calibration start API internally enables DPC and accepts one corresponding input frame. Reading the result disables DPC again, which allows the next calibration pass or the final static configuration to start.
|
||||
|
||||
The following sequence calibrates and enables static correction. ``white_frame`` and ``black_frame`` must be uniform RAW input frames. Acquire them as follows:
|
||||
|
||||
- **White frame**: Fill the sensor field of view with a uniform, texture-free bright target, such as an integrating-sphere source or a defocused matte white reflector. Avoid shadows, vignetting, reflections, and saturated areas.
|
||||
- **Black frame**: Block all light, for example with a lens cap or a dark enclosure. Prevent light leaks, status LEDs, and other stray light from reaching the sensor.
|
||||
|
||||
The way to feed each frame to the ISP and wait for it to complete depends on the input source. The following uses DMA input as an example; ``output_frame`` is the DMA output buffer.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_dpc_calibration_config_t white_calibration_config = {
|
||||
.threshold = 0xf0,
|
||||
.enable_output = true,
|
||||
};
|
||||
esp_isp_dpc_calibration_config_t black_calibration_config = {
|
||||
.threshold = 0x0a,
|
||||
.enable_output = true,
|
||||
};
|
||||
static esp_isp_dpc_calibration_ref_t white_ref;
|
||||
static esp_isp_dpc_calibration_ref_t black_ref;
|
||||
static esp_isp_dpc_calibration_ref_t merged_ref;
|
||||
|
||||
// Find dark defective pixels from a white frame.
|
||||
esp_isp_dpc_static_calibration_start_once(isp_proc, ESP_ISP_DPC_CALIBRATION_IMAGE_WHITE, &white_calibration_config);
|
||||
// Feed white_frame to the ISP and wait until processing completes.
|
||||
// For example, with DMA input:
|
||||
esp_isp_dma_process_frame(isp_proc, output_frame, white_frame, 1000);
|
||||
esp_isp_dpc_calibration_read_result(isp_proc, 1000, &white_ref);
|
||||
|
||||
// Find bright defective pixels from a black frame.
|
||||
esp_isp_dpc_static_calibration_start_once(isp_proc, ESP_ISP_DPC_CALIBRATION_IMAGE_BLACK, &black_calibration_config);
|
||||
// Feed black_frame to the ISP and wait until processing completes.
|
||||
// For example, with DMA input:
|
||||
esp_isp_dma_process_frame(isp_proc, output_frame, black_frame, 1000);
|
||||
esp_isp_dpc_calibration_read_result(isp_proc, 1000, &black_ref);
|
||||
|
||||
// Merge, sort, and remove duplicate coordinates before writing the static LUT.
|
||||
const esp_isp_dpc_calibration_ref_t *calibration_refs[] = {
|
||||
&white_ref,
|
||||
&black_ref,
|
||||
};
|
||||
esp_isp_dpc_calibration_merge_result(calibration_refs, 2, &merged_ref);
|
||||
esp_isp_dpc_static_config_t static_dpc_config = {
|
||||
.dead_pixel_coords = merged_ref.dead_pixel_coords,
|
||||
.dead_pixel_count = merged_ref.dead_pixel_count,
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_static_configure(isp_proc, &static_dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
:cpp:func:`esp_isp_dpc_calibration_merge_result` is a software-only utility that accepts any positive number of references. It does not access an ISP processor or hardware. It sorts all coordinates by y/x, removes duplicates, and keeps at most :c:macro:`ESP_ISP_DPC_MAX_DEAD_PIXELS` coordinates.
|
||||
|
||||
To merge N references, pass an array of their addresses and the number of elements to :cpp:func:`esp_isp_dpc_calibration_merge_result`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const esp_isp_dpc_calibration_ref_t *refs[] = {
|
||||
&ref_0,
|
||||
&ref_1,
|
||||
&ref_2,
|
||||
};
|
||||
const size_t ref_count = sizeof(refs) / sizeof(refs[0]);
|
||||
static esp_isp_dpc_calibration_ref_t merged_ref;
|
||||
|
||||
ESP_ERROR_CHECK(esp_isp_dpc_calibration_merge_result(refs, ref_count, &merged_ref));
|
||||
|
||||
If a factory calibration or another source already provides a defective-pixel coordinate list, the white- and black-frame calibration flow above can be skipped. Pass the coordinate array directly to :cpp:func:`esp_isp_dpc_static_configure`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const esp_isp_dpc_pixel_coord_t factory_bad_pixels[] = {
|
||||
{.x = 24, .y = 24},
|
||||
{.x = 56, .y = 24},
|
||||
{.x = 25, .y = 72},
|
||||
};
|
||||
esp_isp_dpc_static_config_t static_dpc_config = {
|
||||
.dead_pixel_coords = factory_bad_pixels,
|
||||
.dead_pixel_count = sizeof(factory_bad_pixels) / sizeof(factory_bad_pixels[0]),
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_static_configure(isp_proc, &static_dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
Dynamic Correction
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Dynamic Method 1
|
||||
++++++++++++++++
|
||||
|
||||
Dynamic method 1 uses absolute thresholds. A pixel is a bright candidate when it is greater than ``max8 + high_threshold`` and a dark candidate when it is less than ``min8 - low_threshold``, where ``min8`` and ``max8`` are calculated from the eight same-color neighbors.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_dpc_dynamic_config_t dpc_config = {
|
||||
.method = ESP_ISP_DPC_DYNAMIC_METHOD_1,
|
||||
.method_1 = {
|
||||
.high_threshold = 48,
|
||||
.low_threshold = 48,
|
||||
},
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_dynamic_configure(isp_proc, &dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
Dynamic Method 2
|
||||
++++++++++++++++
|
||||
|
||||
Dynamic method 2 detects defective pixels in two stages.
|
||||
|
||||
The first stage uses the maximum value ``max8`` of the eight same-color neighbors to screen the center pixel ``pixel_center``. The normal range is ``max8 * first_stage_lower_ratio < pixel_center < max8 * first_stage_upper_ratio``: pixels within this range pass the first stage, while pixels equal to a boundary or outside the range receive a second test. The first-stage ratios use fixed-point values: ``value = integer + decimal / ISP_DPC_RATIO_MAX``. Valid values are 0.0 to 1.0. For fractional values, set ``integer`` to 0 and ``decimal`` to 0 ... ``ISP_DPC_RATIO_MAX - 1``; for example, 0.5 is ``integer = 0`` and ``decimal = 8``. For 1.0, set ``integer`` to 1 and ``decimal`` to 0.
|
||||
|
||||
- ``first_stage_lower_ratio`` (range ``0.0`` to ``1.0``): Lower bound of the first-stage normal range. Raising it sends more dark pixels to the second-stage test; lowering it lets more dark pixels pass the first stage.
|
||||
- ``first_stage_upper_ratio`` (range ``0.0`` to ``1.0``): Upper bound of the first-stage normal range. Raising it lets more bright pixels pass the first stage; lowering it sends more bright pixels to the second-stage test. It must be greater than ``first_stage_lower_ratio``, otherwise the configuration function returns ``ESP_ERR_INVALID_ARG``.
|
||||
|
||||
The second stage calculates the mean ``est`` of the eight neighbors, the absolute difference ``dif = abs(est - pixel_center)`` between ``est`` and the center pixel, and their mean ``avg``. A dark-pixel candidate is detected when ``est >= pixel_center`` and ``dif > avg * dark_deviation_factor``; a bright-pixel candidate is detected when ``est < pixel_center`` and ``dif > (255 - avg) * bright_deviation_factor``. The deviation factors use fixed-point values: ``value = integer + decimal / ISP_DPC_DEVIATION_FACTOR_MAX``. Valid values are 0.0 to 1.0. For fractional values, set ``integer`` to 0 and ``decimal`` to 0 ... ``ISP_DPC_DEVIATION_FACTOR_MAX - 1``; for example, 0.5 is ``integer = 0`` and ``decimal = 16``. For 1.0, set ``integer`` to 1 and ``decimal`` to 0.
|
||||
|
||||
- ``dark_deviation_factor`` (range ``0.0`` to ``1.0``): Second-stage dark-pixel sensitivity. Lowering it reduces the required dark-pixel deviation and corrects dark pixels more aggressively; raising it is more conservative.
|
||||
- ``bright_deviation_factor`` (range ``0.0`` to ``1.0``): Second-stage bright-pixel sensitivity. Lowering it reduces the required bright-pixel deviation and corrects bright pixels more aggressively; raising it is more conservative.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_dpc_dynamic_config_t dpc_config = {
|
||||
.method = ESP_ISP_DPC_DYNAMIC_METHOD_2,
|
||||
.method_2 = {
|
||||
.first_stage_lower_ratio = {
|
||||
.integer = 0,
|
||||
.decimal = 8,
|
||||
},
|
||||
.first_stage_upper_ratio = {
|
||||
.integer = 1,
|
||||
.decimal = 0,
|
||||
},
|
||||
.bright_deviation_factor = {
|
||||
.integer = 0,
|
||||
.decimal = 16,
|
||||
},
|
||||
.dark_deviation_factor = {
|
||||
.integer = 0,
|
||||
.decimal = 16,
|
||||
},
|
||||
},
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_dynamic_configure(isp_proc, &dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
.. _isp-lsc:
|
||||
|
||||
ISP LSC Controller
|
||||
@@ -983,6 +1162,9 @@ API Reference
|
||||
.. include-build-file:: inc/isp_lsc.inc
|
||||
.. include-build-file:: inc/isp_ccm.inc
|
||||
.. include-build-file:: inc/isp_demosaic.inc
|
||||
.. include-build-file:: inc/isp_dpc.inc
|
||||
.. include-build-file:: inc/isp_dpc_dynamic.inc
|
||||
.. include-build-file:: inc/isp_dpc_static.inc
|
||||
.. include-build-file:: inc/isp_sharpen.inc
|
||||
.. include-build-file:: inc/isp_gamma.inc
|
||||
.. include-build-file:: inc/isp_hist.inc
|
||||
|
||||
@@ -256,6 +256,26 @@ If declarator-id:
|
||||
struct isp_color_saturation_t
|
||||
-----------------------------^
|
||||
|
||||
isp_types.inc:line: WARNING: Error in declarator or parameters-and-qualifiers
|
||||
If pointer to member declarator:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 22]
|
||||
struct isp_dpc_ratio_t
|
||||
----------------------^
|
||||
If declarator-id:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 22]
|
||||
struct isp_dpc_ratio_t
|
||||
----------------------^
|
||||
|
||||
isp_types.inc:line: WARNING: Error in declarator or parameters-and-qualifiers
|
||||
If pointer to member declarator:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 33]
|
||||
struct isp_dpc_deviation_factor_t
|
||||
---------------------------------^
|
||||
If declarator-id:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 33]
|
||||
struct isp_dpc_deviation_factor_t
|
||||
---------------------------------^
|
||||
|
||||
isp_types.inc:line: WARNING: Error in declarator or parameters-and-qualifiers
|
||||
If pointer to member declarator:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 21]
|
||||
|
||||
@@ -47,7 +47,7 @@ ISP 流水线
|
||||
isp_chs [label = "对比度 &\n 色调 & 饱和度", width = 150, height = 70];
|
||||
isp_yuv [label = "YUV 限制\n YUB2RGB", width = 120, height = 70];
|
||||
|
||||
isp_header -> BLC -> BF -> LSC -> 去马赛克 -> WBG -> CCM -> gamma 校正 -> RGB 转 YUV -> 锐化 -> isp_chs -> isp_yuv -> 裁剪 -> isp_tail;
|
||||
isp_header -> BLC -> DPC -> BF -> LSC -> 去马赛克 -> WBG -> CCM -> gamma 校正 -> RGB 转 YUV -> 锐化 -> isp_chs -> isp_yuv -> 裁剪 -> isp_tail;
|
||||
|
||||
LSC -> HIST
|
||||
去马赛克 -> WBG
|
||||
@@ -74,6 +74,7 @@ ISP 驱动程序提供以下服务:
|
||||
- :ref:`isp-hist-statistics` - 涵盖如何单次或连续获取直方图统计信息。
|
||||
- :ref:`isp-bf` - 涵盖如何启用和配置 BF 功能。
|
||||
- :ref:`isp-blc` - 涵盖如何启用和配置 BLC 功能。
|
||||
- :ref:`isp-dpc` - 涵盖如何配置静态和动态坏点校正。
|
||||
- :ref:`isp-lsc` - 涵盖如何启用和配置 LSC 功能。
|
||||
- :ref:`isp-ccm-config` - 涵盖如何配置 CCM。
|
||||
- :ref:`isp-demosaic` - 涵盖如何配置去马赛克功能。
|
||||
@@ -589,6 +590,184 @@ ISP BLC 控制器
|
||||
ESP_ERROR_CHECK(esp_isp_blc_set_correction_offset(isp_proc, &blc_offset));
|
||||
|
||||
|
||||
.. _isp-dpc:
|
||||
|
||||
ISP DPC 控制器
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
坏点校正 (DPC) 在后续 ISP 处理阶段之前校正 RAW Bayer 图像中的坏点。由于 Bayer 图像中相邻像素的颜色不同,DPC 以当前像素为中心,从同色的 8 个邻域像素构成 3×3 同色邻域。检测到坏点后,硬件使用该邻域的中值替换中心像素。
|
||||
|
||||
DPC 支持两种可组合的校正方式:
|
||||
|
||||
- **静态校正**:适用于位置固定的坏点。软件通过均匀白场标定暗坏点、通过均匀黑场标定亮坏点,合并标定结果后得到坐标表;也可以直接使用预先标定的坐标表。配置时,驱动将坐标表写入硬件 LUT,硬件在每帧中对命中坐标的像素进行中值替换。
|
||||
- **动态校正**:适用于瞬时或未知位置的坏点,无需预先提供坐标表。动态方法 1 使用同色邻域的最小值、最大值及绝对阈值检测亮、暗坏点。动态方法 2 先按邻域最大值的比例范围筛选中心像素,再用邻域估计值和自适应亮、暗因子进行二次检测。
|
||||
|
||||
两种方式可以同时启用。请在 DPC 禁用时分别调用 :cpp:func:`esp_isp_dpc_static_configure` 和 :cpp:func:`esp_isp_dpc_dynamic_configure` 配置需要的校正方式,再调用 :cpp:func:`esp_isp_dpc_configure` 配置通用 DPC 设置,最后调用 :cpp:func:`esp_isp_dpc_enable` 启用。若要修改静态坏点坐标表,须先禁用 DPC,再重新配置。
|
||||
|
||||
静态校正和标定
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
静态校正接受 0 到 512 个 :cpp:type:`esp_isp_dpc_pixel_coord_t` 坐标。每个坐标包含 ``x`` 和 ``y`` 字段。坐标数组必须按 y/x 严格升序、无重复,且所有坐标必须位于输入图像范围内。:cpp:func:`esp_isp_dpc_static_configure` 在调用期间将坐标转换为硬件 LUT 格式,因此该调用返回后,调用方可释放坐标数组。
|
||||
|
||||
使用均匀白场帧检测暗坏点,使用均匀黑场帧检测亮坏点。每次调用标定启动 API 都会在内部启用 DPC,并接收一帧对应的输入图像。读取结果会再次禁用 DPC,因此可继续下一次标定,或开始最终的静态校正配置。
|
||||
|
||||
以下流程完成标定并启用静态校正。``white_frame`` 和 ``black_frame`` 必须分别为均匀的 RAW 白场和黑场输入帧。建议按以下方式获取:
|
||||
|
||||
- **白场帧**:使传感器视场完全覆盖均匀、无纹理的明亮目标,例如均匀积分球光源或离焦的纯白漫反射板。避免阴影、渐晕、反光和饱和区域。
|
||||
- **黑场帧**:完全遮光,例如盖上镜头盖或在暗箱中采集。避免漏光、状态指示灯和其他杂散光进入传感器。
|
||||
|
||||
将每帧送入 ISP 并等待处理完成的具体方式取决于所使用的输入源。以下以 DMA 输入为例,``output_frame`` 为 DMA 输出缓冲区。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_dpc_calibration_config_t white_calibration_config = {
|
||||
.threshold = 0xf0,
|
||||
.enable_output = true,
|
||||
};
|
||||
esp_isp_dpc_calibration_config_t black_calibration_config = {
|
||||
.threshold = 0x0a,
|
||||
.enable_output = true,
|
||||
};
|
||||
static esp_isp_dpc_calibration_ref_t white_ref;
|
||||
static esp_isp_dpc_calibration_ref_t black_ref;
|
||||
static esp_isp_dpc_calibration_ref_t merged_ref;
|
||||
|
||||
// 使用白场检测暗坏点。
|
||||
esp_isp_dpc_static_calibration_start_once(isp_proc, ESP_ISP_DPC_CALIBRATION_IMAGE_WHITE, &white_calibration_config);
|
||||
// 将 white_frame 输入 ISP,并等待该帧处理完成。
|
||||
// 例如,使用 DMA 输入:
|
||||
esp_isp_dma_process_frame(isp_proc, output_frame, white_frame, 1000);
|
||||
esp_isp_dpc_calibration_read_result(isp_proc, 1000, &white_ref);
|
||||
|
||||
// 使用黑场检测亮坏点。
|
||||
esp_isp_dpc_static_calibration_start_once(isp_proc, ESP_ISP_DPC_CALIBRATION_IMAGE_BLACK, &black_calibration_config);
|
||||
// 将 black_frame 输入 ISP,并等待该帧处理完成。
|
||||
// 例如,使用 DMA 输入:
|
||||
esp_isp_dma_process_frame(isp_proc, output_frame, black_frame, 1000);
|
||||
esp_isp_dpc_calibration_read_result(isp_proc, 1000, &black_ref);
|
||||
|
||||
// 合并、排序和去重后,再写入静态 LUT。
|
||||
const esp_isp_dpc_calibration_ref_t *calibration_refs[] = {
|
||||
&white_ref,
|
||||
&black_ref,
|
||||
};
|
||||
esp_isp_dpc_calibration_merge_result(calibration_refs, 2, &merged_ref);
|
||||
esp_isp_dpc_static_config_t static_dpc_config = {
|
||||
.dead_pixel_coords = merged_ref.dead_pixel_coords,
|
||||
.dead_pixel_count = merged_ref.dead_pixel_count,
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_static_configure(isp_proc, &static_dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
:cpp:func:`esp_isp_dpc_calibration_merge_result` 是一个纯软件工具 API,可传入任意正数个引用,且不访问 ISP 处理器或硬件。函数会合并所有坐标、按 y/x 排序并去重。合并后的坐标表最多包含 :c:macro:`ESP_ISP_DPC_MAX_DEAD_PIXELS` 个唯一坐标。
|
||||
|
||||
如需合并 N 个引用,将其地址组成数组,并将数组及元素数量传入 :cpp:func:`esp_isp_dpc_calibration_merge_result`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
const esp_isp_dpc_calibration_ref_t *refs[] = {
|
||||
&ref_0,
|
||||
&ref_1,
|
||||
&ref_2,
|
||||
};
|
||||
const size_t ref_count = sizeof(refs) / sizeof(refs[0]);
|
||||
static esp_isp_dpc_calibration_ref_t merged_ref;
|
||||
|
||||
ESP_ERROR_CHECK(esp_isp_dpc_calibration_merge_result(refs, ref_count, &merged_ref));
|
||||
|
||||
如果已有传感器出厂标定或其他方式得到的坏点坐标表,则可跳过上述白场/黑场标定流程,直接将坐标数组传给 :cpp:func:`esp_isp_dpc_static_configure`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static const esp_isp_dpc_pixel_coord_t factory_bad_pixels[] = {
|
||||
{.x = 24, .y = 24},
|
||||
{.x = 56, .y = 24},
|
||||
{.x = 25, .y = 72},
|
||||
};
|
||||
esp_isp_dpc_static_config_t static_dpc_config = {
|
||||
.dead_pixel_coords = factory_bad_pixels,
|
||||
.dead_pixel_count = sizeof(factory_bad_pixels) / sizeof(factory_bad_pixels[0]),
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_static_configure(isp_proc, &static_dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
动态校正
|
||||
~~~~~~~~
|
||||
|
||||
动态方法 1
|
||||
++++++++++
|
||||
|
||||
动态方法 1 使用绝对阈值。设 ``min8`` 和 ``max8`` 分别为 8 个同色邻域像素的最小值和最大值:像素值大于 ``max8 + high_threshold`` 时为亮坏点候选;小于 ``min8 - low_threshold`` 时为暗坏点候选。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_dpc_dynamic_config_t dpc_config = {
|
||||
.method = ESP_ISP_DPC_DYNAMIC_METHOD_1,
|
||||
.method_1 = {
|
||||
.high_threshold = 48,
|
||||
.low_threshold = 48,
|
||||
},
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_dynamic_configure(isp_proc, &dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
动态方法 2
|
||||
++++++++++
|
||||
|
||||
动态方法 2 分两层检测坏点。
|
||||
|
||||
第一层使用 8 个同色邻域像素的最大值 ``max8`` 筛选中心像素 ``pixel_center``。正常范围为 ``max8 * first_stage_lower_ratio < pixel_center < max8 * first_stage_upper_ratio``:落在该范围内的像素通过第一层;等于边界或不在该范围内的像素进入第二层。第一层比例使用定点数表示:``value = integer + decimal / ISP_DPC_RATIO_MAX``。有效取值范围为 0.0 到 1.0。表示小数时,``integer`` 设为 0,``decimal`` 取值为 0 ... ``ISP_DPC_RATIO_MAX - 1``;例如 0.5 配置为 ``integer = 0``、``decimal = 8``。表示 1.0 时,``integer`` 设为 1,``decimal`` 设为 0。
|
||||
|
||||
- ``first_stage_lower_ratio``\ (取值范围 ``0.0`` 到 ``1.0``):第一层正常范围的下界。增大该值会使更多偏暗像素进入第二层检测;减小该值会让更多偏暗像素直接通过第一层。
|
||||
- ``first_stage_upper_ratio``\ (取值范围 ``0.0`` 到 ``1.0``):第一层正常范围的上界。增大该值会让更多偏亮像素直接通过第一层;减小该值会使更多偏亮像素进入第二层检测。该值必须大于 ``first_stage_lower_ratio``,否则配置函数返回 ``ESP_ERR_INVALID_ARG``。
|
||||
|
||||
第二层计算 8 个邻域像素的均值 ``est``、中心像素与 ``est`` 的绝对差 ``dif = abs(est - pixel_center)``,以及两者的均值 ``avg``。当 ``est >= pixel_center`` 且 ``dif > avg * dark_deviation_factor`` 时,检测为暗坏点候选;当 ``est < pixel_center`` 且 ``dif > (255 - avg) * bright_deviation_factor`` 时,检测为亮坏点候选。偏差因子使用定点数表示:``value = integer + decimal / ISP_DPC_DEVIATION_FACTOR_MAX``。有效取值范围为 0.0 到 1.0。表示小数时,``integer`` 设为 0,``decimal`` 取值为 0 ... ``ISP_DPC_DEVIATION_FACTOR_MAX - 1``;例如 0.5 配置为 ``integer = 0``、``decimal = 16``。表示 1.0 时,``integer`` 设为 1,``decimal`` 设为 0。
|
||||
|
||||
- ``dark_deviation_factor``\ (取值范围 ``0.0`` 到 ``1.0``):第二层暗坏点判定的灵敏度。减小该值会降低暗坏点所需的偏差,更容易校正偏暗像素;增大该值则更保守。
|
||||
- ``bright_deviation_factor``\ (取值范围 ``0.0`` 到 ``1.0``):第二层亮坏点判定的灵敏度。减小该值会降低亮坏点所需的偏差,更容易校正偏亮像素;增大该值则更保守。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
esp_isp_dpc_dynamic_config_t dpc_config = {
|
||||
.method = ESP_ISP_DPC_DYNAMIC_METHOD_2,
|
||||
.method_2 = {
|
||||
.first_stage_lower_ratio = {
|
||||
.integer = 0,
|
||||
.decimal = 8,
|
||||
},
|
||||
.first_stage_upper_ratio = {
|
||||
.integer = 1,
|
||||
.decimal = 0,
|
||||
},
|
||||
.bright_deviation_factor = {
|
||||
.integer = 0,
|
||||
.decimal = 16,
|
||||
},
|
||||
.dark_deviation_factor = {
|
||||
.integer = 0,
|
||||
.decimal = 16,
|
||||
},
|
||||
},
|
||||
};
|
||||
esp_isp_dpc_config_t common_dpc_config = {
|
||||
.flags.update_once_configured = true,
|
||||
};
|
||||
esp_isp_dpc_dynamic_configure(isp_proc, &dpc_config);
|
||||
esp_isp_dpc_configure(isp_proc, &common_dpc_config);
|
||||
esp_isp_dpc_enable(isp_proc);
|
||||
|
||||
.. _isp-lsc:
|
||||
|
||||
ISP LSC 控制器
|
||||
@@ -983,6 +1162,9 @@ API 参考
|
||||
.. include-build-file:: inc/isp_lsc.inc
|
||||
.. include-build-file:: inc/isp_ccm.inc
|
||||
.. include-build-file:: inc/isp_demosaic.inc
|
||||
.. include-build-file:: inc/isp_dpc.inc
|
||||
.. include-build-file:: inc/isp_dpc_dynamic.inc
|
||||
.. include-build-file:: inc/isp_dpc_static.inc
|
||||
.. include-build-file:: inc/isp_sharpen.inc
|
||||
.. include-build-file:: inc/isp_gamma.inc
|
||||
.. include-build-file:: inc/isp_hist.inc
|
||||
|
||||
Reference in New Issue
Block a user