PotatoPie 4.0 实验教程(25) —— FPGA实现摄像头图像直方图均衡变换

ops/2024/10/18 12:24:25/

图像的直方图均衡是什么?

图像的直方图均衡是一种用于增强图像对比度的图像处理技术。在直方图均衡中,图像的像素值被重新分配,以使得图像的直方图变得更均匀,即各个像素值的分布更加平衡。这意味着直方图中每个像素值的频率大致相同,从而使得图像的对比度增强。

直方图均衡可以应用于灰度图像和彩色图像,并且通常用于图像增强、图像预处理以及计算机视觉应用中。它有以下几个主要作用和优势:

  1. 增强对比度:直方图均衡可以增强图像的对比度,使得图像中的细节更加清晰、突出。通过重新分配像素值,可以拉伸直方图,使得图像中的像素值范围更广,从而增加了图像的动态范围。

  2. 消除背景噪声:直方图均衡可以帮助消除图像中的背景噪声,提高图像的质量。通过增强图像的对比度,可以更好地区分目标与背景,减少背景噪声的影响。

  3. 提高图像质量:直方图均衡可以改善图像的视觉质量,使图像更加清晰、生动,提高了图像的观赏性和识别性。

  4. 改善图像分割和特征提取:直方图均衡可以使得图像中不同目标的灰度级别更加明显,有利于图像分割和特征提取。这对于后续的图像分析、目标检测和识别等任务非常重要。

  5. 预处理步骤:直方图均衡通常作为图像预处理的一部分,用于提高后续图像处理算法的性能和准确性。例如,在图像识别、目标跟踪和计算机视觉任务中,对图像进行直方图均衡可以改善算法的鲁棒性和准确率。

总的来说,直方图均衡是一种简单而有效的图像增强技术,可以提高图像的质量和可用性,使得图像在各种应用领域中都能取得更好的效果。

直方图均衡算法的步骤

直方图均衡的步骤通常包括以下几个阶段:

  1. 计算图像的灰度直方图:统计图像中每个灰度级别的像素数量。
  2. 计算累积分布函数(CDF):对灰度直方图进行归一化处理,得到像素值的累积分布函数,该函数描述了每个灰度级别在图像中出现的累积概率。
  3. 根据CDF进行像素值映射:使用累积分布函数对图像的像素值进行重新映射,以使得图像的直方图更加均匀。通常情况下,这涉及到将原始像素值映射到新的像素值,以便在直方图中实现更均匀的分布。
  4. 应用像素值映射:根据映射关系,将图像中的每个像素值替换为对应的新值,从而完成直方图均衡化。

python实现图像的直方图均衡变换源码

PotatoPie 4.0 实验教程(25) —— FPGA实现摄像头图像直方图均衡变换-Anlogic-安路论坛-FPGA CPLD-ChipDebug

这段代码实现了图像的直方图均衡化,并使用 Matplotlib 库在 Python 中进行可视化展示。以下是对代码功能的详细说明:

  1. 导入必要的库

    • os:用于处理文件路径。
    • numpy:用于数组操作和数学计算。
    • cv2:OpenCV 库,用于图像处理
    • matplotlib.pyplot:用于绘制图像和直方图。
  2. 获取图像路径

    • 使用 os.path.dirname 和 os.path.abspath 函数获取当前 Python 脚本所在目录的路径。
    • 使用 os.path.join 函数构造图像文件的完整路径。
  3. 读取图像

    • 使用 OpenCV 的 cv2.imread 函数读取图像。
  4. 将图像转换为灰度图像

    • 使用 OpenCV 的 cv2.cvtColor 函数将彩色图像转换为灰度图像。
  5. 计算直方图

    • 创建一个长度为 256 的数组 histogram,用于存储灰度级别的像素数量。
    • 使用双重循环遍历图像的每个像素,并在 histogram 中累计每个灰度级别的像素数量。
  6. 计算累积分布函数

    • 创建一个长度为 256 的数组 cumulative_distribution,用于存储每个灰度级别的累积分布函数值。
    • 使用双重循环遍历直方图,计算每个灰度级别的累积像素数量,并将其除以总像素数得到累积分布函数值。
  7. 计算直方图均衡化的灰度值映射表

    • 创建一个长度为 256 的数组 LUT,用于存储直方图均衡化后的灰度值映射表。
    • 将累积分布函数值乘以 255 并四舍五入,得到灰度值映射表。
  8. 直方图均衡化

    • 创建一个与原始图像相同大小的数组 image_equal,用于存储直方图均衡化后的图像。
    • 使用双重循环遍历原始图像的每个像素,根据灰度值映射表将每个像素的灰度值替换为均衡化后的灰度值。
  9. 可视化

    • 使用 Matplotlib 的 plt.imshow 和 plt.bar 函数分别显示原始图像和其直方图。
    • 使用 Matplotlib 的 plt.plot 函数绘制累积分布函数曲线。
    • 使用 Matplotlib 的 plt.show 函数显示图像及其直方图的子图布局。

通过以上步骤,代码实现了直方图均衡化并可视化显示了原始图像、均衡化后的图像、直方图以及累积分布函数。

MATLAB实现图像的直方图均衡变换源码

上面的代码实现了图像的直方图均衡化,具体步骤如下:

  1. 读取图像并转换为灰度图像: 使用imread函数读取名为’dog.png’的图像,并使用rgb2gray函数将彩色图像转换为灰度图像。

  2. 计算直方图: 首先创建一个256×1的零矩阵histogram,用于存储灰度级别的直方图。然后使用嵌套的循环遍历图像的每个像素点,将每个灰度级别出现的频数累加到相应的直方图位置上。

  3. 计算累积分布函数: 创建一个256×1的零矩阵cumulative_distribution,用于存储累积分布函数的值。然后通过循环计算累积分布函数的值,其中使用变量sum累积直方图的频数,并将其除以图像的总像素数(行数乘以列数)得到归一化后的累积分布函数。

  4. 计算灰度值映射表: 创建一个256×1的零矩阵LUT,用于存储直方图均衡化后的灰度值映射表。然后通过循环遍历累积分布函数,对每个灰度级别的累积分布函数值乘以255并四舍五入,得到灰度值映射表。

  5. 直方图均衡化: 创建一个与原始图像大小相同的零矩阵image_equal,用于存储直方图均衡化后的图像。然后通过嵌套的循环遍历原始图像的每个像素点,根据灰度值映射表将每个像素点的灰度值替换为对应的直方图均衡化后的灰度值。

  6. 显示结果: 使用subplot函数将原始图像、直方图、直方图均衡化后的图像以及其直方图和累积分布图显示在一个图像窗口中。标题使用中文显示,并指定使用微软雅黑字体。

工程分析

链接直达

https://item.taobao.com/item.htm?ft=t&id=776516984361

工程层次图

demo18相比,只是多了一个img_histogram的模块,也就是下面这一段代码,在从SDRAM读出来之后,经它处理后再输出hdmi_tx模块。

img_histogram u_img_histogram
(.i_clk          (clk_pixel                ),.i_rst_n        (sys_rst_n                ),.i_hs           (VGA_HS                   ),.i_vs           (VGA_VS                   ),.i_de           (VGA_DE                   ),.i_x_pos        (lcd_xpos                 ),.i_y_pos        (lcd_ypos                 ),.o_hs           (histogram_hs             ),.o_vs           (histogram_vs             ),.o_de           (histogram_de             ),.o_r            (histogram_r              ),.o_g            (histogram_g              ),.o_b            (histogram_b              ) 
);

img_histogram直方图均衡模块源代码分析

从层次图可到这个模块包含两个子ROM模块, 上面这个img_histogram ROM是我们要做直方图均衡的图像数据,dog.png就存在这里,为什么这个实验没有直接对摄像头进行处理,因为直方图需要大量的RAM,而EG4的RAM没有这么大,所以我们用ROM存一个小图来验证这个算法

下面那个u_img_equal_ram_dp 是用来存储直方图映射表。

接下来我们讲述直方图均衡化的FPGA算法关键点:

1. 从ROM读取dog.png的图像数据

由于我们需要在指定位置处理像,而我们显示屏大于图像的尺寸,因此需要行场计数到达指定位置时才从ROM读取图像数据。

我们用这几个参数定义显示处理图像的位置

parameter H_ACTIVE = 160; //显示区域宽度
parameter V_ACTIVE = 120; //显示区域高度
parameter BEGIN_X = 640; //显示起始坐标
parameter BEGIN_Y = 360; //显示起始坐标

然后分别进行/显示区域行计数和列计数,

if(h_cnt == H_ACTIVE - 1'b1)h_cnt <= 11'd0;else h_cnt <= h_cnt + 11'd1;..... 省略if(v_cnt == V_ACTIVE - 1'b1)v_cnt <= 11'd0;else v_cnt <= v_cnt + 11'd1;

往下看就看到代码定义ROM的地方了

 

//存储dog.png图片数据的ROM

dog_160x120 u_image_buffer(

.doa ({r_d0,g_d0,b_d0}),

.addra (rd_addr ),

.clka (i_clk )

);

接下来的这行代码处理了图像数据ROM的地址计数。

rd_addr <= v_cnt * H_ACTIVE + h_cnt;

2.图像的灰度化

PotatoPie 4.0 实验教程(25) —— FPGA实现摄像头图像直方图均衡变换-Anlogic-安路论坛-FPGA CPLD-ChipDebug

3.计算直方图

跟matlab和python代码一样,统计一帧图像数据中每个灰度出现的次数

hist_ram[gray_d0[15:8]]<=hist_ram[gray_d0[15:8]]+1'b1;

4.计算累积分布函数建立映射表

PotatoPie 4.0 实验教程(25) —— FPGA实现摄像头图像直方图均衡变换-Anlogic-安路论坛-FPGA CPLD-ChipDebug

5. 将计算结果写映射表的ROM

例化双端RAM用于存储映射表

// 存储直方图均衡化后的灰度值映射表,输出时直接用灰度值作为地址进行查表
ram_dp#(.DATA_WIDTH   (8          ),.ADDRESS_WIDTH  (8             )
) u_img_equal_ram_dp(.i_clk      (i_clk        ),.i_data_a    (image_equal    ),.i_addr_a    (wr_addr_cnt    ),.i_wea      (sum_hist_flag_d3  ),.o_qout_a    (          ),.i_data_b    (          ),.i_addr_b    (gray_d0[15:8]    ),.i_web      (          ),.o_qout_b    (hist_out      )
);

显示的时候,直接用灰度值作为地址进行查表读出值即可。

管脚约束

与PotatoPie 4.0 实验教程(18) —— FPGA实现OV5640摄像头采集以SDRAM作为显存进行HDMI输出显示相同,不作赘述。

时序约束

与PotatoPie 4.0 实验教程(18) —— FPGA实现OV5640摄像头采集以SDRAM作为显存进行HDMI输出显示相同,不作赘述。

实验结果


http://www.ppmy.cn/ops/20810.html

相关文章

分类算法——模型评估(八)

1混淆矩阵 在分类任务下&#xff0c;预测结果与正确标记之间存在四种不同的组合&#xff0c;构成混淆矩阵&#xff08;适用于多分类&#xff09; TP True Possitive FN False Negative 2精确率&#xff08;Precision&#xff09;与召回率&#xff08;Recall&#xff09; 精…

从Kafka的可靠性设计体验软件设计之美

目录 1. Kafka可靠性概述 2. 副本剖析 2.1 什么是副本 2.2 副本失效场景 2.3 数据丢失场景 2.4 解决数据丢失方案 3. 日志同步机制 4. 可靠性分析 1. Kafka可靠性概述 Kafka 中采用了多副本的机制&#xff0c;这是大多数分布式系统中惯用的手法&#xff0c;以此来实现水平扩…

【CSS】深入理解:BFC究竟是什么?

深入理解&#xff1a;BFC究竟是什么&#xff1f; 在我们了解BFC之前&#xff0c;我们先来看看什么是FC 1. FC的概念 FC全称 Formatting Context ,元素在标准流里面都属于一个FC 块级元素的布局都属于Block Formatting Context,也就是BFC block level box都是在BFC中布局的 …

NXP恩智浦 S32G电源管理芯片 VR5510 安全概念 Safety Concept (万字长文详解,配21张彩图)

NXP恩智浦 S32G电源管理芯片 VR5510 安全概念 Safety Concept (万字长文详解&#xff0c;配21张彩图) 1. 简介 本应用笔记描述了与S32G处理器和VR5510 PMIC相关的安全概念。该文档涵盖了S32G和VR5510的安全功能以及它们如何相互作用&#xff0c;以确保对ASIL D安全完整性级别…

学习 Rust 的第十天:枚举和模式匹配

大家好&#xff0c; 今天是学习 Rust 的第十天。昨天我们讨论了如何使用 structs 将相关数据分组在一起。今天我们来看一个类似的概念&#xff0c;即 enums。 导论 Rust 中的枚举是一种数据类型&#xff0c;允许你通过列举可能的值来定义类型&#xff0c;提供了一种简洁而类…

Thinkphp--in-sqlinjection

一、漏洞原理 在 Builder 类的 parseData 方法中&#xff0c;由于程序没有对数据进行很好的过滤&#xff0c;将数据拼接进 SQL 语句&#xff0c;导致 SQL注入漏洞 的产生。 影响版本 5.0.13<ThinkPHP<5.0.15 5.1.0<ThinkPHP<5.1.5 在相应的文件夹位置打开终端…

No ‘Access-Control-Allow-Origin‘ header is present on the requested resource关于vue跨域问题

浏览器为了安全考虑&#xff0c;有一个最基本的安全策略&#xff0c;即同源策略。 同源策略规定&#xff1a;浏览器在解析Ajax请求时&#xff0c;要求浏览器的路径与Ajax的请求的路径必须满足三个要求&#xff0c;即请求的协议、域名、端口号都相同&#xff0c;满足同源策略&am…

IntelliJ IDEA 如何启用 JDK 预览特性

IntelliJ IDEA 也可以启用 JDK 的预览特性。 针对项目&#xff0c;选择项目结构。 配置是在语言结构上。 单击语言结构上的 SDK 默认&#xff0c;往下拉&#xff0c;就可以看到针对新版本的选项。 同时还可以看到那些版本是支持新特性预览的&#xff0c;那些版本是不支持新特…