米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
版本信息:
版本 REV2024
时间 11/30/2024
米联客 2024 版 FPGA 图像处理课程高级篇
Milianke 2024 Course
电子版自学资料
常州米联客信息科技有限公司
版权所有
米联客(MILIANKE)04QQ
米联客(MILIANKE)03QQ
米联客(MILIANKE)02QQ
米联客(MILIANKE)01QQ
群:516869816
群:543731097
群:86730608
群:34215299
微信扫码注册米联客技术论坛www.uisrc.com免费享受更多资源
扫码关注微信公众平台“MSXBO(米联客)”掌握更多信息动态
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
版本
时间
描述
Rev2024
2024-11-11
第一版
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
目录
米联客 2024 版 FPGA 图像处理课程高级篇 ........................................................................................................................... 1
1.图像处理基础知识 ................................................................................................................................................................... 7
1.1Python 简介 .....................................................................................................................................................................7
1.2 图像格式的区别以及应用 ............................................................................................................................................9
1.3 颜色空间 ..................................................................................................................................................................... 10
1.4 图像的颜色和视觉感知 ..............................................................................................................................................12
2. FPGA 实现 RGB 与 YUV 的相互转化 ............................................................................................................................... 13
2.1 概述 .............................................................................................................................................................................. 13
2.2YUV 格式介绍 ............................................................................................................................................................. 13
2.3RGB 转 YUV ................................................................................................................................................................ 14
2.3.1RGB 转 YUV 原理 ............................................................................................................................................14
2.3.2Verilog Design 代码分析 ...................................................................................................................................14
2.4YUV 转 RGB ................................................................................................................................................................ 17
2.4.1YUV 转 RGB 原理 ............................................................................................................................................17
2.4.2Verilog Design 代码分析 ...................................................................................................................................17
2.5 图片仿真 ...................................................................................................................................................................... 20
2.5.1Verilog Simulation 代码分析 ........................................................................................................................... 20
2.6 仿真结果 ...................................................................................................................................................................... 27
2.6.1 波形仿真结果 ...................................................................................................................................................27
2.6.2 图片仿真结果 ...................................................................................................................................................28
2.7Python 实现 ...................................................................................................................................................................29
2.7.1Python 代码 ....................................................................................................................................................... 29
2.7.2 结果显示 ...........................................................................................................................................................30
2.8 总结 .............................................................................................................................................................................. 31
3. FPGA 实现 RGB 与 HSV 相互转化 .................................................................................................................................... 32
3.1HSV 色彩空间简介 ......................................................................................................................................................32
3.2RGB 转 HSV .................................................................................................................................................................34
3.2.1RGB 转 HSV 原理分析 .................................................................................................................................... 34
3.2.2Verilog Design 代码分析 ...................................................................................................................................36
3.2.3 IP 调用之除法器 .............................................................................................................................................. 40
3.3HSV 转 RGB .................................................................................................................................................................42
3.3.1HSV 转 RGB 原理分析 .................................................................................................................................... 42
3.3.2Verilog Design 代码分析 ...................................................................................................................................44
3.4 图片仿真 ...................................................................................................................................................................... 48
3.4.1Verilog Simulation 代码分析 ........................................................................................................................... 48
3.5 仿真结果 ...................................................................................................................................................................... 55
3.5.1 波形仿真结果 ...................................................................................................................................................55
3.5.2 图片仿真结果 ...................................................................................................................................................56
3.6Python 实现 ...................................................................................................................................................................57
3.6.1Python 代码 ....................................................................................................................................................... 57
3.6.2 结果显示 ...........................................................................................................................................................58
3.7 总结 .............................................................................................................................................................................. 58
4.FPGA 实现并行视频接口转 Stream 接口 ........................................................................................................................... 60
4.1 并行视频接口和 Stream 接口简介 ............................................................................................................................ 60
4.2 代码分析(行数据有效和场数据有效) ................................................................................................................. 61
4.2.1Verilog Design 代码分析 ...................................................................................................................................61
4.2.2Verilog Simulation 代码分析 ........................................................................................................................... 63
第 2页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
4.2.3 仿真结果 ...........................................................................................................................................................66
4.3 代码分析(行数据有效和场数据有效) ................................................................................................................. 68
4.3.1Verilog Design 代码分析 ...................................................................................................................................68
4.3.2Verilog Simulation 代码分析 ........................................................................................................................... 70
4.3.3 仿真结果 ...........................................................................................................................................................73
5.FPGA 实现 Stream 接口转并行视频接口 ............................................................................................................................ 75
5.1 并行视频接口和 Stream 接口简介 ............................................................................................................................ 75
5.2 代码分析 ...................................................................................................................................................................... 76
5.2.1Verilog Design 代码分析 ...................................................................................................................................76
5.2.2Verilog Simulation 代码分析 ........................................................................................................................... 77
5.2.3 仿真结果 ...........................................................................................................................................................81
6.FPGA 实现行缓存设计(矩阵形成) ................................................................................................................................. 83
6.1 简介 .............................................................................................................................................................................. 83
6.2 原理讲解 ...................................................................................................................................................................... 83
6.3 代码分析 ...................................................................................................................................................................... 85
6.3.1Verilog Design 代码分析 ..................................................................................................................................85
6.3.2Verilog Simulation 代码分析 ........................................................................................................................... 89
6.4 仿真及结果 ..................................................................................................................................................................95
6.4.1 仿真波形图结果 ...............................................................................................................................................95
6.4.2 仿真图片结果 ...................................................................................................................................................96
6.5 总结 .............................................................................................................................................................................. 96
7.FPGA 实现双线性插值算法 ..................................................................................................................................................97
7.1 双线性插值法算法简介 ............................................................................................................................................. 97
7.2 原理 ..............................................................................................................................................................................97
7.3 模拟分析 ......................................................................................................................................................................98
8.FPGA 实现 Bayer 格式原始图像去马赛克处理 ................................................................................................................101
8.1 简介 ............................................................................................................................................................................ 101
8.2 去马赛克算法详述 ....................................................................................................................................................102
8.2.1 主要 IP ............................................................................................................................................................ 102
8.2.2raw_matrix_3x3_buffer 模块 .......................................................................................................................... 104
8.2.3bilinear_interpolati 模块 .................................................................................................................................. 106
8.2.4 双线性插值算法(单个时钟传输四个像素点) ........................................................................................ 109
8.3 相关 IP 调用详情 ..................................................................................................................................................... 110
8.3.1 去马赛克模块 IP 调用 ................................................................................................................................... 111
8.3.2 其他 IP 调用 ................................................................................................................................................... 113
8.4 代码分析 ................................................................................................................................................................... 124
8.4.1 mipi_to_raw_converter 模块代码分析 ..........................................................................................................124
8.4.2line_buffer 模块代码分析 ...............................................................................................................................126
8.4.3raw_matrix_3x3_buffer 模块代码分析 .......................................................................................................... 127
8.4.4bilinear_interpolation 模块代码分析 ..............................................................................................................132
8.5 上板结果 ....................................................................................................................................................................136
8.5.1 接线图 .............................................................................................................................................................136
8.5.2 结果显示 .........................................................................................................................................................136
8.6Python 实现 ................................................................................................................................................................ 137
8.6.1Python 代码分析 ............................................................................................................................................. 137
8.6.2 结果显示 .........................................................................................................................................................140
9.FPGA 实现图像自动白平衡处理 ....................................................................................................................................... 141
9.1 图像自动白平衡算法简介 ....................................................................................................................................... 141
9.2 图像自动白平衡算法原理 ........................................................................................................................................141
第 3页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
9.3 代码分析 ....................................................................................................................................................................142
9.3.1Verilog Design 代码分析 ................................................................................................................................ 142
9.3.2Verilog Simulation 代码分析 .......................................................................................................................... 152
9.4 仿真及结果 ................................................................................................................................................................159
9.4.1 仿真时序图结果 .............................................................................................................................................159
9.4.2 仿真图片结果 .................................................................................................................................................160
9.5 上板验证 ....................................................................................................................................................................160
9.5.1 结果展示 .........................................................................................................................................................161
9.6Python 实现 ................................................................................................................................................................ 161
9.6.1 代码实现 .........................................................................................................................................................161
9.6.2 结果实现 .........................................................................................................................................................162
10.FPGA 实现图像去噪处理 ..................................................................................................................................................164
10.1 图像去噪算法简介 ................................................................................................................................................. 164
10.2 原理分析 ..................................................................................................................................................................165
10.3 代码分析 ..................................................................................................................................................................167
10.3.1IP 分析 ........................................................................................................................................................... 167
10.3.2Verilog Design 代码分析 .............................................................................................................................. 168
10.3.3Verilog Simulation 代码分析 ........................................................................................................................ 178
10.4 仿真及结果 ..............................................................................................................................................................185
10.4.1 仿真时序图结果 ...........................................................................................................................................185
10.4.2 仿真图片结果 ...............................................................................................................................................186
10.5 上板结果 ................................................................................................................................................................. 186
10.6Python 实现 .............................................................................................................................................................. 187
10.6.1Python 代码实现 ........................................................................................................................................... 187
10.6.2 结果展示 .......................................................................................................................................................188
11.FPGA 实现图像自动曝光算法 ..........................................................................................................................................190
11.1 图像自动曝光算法简介 ......................................................................................................................................... 190
11.2 自动曝光算法原理 .................................................................................................................................................. 190
11.3 代码分析 .................................................................................................................................................................. 191
11.3.1IP 解析 ........................................................................................................................................................... 191
11.3.2Verilog Design 代码分析 ...............................................................................................................................192
11.3.3Verilog Simulation 代码分析 ........................................................................................................................ 200
11.4 仿真结果 .................................................................................................................................................................. 207
11.4.1 仿真波形图结果 ...........................................................................................................................................207
11.4.2 仿真图结果 ................................................................................................................................................... 208
11.5 上板结果 .................................................................................................................................................................. 208
11.6Python 实现 ...............................................................................................................................................................209
11.6.1 代码实现 ....................................................................................................................................................... 209
11.6.2 结果展示 ....................................................................................................................................................... 210
12.FPGA 实现图像对比度调节 ..............................................................................................................................................212
12.1 图像对比度调节简介 ..............................................................................................................................................212
12.2 原理分析 .................................................................................................................................................................. 212
12.3 代码分析 .................................................................................................................................................................. 212
12.3.1IP 解析 ........................................................................................................................................................... 212
12.3.2Verilog Design 代码分析 .............................................................................................................................. 213
12.3.3Verilog Simulation 代码分析 ........................................................................................................................ 216
12.4 仿真结果 .................................................................................................................................................................. 223
12.4.1 仿真波形图结果 ...........................................................................................................................................223
12.4.2 仿真图片结果 ...............................................................................................................................................225
第 4页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
12.5 上板结果 .................................................................................................................................................................. 225
12.6Python 实现 ...............................................................................................................................................................226
12.6.1Python 代码 ................................................................................................................................................... 226
12.6.2 结果显示 .......................................................................................................................................................227
13.FPGA 实现图像饱和度调节 ..............................................................................................................................................228
13.1 图像饱和度调节简介 ..............................................................................................................................................228
13.2 算法原理 .................................................................................................................................................................. 228
13.3.1IP 分析 ........................................................................................................................................................... 228
13.3.2Verilog Design 代码分析 .............................................................................................................................. 229
13.3.3Verilog 代码分析 ........................................................................................................................................... 234
13.4 仿真及结果 ..............................................................................................................................................................241
13.4.1 仿真波形图结果 ...........................................................................................................................................241
13.4.2 仿真图片结果 ...............................................................................................................................................242
13.5 上板结果 .................................................................................................................................................................. 242
13.6Python 实现 ...............................................................................................................................................................243
13.6.1 代码实现 .......................................................................................................................................................243
13.6.2 结果展示 .......................................................................................................................................................244
14.FPGA 实现图像亮度调节 ..................................................................................................................................................245
14.1 图像亮度调节简介 ..................................................................................................................................................245
14.2 图像亮度调节原理 ..................................................................................................................................................245
14.3 代码分析 .................................................................................................................................................................. 245
14.3.1IP 解析 ........................................................................................................................................................... 245
14.3.2Verilog Design 代码分析 .............................................................................................................................. 246
14.3.3Verilog Simulation 代码分析 ........................................................................................................................ 249
14.4 仿真结果 .................................................................................................................................................................. 255
14.4.1 仿真波形图结果 ...........................................................................................................................................255
14.4.2 仿真图片结果 ...............................................................................................................................................256
14.5 上板结果 .................................................................................................................................................................. 258
14.6Python 实现 ...............................................................................................................................................................259
14.6.1Python 代码 ................................................................................................................................................... 259
14.6.2 结果展示 .......................................................................................................................................................259
15.FPGA 实现图像 Gamma 校正 ...........................................................................................................................................261
15.1Gamma 算法简介 ..................................................................................................................................................... 261
15.2Gamma 算法原理 ..................................................................................................................................................... 262
15.3 代码分析 .................................................................................................................................................................. 262
15.3.1IP 讲解 ........................................................................................................................................................... 262
15.3.2Verilog Design 代码分析 .............................................................................................................................. 263
15.3.3Verilog Simulation 代码分析 ........................................................................................................................ 273
15.4 仿真结果 .................................................................................................................................................................. 280
15.4.1 仿真波形图结果 ...........................................................................................................................................280
15.4.2 仿真图结果 ...................................................................................................................................................281
15.5 上板结果 .................................................................................................................................................................. 281
15.6Python 实现 ...............................................................................................................................................................282
15.6.1Python 代码 ................................................................................................................................................... 282
15.6.2 结果展示 .......................................................................................................................................................283
16.FPGA 实现图像黑电平校正 ..............................................................................................................................................284
16.1 图像黑电平校正简介 ..............................................................................................................................................284
16.2 图像黑电平校正原理 ..............................................................................................................................................284
16.2.1 黑电平偏移的来源 .......................................................................................................................................284
第 5页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
16.2.2 黑电平偏移的基本步骤 ...............................................................................................................................284
16.2.3 黑电平校正的主要 IP 核 ............................................................................................................................. 285
16.3 代码分析 .................................................................................................................................................................. 286
16.3.1BLC 模块 ....................................................................................................................................................... 286
16.3.2BLC 测量模块 ............................................................................................................................................... 288
16.4 上板结果 .................................................................................................................................................................. 290
16.5Python 实现 ...............................................................................................................................................................291
16.5.1Python 代码 ................................................................................................................................................... 291
16.5.2 结果展示 .......................................................................................................................................................293
17.FPGA 实现图像锐化 ..........................................................................................................................................................294
17.1 图像锐化算法简介 ..................................................................................................................................................294
17.2 图像锐化算法原理 ..................................................................................................................................................294
17.2.1 拉普拉斯公式 ...............................................................................................................................................294
17.2.2 图像锐化具体步骤 .......................................................................................................................................294
17.3 设计分析 .................................................................................................................................................................. 295
17.3.1IP 分析 ........................................................................................................................................................... 295
17.3.2Verilog Design 代码分析 .............................................................................................................................. 296
17.3.3Verilog Simulation 代码分析 ........................................................................................................................ 301
17.4 仿真结果 .................................................................................................................................................................. 309
17.4.1 仿真波形图结果 ...........................................................................................................................................309
17.4.2 仿真图片结果 ...............................................................................................................................................309
17.5 上板结果 .................................................................................................................................................................. 310
17.6Python 实现 ...............................................................................................................................................................310
17.6.1 代码实现 .......................................................................................................................................................310
17.6.2 结果显示 ....................................................................................................................................................... 311
18.FPGA 实现 ISP ................................................................................................................................................................... 312
18.1ISP 简介 .................................................................................................................................................................... 312
18.2 设计分析 .................................................................................................................................................................. 312
18.3 上板结果 .................................................................................................................................................................. 312
19.结语 ..................................................................................................................................................................................... 314
附录一 :软件安装 ................................................................................................................................................................315
1.Python 安装教程 .......................................................................................................................................................... 315
2 PyCharm 安装教程 .......................................................................................................................................................318
附录二 :常见问题链接 ........................................................................................................................................................325
1 联系方式 ..............................................................................................................................................................325
2 售后 ...................................................................................................................................................................... 325
3 销售 ...................................................................................................................................................................... 325
4 在线视频 ..............................................................................................................................................................325
5 资源下载 ..............................................................................................................................................................325
6 软件或其他下载 ..................................................................................................................................................325
第 6页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
1.图像处理基础知识
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
数字图像处理,即用计算机对图像进行处理。他是一门相对年轻的学科。但是在短短的历史中,却以独特的魅
力被各个领域所着迷。由于图像处理的设备价格逐渐降低及其他的因素的推动下,数字图像处理的领域继续成长中。
数字图像处理系统分为三个部件处理图像的计算机,图像数字化仪器,图像显示设备。在其自然的形式下,图像并
不能直接由计算机分析。因为计算机只能处理数字而不是图片,所以一副图像在用计算机进行处理前必须先转化为
数字形式。数字图像就是用一个数字矩阵来表示一个物理图像。物理图像再次被划分称作图像元素(picture
element)的小区域,图像元素简称像素(pixel)。图像被分割成由相邻像素组成的许多水平线,赋予每个像素位置
的数值反应了物理图像上对应点的亮度。
图像转化的过程称为数字化,在每个像素位置,图像的亮度被采样和量化,从而得到图像对应点的亮暗程度的
一个整数值,每个像素具有位置和灰度两个属性
以下图一串对应图像组成的链表明图像处理的整个过程
1.1Python 简介
Python 是一种高级、解释型、通用的编程语言,由 Guido van Rossum 于 1980 年代末首次设计,并于 1991 年
首次发布,Python 的设计哲学强调代码的可读性和简洁性,使其成为初学者和专业开发者的热门选择。
第 7页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
想要使用 Python 进行操作,去官网下载好所需要的编译器和解释器即可,如果需要调用所需要的库,在控制台
输入命令 “pip install 库名称”下载即可,由于 Python 使用的是国外的镜像,所以有时候下载速度非常缓慢,这个
时候可以加上国内的镜像源,常用的国内镜像源有以下几个:
清华大学:https://pypi.tuna.tsinghua.edu.cn/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科技大学:https://pypi.mirrors.ustc.edu.cn/simple/
豆瓣 :http://pypi.douban.com/simple/
中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/
如此,在安装的所需要的库的时候,我们只需要在后面添加上“-i 镜像源” 即可。
简单举个例子,比如我们想要安装 numpy 库,不加速的情况下只需要输入以下命令:
pip install numpy
若需要加速,以清华大学镜像源为例,需要输入以下命令:
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple/
即可实现对安装 numpy 库的加速,当然还有一些其他的关于 pip 的指令,例如:
pip list
查看已安装包列表
pip install numpy
直接安装包
pip install numpy==1.2
安装指定版本为 1.2 的 numpy 包
pip install --upgrade numpy
升级包
pip uninstall numpy
卸载包
学会这些就可以初步对 Python 进行使用了,当然 Python 涉及的领域非常广泛,这里也是简单说明一下使用方法。
第 8页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
1.2 图像格式的区别以及应用
1.
jpg 格式
全名应该是 JPEG。JPEG 图片以 24 位颜色存储单个光栅图像。JPEG 是与平台无关的格式,支持最高级别的
压缩,不过,这种压缩是有损耗的。渐近式 JPEG 文件支持交错。可以提高或降低 JPEG 文件压缩的级别。但是,
文件大小是以图像质量为代价的。压缩比率可以高达 100:1。(JPEG 格式可在 10:1 到 20:1 的比率下轻松地压缩
文件,而图片质量不会下降。)JPEG 压缩可以很好地处理写实摄影作品。但是,对于颜色较少、对比级别强烈、
实心边框或纯色区域大的较简单的作品,JPEG 压缩无法提供理想的结果。有时,压缩比率会低到 5:1,严重损失了
图片完整性。这一损失产生的原因是,JPEG 压缩方案可以很好地压缩类似的色调,但是 JPEG 压缩方案不能很好
地处理亮度的强烈差异或处理纯色区域。
Jpeg 格式特点:
1、透明性:它不支持透明性
2、动画:它不支持动画
3、损耗性:除了一些比如说(仅仅是 90、180、270 度旋转),裁切,从标准类型到先进类型,编辑图片的原
数据之外,所有其它操作对 jpeg 图像的处理都会使得它的质量损失,所以我们在编辑过程一般用 png 作为过渡格式。
4、隔行渐进显示,它支持隔行渐进显示(但是 ie 浏览器并不支持这个属性,但是 ie 会在整个图像信息完全达
到的时候显示)。
由上可以看出 Jpeg 是最适 web 上面的摄影图片和数字照相机中。根据惊叹我们在页面中使用的商品图片、采
用人像或者好、实物素材制作的广告更适合采用 JPG 格式保存。
2.
gif 格式
GIF(GraphicsInterchange Format)的原义是“图像互换格式”,是 CompuServe 公司在 1987 年开发的图像文件格式。
GIF 文件的数据,是一种基于 LZW 算法的连续色调的无损压缩格式。其压缩率一般在 50%左右,它不属于任何应
用程序。目前几乎所有相关软件都支持它,公共领域有大量的软件在使用 GIF 图像文件。GIF 图像文件的数据是经
过压缩的,而且是采用了可变长度等压缩算法。所以 GIF 的图像深度从 lbit 到 8bit,也即 GIF 最多支持 256 种色彩
的图像。GIF 格式的另一个特点是其在一个 GIF 文件中可以存多幅彩色图像,如果把存于一个文件中的多幅图像数
据逐幅读出并显示到屏幕上,就可构成一种最简单的动画。
gif 格式特点:
1、透明性:gif 是一种布尔透明类型,即它可以使全透明,也可是全不透明,但是它并没有半透明的(alpha
透明)。
2、动画:gif 格式支持动画。
3、无损耗性:gif 是一种无损耗的图像格式,这也意味着你可以对 gif 图片做任何操作也不会使得图像质量产
生损耗。
4、水平扫描:gif 是使用一种叫做 LZW 的算法进行压缩的,当压缩 gif 的过程中,像素是由上到下水平压缩的,
这也意味着同等条件下,横向的 gif 图片比竖向的 gif 更加小。例如 500*10 的图片比 10*500 的图片更加小。
5、间隔渐进显示:gif 支持可选择性的间隔渐进显示。
由以上特点看出只有 256 种颜色的 gif 图片不适合照片,但它适合对颜色要求不高的图形(比如说图标、图表
等)。
3.
png 格式
PNG 是 20 世纪 90 年代中期开始开发的图像文件存储格式,其目的是企图替代 GIF 和 TIFF 文件格式,同时增
加一些 GIF 文件格式所不具备的特性。流式网络图形格式(Portable Network Graphic Format,PNG)名称来源于非官
方的“PNG’s NotGIF”,是一种位图文件(bitmapfile)存储格式,读成“ping”。PNG 用来存储灰度图像时,灰度图像的
深度可多到 16 位,存储彩色图像时,彩色图像的深度可多到 48 位,并且还可存储多到 16 位的α通道数据。PNG 使
用从 LZ77 派生的无损数据压缩算法。
Png 格式特点:
1、类型:Png 这种图片格式包括了许多类,但是在实践的大致中可以分为 256 色的 png 和全色的 png,你完全
第 9页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以用 256 色的 png 代替 gif,用全色的 png 代替 jpeg。
2、透明性:png 是完全支持 alpha 透明的(透明、半透明、不透明),尽管有两个怪异的现象在 ie6(下面详
细讨论)
3、动画:它不支持动画 Png8 的在 ie 中的怪异表现,半透明的 png8 在 ie6 以下的浏览器显示为全透明。alpha 透
明的全色 PNG(png32)在 ie6 中会出现背景颜色(通常是灰色)
上面可以总结:全透明的 png8 可以在任一浏览器正常显示(就像 gif 一样)。半透明的 png8 在除了 ie6 及其一
下的浏览器下错误的显示成全透明,其它的浏览器都能正常显示半透明。图像上颜色较少、并且主要以纯色或者平
滑的渐变色填充以及具备较大的亮度差异的图像适合以 png8 格式存储。
4.
svg 格式
可缩放矢量图形是基于可扩展标记语言(标准通用标记语言的子集),用于描述二维矢量图形的一种图形格式。
它由万维网联盟制定,是一个开放标准。
SVG 格式特点:
1、SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
2、SVG 用来定义用于网络的基于矢量的图形
3、SVG 使用 XML 格式定义图形
4、SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失
5、SVG 是万维网联盟的标准
6、SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体
SVG 跟上面这些图片格式最大的不同,是 SVG 是矢量图。这意味着 SVG 图片由直线和曲线以及绘制它们的方
法组成。当你放大一个 SVG 图片的时候,你看到的还是线和曲线,而不会出现像素点。这意味着 SVG 图片在放大
时,不会失真,所以它非常适合用来绘制企业 Logo、Icon 等。
5.
bmp 格式
BMP 是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,
不采用其他任何压缩,因此,BMP 文件所占用的空间很大。BMP 文件的图像深度可选 lbit、4bit、8bit 及 24bit。BMP
文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。
这是一种比较老的图片格式。BMP 是无损的,但同时这种图片格式几乎没有对数据进行压缩,所以 BMP 格式
的图片通常具有较大的文件大小。虽然同时支持索引色和直接色是一个优点,但是太大的文件格式格式导致它几乎
没有用武之地,现在除了在 Windows 操作系统中还比较常见之外,我们几乎看不到它。
6.
WebP 格式
WebP 是谷歌开发的一种新图片格式,WebP 是同时支持有损和无损压缩的、使用直接色的、点阵图。
想象 Web 上的图片之多,百分之几十的提升,是非常非常大的优化。只可惜,目前只有 Chrome 浏览器和 Opera
浏览器支持 WebP 格式,所以 WebP 的应用并不广泛。为了使用更先进的技术,比如 WebP 图片格式,来压缩互联
网上传输的数据流量,谷歌甚至提供了 Chrome Data Compression Proxy,设置了 Chrome Data Compression Proxy 作
为 Web 代理之后,你访问的所有网站中的图片,在经过 Proxy 的时候,都会被转换成 WebP 格式,以降低图片文件
的大小。从名字就可以看出来它是为 Web 而生的,什么叫为 Web 而生呢?就是说相同质量的图片,WebP 具有更小
的文件体积。现在网站上充满了大量的图片,如果能够降低每一个图片的文件大小,那么将大大减少浏览器和服务
器之间的数据传输量,进而降低访问延迟,提升访问体验。
1.3 颜色空间
1.
RGB 颜色空间
RGB 颜色空间是一种基于红色(Red)、绿色(Green)和蓝色(Blue)三种基本颜色的颜色模型。这三种颜色
通过不同的组合和强度可以表示出各种各样的颜色。RGB 颜色空间广泛应用于显示器、电视、相机和其他电子显示
设备。
第 10页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
RGB 颜色空间有多种表示形式,这些形式主要区别在于每种颜色分量的位数和总位数,下面会简单介绍一些常
见的形式以及它们的应用和优缺点:
RGB332:
位数分配: 3 位红色,3 位绿色,2 位蓝色,共 8 位(1 字节)。
色彩数量: 2^8 = 256 种颜色。
应用: 适用于非常低资源的显示设备,如一些简单的图形 LCD 屏。
优点: 占用极少的存储空间和带宽。
缺点: 色彩表现力非常有限,颜色过渡不平滑。
RGB444:
位数分配: 每种颜色 4 位,共 12 位。
色彩数量: 2^12 = 4,096 种颜色。
应用: 用于一些需要比 RGB332 更好但不需要 RGB565 或 RGB888 的场景。
优点: 比 RGB332 有更好的色彩表现力,仍然相对节省存储空间。
缺点: 色彩表现力仍然有限。
RGB666:
位数分配: 每种颜色 6 位,共 18 位。
色彩数量: 2^18 = 262,144 种颜色。
应用: 用于一些需要比 RGB565 更好但不需要 RGB888 的场景,如某些中端显示器。
优点: 提供比 RGB565 更多的颜色,色彩表现力较好。
缺点: 占用的存储空间和带宽比 RGB565 多,但比 RGB888 少。
RGB565:
位数分配: 5 位红色,6 位绿色,5 位蓝色,共 16 位(2 字节)。
色彩数量: 2^16 = 65,536 种颜色。
应用: 常用于需要较低存储和带宽的应用场景,如嵌入式系统和一些移动设备的显示屏。
优点: 占用较少的存储空间和带宽,适合资源受限的设备。
缺点: 色彩表现力较低,特别是红色和蓝色的表现力因为只有 5 位而相对较差。
RGB888:
位数分配: 每种颜色 8 位,共 24 位(3 字节)。
色彩数量: 2^24 = 16,777,216 种颜色。
应用: 广泛应用于需要高色彩表现力的场景,如电脑显示器、电视、相机和图像处理。
优点: 色彩表现力强,能够显示更丰富和细腻的颜色。
缺点: 占用更多的存储空间和带宽,不适合资源受限的设备。
2.
HSV 颜色空间
HSV 颜色空间是一种基于人类视觉感知的颜色模型,它通过色调(Hue)、饱和度(Saturation)和明度(Value)
三个参数来描述颜色。HSV 颜色空间在图像处理、计算机视觉和图形设计中有广泛应用,因为它更直观地反映了人
类对颜色的感知方式,下面说说它的一些应用场景。
图像处理: 在图像处理中,HSV 颜色空间常用于颜色分割、颜色滤波和颜色增强等操作。
计算机视觉: 在计算机视觉中,HSV 颜色空间常用于物体检测和跟踪,因为它对光照变化不敏感。
图形设计: 在图形设计中,HSV 颜色空间使得设计师更容易调整颜色的色调、饱和度和亮度。
3.
CMYK 颜色空间
CMYK 颜色空间是一种基于减色模型的颜色表示方法,主要用于印刷和一些彩色打印设备。CMYK 代表青色
(Cyan)、品红色(Magenta)、黄色(Yellow)和黑色(Key, K),与 RGB 颜色空间(加色模型)不同,CMYK
颜色空间通过吸收光线来表示颜色,下面详细介绍它的颜色组成:
青色(Cyan, C):
定义: 青色是 RGB 颜色空间中绿色和蓝色的混合色,对应于吸收红光的颜料。
范围: 通常表示为 0 到 100%,0 表示没有青色,100%表示完全青色。
第 11页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
品红色(Magenta, M):
定义: 品红色是 RGB 颜色空间中红色和蓝色的混合色,对应于吸收绿光的颜料。
范围: 通常表示为 0 到 100%,0 表示没有品红色,100%表示完全品红色。
黄色(Yellow, Y):
定义: 黄色是 RGB 颜色空间中红色和绿色的混合色,对应于吸收蓝光的颜料。
范围: 通常表示为 0 到 100%,0 表示没有黄色,100%表示完全黄色。
黑色(Key, K):
定义: 黑色用于增加颜色的深度和对比度,补充其他三种颜色的不足。
范围: 通常表示为 0 到 100%,0 表示没有黑色,100%表示完全黑色。
4.
YUV/YCbCr 颜色空间
YUV 和 YCbCr 颜色空间主要用于视频解码、图像处理和电视广播等领域,它们是由 RGB 颜色空间转换而来
的,分别包含三个分量:
Y(Luma): 表示图像的亮度信息。
Cb(Chrominance, Blue-difference component): 表示蓝色色度信息,即蓝色分量与亮度的差值。
Cr(Chrominance, Red-difference component): 表示红色色度信息,即红色分量与亮度的差值。
这两种颜色空间在图像和视频处理中的广泛应用,充分利用了它们在亮度和色度分离方面的优势,使得颜色信
息的处理和传输更加高效和准确。
1.4 图像的颜色和视觉感知
1.
亮度
在图像处理中,亮度(Brightness)是一个关键的视觉特性,它表示图像的明暗程度,亮度反映了图像中每个像
素的光强度,是人类视觉系统对光线强弱的感知,亮度在不同的颜色空间中有不同的表示方法,但其核心概念是相
同的,即它描述了图像的整体光照水平。
2.
色调
色调(Hue)是图像处理中一个重要的颜色特性,它描述了颜色的基本类型或类别,如红色、绿色、蓝色等。
色调是颜色的一个基本属性,通常用角度表示,范围从 0°到 360°,色调在颜色空间中的表示和调整对于图像处
理、图形设计和计算机视觉等领域有重要意义。
3.
饱和度
饱和度指的是颜色的纯度,即颜色的鲜艳程度,高饱和度的颜色看起来更鲜艳和生动,低饱和度的颜色看起来
更灰暗和柔和,在不同的颜色空间中,饱和度的表示方法有所不同。
4.
对比度
对比度表示图像中最亮和最暗部分的差异程度,高对比度意味着亮部和暗部的差异大,低对比度意味着亮部和
暗部的差异小,它是图像处理和显示技术中一个重要的性能指标,其可以通过调整图像的亮度分布来表示。
第 12页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
2. FPGA 实现 RGB 与 YUV 的相互转化
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
2.1 概述
RGB 和 YUV 是两种不同的颜色空间,各自有其特定的用途和优点,Y'UV 的发明是由于彩色电视与黑白电视
的过渡时期黑白视频只有 Y(Luma,Luminance)视频,也就是灰阶值。到了彩色电视规格的制定,是以 YUV/YIQ
的格式来处理彩色电视图像,把 UV 视作表示彩度的 C(Chrominance 或 Chroma),如果忽略 C 信号,那么剩下的
Y(Luma)信号就跟之前的黑白电视频号相同,这样一来便解决彩色电视机与黑白电视机的兼容问题。Y'UV 最大
的优点在于只需占用极少的带宽。
再说说 RGB 颜色空间,它是由红色(Red)、绿色(Green)和蓝色(Blue)三种基色组成,通常用于显示设
备,如计算机显示器、电视和相机传感器,因为这些设备直接使用这三种颜色来产生其他颜色,而 YUV 颜色空间,
它是由亮度(Y)和两个色度(U 和 V)分量组成,其中 Y 表示图像的亮度信息,,U 和 V 表示色彩信息,即色度,
广泛用于视频压缩和传输,如 JPEG 图像压缩、MPEG 视频压缩和广播电视。
2.2YUV 格式介绍
在 YUV 格式中,各个字母分别代表以下含义:
Y(Luma or Luminance):Y 表示亮度(也称为亮度或明度),它代表图像的灰度信息,描述了图像的光亮程
度。亮度信息是通过将 RGB 颜色空间中的红、绿、蓝三种颜色加权平均得到的,人眼对亮度的变化比对色度的变
化更敏感。
U(Chrominance - Blue projection):U 表示色度信息中的蓝色分量(具体来说是蓝色投影),它表示图像中的
颜色信息,与亮度信息相对独立。U 分量是由蓝色信号(B)减去亮度信号(Y)后得到的偏差量,具体公式为:
U=B-Y
V(Chrominance - Red projection):V 表示色度信息中的红色分量(具体来说是红色投影),它同样表示图像
中的颜色信息,与亮度信息相对独立。V 分量是由红色信号(R)减去亮度信号(Y)后得到的偏差量,具体公式
为:
V=R-Y
总结来说,YUV 颜色空间将图像的亮度信息(Y)和色度信息(U 和 V)分离开来,使得在处理、压缩和传输
图像和视频时更加高效和便捷。这种分离有助于优化各种图像处理算法和提高压缩效率,从而在保证图像质量的同
时减少数据量。
下面将简单介绍 5 钟 YUV 格式:
4:4:4 表示完全取样。
4:4:0 表示水平完全取样,垂直 4:1 采样。
4:2:2 表示 2:1 的水平取样,垂直完全采样。
4:2:0 表示 2:1 的水平取样,垂直 2:1 采样。
4:1:1 表示 4:1 的水平取样,垂直完全采样。
(1).YUV444:
每个像素都包含一组完整的 Y、U、V 分量
YUV444 每个像素占用的存储空间,也就是像素深度(piex_depth)为:3 * 8bit = 24bits
一帧 YUV444 图像占用的空间就是:w * h * 3byte
(2).YUV440:
第 13页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
垂直方向两个相邻的像素共用一组 U、V
YUV440 的像素深度(piexl_depth):(1 * 8bit) + (0.5 *8bit) + (0.5 *8bit) = 16bits
一帧 YUV440 图像占用的空间就是:w * h * 2byte
(3).YUV422:
水平方向两个相邻的像素共用一组 U、V
YUV422 的像素深度(piexl_depth):(1 * 8bit) + (0.5 *8bit) + (0.5 *8bit) = 16bits
一帧 YUV422 图像占用的空间就是:w * h * 2byte
(4).YUV411:
水平方向两个相邻的像素共用一组 U、V
YUV411 的像素深度(piexl_depth):(1 * 8bit) + 2*(0.25 *8bit) = 12bits
一帧 YUV411 图像占用的空间就是:w * h * 1.5byte
(5).YUV420:
水平垂直方向四个相邻的像素共用一组 U、V
YUV420 的像素深度(piexl_depth):(1 * 8bit) + 2*(0.25 *8bit) = 12bits
一帧 YUV420 图像占用的空间就是:w * h * 1.5byte
2.3RGB 转 YUV
RGB 转 YUV 的意义在于,YUV 格式更便于进行色彩调整和图像处理,如亮度调节、色彩校正等,因为 YUV
将亮度信息(Y)与色度信息(U 和 V)分离,这种分离有助于在视频压缩中利用人眼对亮度更敏感而对色度不太
敏感的特性,而且在视频压缩中,YUV 格式允许对色度分量进行更高程度的压缩(如 4:2:0 采样),而不显著影响
视觉质量,这提高了压缩效率,降低了带宽需求。
2.3.1RGB 转 YUV 原理
此处采用的为 BT.601 标准,它在标清电视时代被广泛采用,尽管现在高清和超高清标准(如 BT.709 和 BT.2020)
已经取代了它在许多应用中的地位,但它仍然是理解数字视频编码和处理的重要基础。
RGB 转 YUV 的公式为:
Y = 0.299R + 0.587G + 0.114B
U=Cb = 0.564(B - Y) + 128
V=Cr = 0.713(R - Y) + 128
2.3.2Verilog Design 代码分析
module RGB2YUV
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
I_tdata
,
input
[23:0]
,
input
I_tvalid ,
output
I_tready ,
output
O_tlast
,
第 14页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
output
O_tuser
,
output [23:0]
O_tdata
,
output
O_tvalid ,
input
O_tready
);
/*****************************************************************
signals declaration
*****************************************************************/
reg
[2:0]
I_tlast_r
;
reg
[2:0]
I_tuser_r
;
reg
[2:0]
I_tvalid_r
;
reg
[17:0]
Y_red ,U_red ,V_red
reg
[17:0]
Y_green,U_green,V_green;
reg
[17:0]
Y_blue ,U_blue ,V_blue ;
reg
[17:0] Y_r0;
reg
[17:0] U_r0;
reg
[17:0] V_r0;
reg
[7:0]
Y;
reg
[7:0]
U;
reg
[7:0]
V;
wire [7:0]
rgb888_r = I_tdata[16+:8];
wire [7:0]
rgb888_g = I_tdata[8+:8] ;
wire [7:0]
rgb888_b = I_tdata[0+:8] ;
;
parameter C0 = 9'd306;//0.299*1024;
parameter C1 = 10'd601;//0.587*1024;
parameter C2 = 7'd117;//0.114*1024;
parameter C3 = 8'd173;//0.169*1024;
parameter C4 = 9'd339;//0.331*1024;
parameter C5 = 10'd512;//0.5*1024;
parameter C6 = 10'd512;//0.5*1024;
parameter C7 = 9'd429;//0.419*1024;
parameter C8 = 7'd83;//0.081*1024;
parameter BASE = 128*1024;
/*****************************************************************
Calculation description
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y_red
<= 0;
Y_green <= 0;
Y_blue <= 0;
U_red
<= 0;
U_green <= 0;
U_blue <= 0;
第 15页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
V_red
<= 0;
V_green <= 0;
V_blue <= 0;
end
else if(I_tvalid)begin
Y_red
<= rgb888_r * C0;
Y_green <= rgb888_g * C1;
Y_blue
<= rgb888_b * C2;
U_red
<= rgb888_r * C3;
U_green <= rgb888_g * C4;
U_blue
<= rgb888_b * C5;
V_red
<= rgb888_r * C6;
V_green <= rgb888_g * C7;
V_blue
<= rgb888_b * C8;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y_r0
<= 18'd0 ;
U_r0
<= 18'd0 ;
V_r0
<= 18'd0 ;
end
else if(I_tvalid_r[0])begin
Y_r0 <= Y_red + Y_green + Y_blue ;
U_r0 <= U_blue - U_red
- U_green + BASE;
V_r0 <= V_red - V_green - V_blue + BASE;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y <= 0;
U <= 0;
V <= 0;
end
else if(I_tvalid_r[1])begin
Y <= Y_r0[17:10];
U <= U_r0[17:10];
V <= V_r0[17:10];
end
end
/*****************************************************************
Signal synchronization
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
第 16页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[1:0],I_tlast};
I_tuser_r <= {I_tuser_r[1:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[1:0],I_tvalid};
end
end
assign
O_tlast
= I_tlast_r[2];
assign
O_tuser
= I_tuser_r[2];
assign
O_tvalid = I_tvalid_r[2];
assign
O_tdata = {Y,U,V};
assign I_tready = O_tready;
endmodule
2.4YUV 转 RGB
2.4.1YUV 转 RGB 原理
此处采用的为 BT.601 标准,它在标清电视时代被广泛采用,尽管现在高清和超高清标准(如 BT.709 和 BT.2020)
已经取代了它在许多应用中的地位,但它仍然是理解数字视频编码和处理的重要基础。
YUV 转 RGB 的公式为:
R = Y + 1.402*(V-128) = Y + 1.402V - 1.402*128
G = Y - 0.344*(U-128) - 0.714*(V-128) = Y - 0.344*U -0.714*V + 1.058*128
B = Y + 1.772*(U-128) = Y + 1.772*U - 1.772*128
2.4.2Verilog Design 代码分析
RGBתYUV
Y=0.299*Rʮ0.587*G+0.114*B
U=Cb=0.564*(B-Y) + 128 = 0.499704*B - 0.168636*R - 0.331068*G + 128 = 0.5*B - 0.169*R - 0.331*G +
128
V=Cr=0.713*(R-Y) + 128 = 0.499813*R - 0.418531*G - 0.081282*B + 128 = 0.5*R - 0.419*G - 0.081*B +
128
YUVתRGB
R = Y + 1.402*(V-128) = Y + 1.402V - 1.402*128
G = Y - 0.344*(U-128) - 0.714*(V-128) = Y - 0.344*U -0.714*V + 1.058*128
B = Y + 1.772*(U-128) = Y + 1.772*U - 1.772*128
*****************************************************************/
module YUV2RGB
(
input
I_clk
input
I_rst_n,
,
第 17页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
input
I_tlast
,
input
I_tuser
,
I_tdata
,
input
[23:0]
input
I_tvalid ,
output
I_tready ,
output
O_tlast
,
output
O_tuser
,
output [23:0]
O_tdata
,
output
O_tvalid ,
input
O_tready
);
/*****************************************************************
signals declaration
*****************************************************************/
reg
[2:0]
I_tlast_r
;
reg
[2:0]
I_tuser_r
;
reg
[2:0]
I_tvalid_r
;
wire [7:0] Y, U, V;
reg [17:0] Y_m;
reg [18:0] R_V_m;
reg [16:0] G_U_m;
reg [17:0] G_V_m;
reg [18:0] B_U_m;
reg [19:0] R_s;
reg [19:0] G_s;
reg [19:0] B_s;
reg [7:0] R, G, B;
parameter C0 = 11'd1436;//1.402*1024;
parameter C1 = 9'd352;//0.344*1024;
parameter C2 = 10'd731;//0.714*1024;
parameter C3 = 11'd1814;//1.772*1024;
parameter R_BASE = 18'd183763;//1.402*128*1024
parameter G_BASE = 18'd138674;//1.058*128*1024
parameter B_BASE = 18'd232260;//1.772*128*1024
assign {Y, U, V} = I_tdata;
/*****************************************************************
Calculation description
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
Y_m <= 0;
R_V_m <= 0;
G_U_m <= 0;
第 18页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
G_V_m <= 'b0;
B_U_m <= 'b0;
end else begin
if(I_tvalid) begin
Y_m <= {Y,10'b0};
R_V_m <= V*C0;
G_U_m <= U*C1;
G_V_m <= V*C2;
B_U_m <= U*C3;
end
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R_s, G_s, B_s} <= 0;
end
else if(I_tvalid_r[0]) begin
R_s <= Y_m + R_V_m - R_BASE;
G_s <= Y_m - G_U_m - G_V_m + G_BASE;
B_s <= Y_m + B_U_m - B_BASE;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R, G, B} <= 0;
end
else if(I_tvalid_r[1]) begin
R <= R_s[19] ? 'b0 : R_s[18] ? 'd255 : R_s[17:10];
G <= G_s[19] ? 'b0 : G_s[18] ? 'd255 : G_s[17:10];
B <= B_s[19] ? 'b0 : B_s[18] ? 'd255 : B_s[17:10];
end
end
/*****************************************************************
Signal synchronization
*****************************************************************/
//同步信号
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[1:0],I_tlast};
I_tuser_r <= {I_tuser_r[1:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[1:0],I_tvalid};
end
第 19页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end
assign
O_tlast
= I_tlast_r[2];
assign
O_tuser
= I_tuser_r[2];
assign
O_tvalid = I_tvalid_r[2];
assign
O_tdata = {R, G, B};
assign I_tready = O_tready;
endmodule
2.5 图片仿真
在 FPGA 图像处理基础课程中,对于一些图像处理类的 demo 可以先用图片仿真去进行检测,这样不仅能大幅
度减少我们设计的时间,也能让我们从中快速发现错误,详情请参考米联客的 FPGA 图像处理基础课程。
2.5.1Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
*****************************************************************/
// Define the image resolution here
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE_RGB "../../../../picture_bmp/out/output_rgb.bmp"
`define OUTPUT_IMAGE_YUV "../../../../picture_bmp/out/output_yuv.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
第 20页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 1
module image_simulation();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_rgb_fd, output_yuv_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer rgb_offset, yuv_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
第 21页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`COLOR_DEPTH*3-1:0] input_rgb_data;
wire yuv_data_valid;
wire [`COLOR_DEPTH*3-1:0] yuv_data;
wire output_data_valid;
wire [`COLOR_DEPTH*3-1:0] output_rgb_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tlast_yuv ;
wire
O_tuser_yuv ;
wire
O_tready_yuv;
wire
O_tlast ;
wire
O_tuser ;
wire
O_tready;
reg
de_r0;
reg
data_req;
reg
flag_req;
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_output_valid, prev_yuv_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_red, output_green, output_blue;
wire [`COLOR_DEPTH-1:0] output_y, output_u, output_v;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
第 22页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - 1));
#(CLOCK_PERIOD * 2);
// Adjust file lengths to be multiples of 4 bytes (BMP format requirement)
$fseek(output_rgb_fd, 0, `SEEK_END);
$fseek(output_yuv_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_rgb_fd) % 4;
if (padding_bytes != 0) begin
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_rgb_fd, "%c", 0);
$fwrite(output_yuv_fd, "%c", 0);
end
end
// Close all files
$fclose(output_rgb_fd);
$fclose(output_yuv_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
第 23页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end
// Open output files for writing
output_rgb_fd = $fopen(`OUTPUT_IMAGE_RGB, "wb");
output_yuv_fd = $fopen(`OUTPUT_IMAGE_YUV, "wb");
// Write BMP header to output files
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_rgb_fd, "%c", bmp_header[i]);
$fwrite(output_yuv_fd, "%c", bmp_header[i]);
end
// Set file offsets to the beginning of the image data
rgb_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
yuv_offset = rgb_offset;
$fseek(output_rgb_fd, rgb_offset, 0);
$fseek(output_yuv_fd, yuv_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to YUV conversion module
RGB2YUV RGB2YUV
(
/* input
*/.I_clk
/* input
*/.I_rst_n (I_rst_n),
/* input
*/.I_tlast (I_tlast),
/* input
*/.I_tuser (I_tuser),
/* input
[23:0]
(I_clk),
*/.I_tdata (input_rgb_data),
/* input
*/.I_tvalid(data_valid),
/* output
*/.I_tready(O_tready_yuv),
/* output
*/.O_tlast (O_tlast_yuv),
/* output
*/.O_tuser (O_tuser_yuv),
/* output [23:0]
*/.O_tdata (yuv_data),
/* output
*/.O_tvalid(yuv_data_valid),
/* input
*/.O_tready(I_tready)
);
// Instantiate the YUV to RGB conversion module
YUV2RGB YUV2RGB
(
第 24页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
/* input
*/.I_clk
/* input
*/.I_rst_n (I_rst_n),
/* input
*/.I_tlast (O_tlast_yuv),
/* input
*/.I_tuser (O_tuser_yuv),
/* input
[23:0]
Image processing course advanced(2024)
(I_clk),
*/.I_tdata (yuv_data),
/* input
*/.I_tvalid(yuv_data_valid),
/* output
*/.I_tready(O_tready),
/* output
*/.O_tlast (O_tlast ),
/* output
*/.O_tuser (O_tuser ),
/* output [23:0]
*/.O_tdata (output_rgb_data),
/* output
*/.O_tvalid(output_data_valid),
/* input
*/.O_tready(O_tready_yuv)
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
// I_tuser <= 1'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
第 25页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1) ;
// Assemble input RGB data from individual color channels
assign input_rgb_data = {red_channel[memory_address], green_channel[memory_address],
blue_channel[memory_address]};
// Extract individual color components from output data
assign {output_y, output_u, output_v} = yuv_data;
assign {output_red, output_green, output_blue} = output_rgb_data;
// Write output data to files
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_output_valid <= 0;
prev_yuv_valid <= 0;
end else begin
prev_output_valid <= output_data_valid;
prev_yuv_valid <= yuv_data_valid;
// If YUV data is valid, write to YUV output files
if (yuv_data_valid) begin
$fwrite(output_yuv_fd, "%c", output_y);
$fwrite(output_yuv_fd, "%c", output_u);
$fwrite(output_yuv_fd, "%c", output_v);
第 26页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
end else if (prev_yuv_valid) begin
// Move file pointer to the previous line for BMP format
yuv_offset = yuv_offset - `IMAGE_WIDTH * 3;
$fseek(output_yuv_fd, yuv_offset, 0);
end
// If RGB output data is valid, write to RGB output file
if (output_data_valid) begin
$fwrite(output_rgb_fd, "%c", output_blue);
$fwrite(output_rgb_fd, "%c", output_green);
$fwrite(output_rgb_fd, "%c", output_red);
output_pixel_counter <= output_pixel_counter + 1;
end else if (prev_output_valid) begin
// Move file pointer to the previous line for BMP format
rgb_offset = rgb_offset - `IMAGE_WIDTH * 3;
$fseek(output_rgb_fd, rgb_offset, 0);
end
end
end
endmodule
2.6 仿真结果
2.6.1 波形仿真结果
第 27页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
2.6.2 图片仿真结果
原图(RGB)结果显示:
YUV 结果显示:
第 28页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
文档结果显示:
2.7Python 实现
2.7.1Python 代码
import cv2
# 1.读取图像
file_path = '001.bmp'
第 29页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
rgb_image = cv2.imread(file_path)
# 2.将 RGB 图像转换为 YUV 图像
yuv_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2YUV)
# 3.将 YUV 图像转为 RGB 图像
rgb_image_again = cv2.cvtColor(yuv_image, cv2.COLOR_YUV2RGB)
# 4.建立窗口
#cv2.WINDOW_NORMAL: 值为 0,表示创建一个可调整大小的窗口。你可以手动调整窗口的大小。
#cv2.WINDOW_AUTOSIZE: 值为 1,表示创建一个自动调整大小的窗口,窗口的大小会根据显示的图像自动调整,无法
手动调整窗口大小。
#cv2.WINDOW_FULLSCREEN: 表示创建一个全屏窗口。
#cv2.WINDOW_FREERATIO: 表示窗口的宽高比可以自由调整。
#cv2.WINDOW_KEEPRATIO: 表示窗口的宽高比保持不变。
cv2.namedWindow("rgb",0)
cv2.resizeWindow("rgb",300,180)
cv2.namedWindow("yuv",0)
cv2.resizeWindow("yuv",300,180)
cv2.namedWindow("rgb_again",0)
cv2.resizeWindow("rgb_again",300,180)
# 5.图像显示
cv2.imshow('rgb',rgb_image)
cv2.imshow('yuv',yuv_image)
cv2.imshow('rgb_again',rgb_image_again)
# 6.设置窗口显示时间
cv2.waitKey(10000000)
# 7.关闭所有窗口
cv2.destroyAllWindows()
在 file_path 后面输入自己找的图片即可。
2.7.2 结果显示
这是 Python 代码运行的结果:
第 30页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见,这个经过了转化后和前面所用算法经过转化后的图差不多。
2.8 总结
RGB 与 YUV 互转在图像和视频处理领域具有重要意义,特别是在需要压缩、传输和处理视频数据的场合,选
择合适的颜色空间可以提高处理效率和视觉效果。
第 31页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
3. FPGA 实现 RGB 与 HSV 相互转化
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
3.1HSV 色彩空间简介
HSV 颜色空间是一种常用的颜色表示方法,它以更符合人类视觉感知的方式描述颜色,HSV 代表色相(Hue)、
饱和度(Saturation)和明度(Value),这三个分量分别对应颜色的基本属性,下面将详细介绍它的基本组成,下
面是它的一个颜色模型图:
Hue(色相):
色相表示颜色的基本类型,如红色、绿色、蓝色等。
通常以角度表示,范围为 0°到 360°。例如,0°表示红色,120°表示绿色,240°表示蓝色。
色相是一个循环的概念,0°和 360°都表示红色。
第 32页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Saturation(饱和度):
饱和度表示颜色的纯度或强度。
范围为 0 到 1,值越高表示颜色越纯,越低表示颜色越灰。
饱和度为 0 时,颜色是灰色(无色相)。
Value(明度):
明度表示颜色的亮度。
范围为 0 到 1,值越高表示颜色越亮。
明度为 0 时,颜色为黑色(无论色相和饱和度如何)。
第 33页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
3.2RGB 转 HSV
3.2.1RGB 转 HSV 原理分析
RGB 到 HSV 转换的步骤:
1. 归一化 RGB 值
首先,将 RGB 值归一化到 [0, 1] 的范围,但是如果归一化到 [0, 1] ,那么后续的代码复杂度就会大大加深,所
以此处直接使用,R、G、B 原值,即 0-255 的范围。
2. 计算最大值和最小值
为了计算 HSV 模型中的亮度 (V) 和饱和度 (S),我们需要找到 RGB 值中的最大值和最小值:
然后计算最大值和最小值之间的差值 (即色彩的变化量):
3. 计算亮度 (Value)
亮度 ( V ) 是颜色的最大分量,它反映了颜色的强度或亮度。亮度的计算公式为:
在 HSV 模型中,亮度 ( V ) 直接等于 RGB 中的最大分量。
第 34页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
4. 计算饱和度 (Saturation)
饱和度 ( S ) 表示颜色的纯度,它定义为最大分量和最小分量的差值相对于最大分量的比例。如果颜色是灰色,则
饱和度为 0;否则,饱和度为:
5. 计算色相 (Hue)
色相 ( H ) 表示颜色的类型,它是基于哪个 RGB 分量最大来计算的。色相通常是一个角度值,表示颜色在色轮上
的位置。色相的计算分为三种情况:
5.1 如果红色是最大值
当 ( R ) 是最大值时,色相的计算公式为:
5.2 如果绿色是最大值
当 ( G ) 是最大值时,色相的计算公式为:
5.3 如果蓝色是最大值
当 ( B ) 是最大值时,色相的计算公式为:
这些公式的作用是将色相映射到 0 到 255 的范围。
6. 特殊情况:灰色
如果 ( Δ=Max−Min= 0 ),说明 ( R = G = B ),此时颜色是灰色。灰色没有色相和饱和度,因此:
7. 总结公式
7.1 最大值和最小值
首先,计算 RGB 中的最大值和最小值:
7.2 亮度 ( V )
亮度直接等于最大分量:
第 35页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
7.3 饱和度 ( S )
饱和度的计算公式为:
如果 (Δ=Max−Min= 0),则 ( S = 0 )。
7.4 色相 ( H )
色相的计算公式分为三种情况:
如果 ( R ) 是最大值:
如果 ( G ) 是最大值:
如果 ( B ) 是最大值:
7.5 特殊情况
如果 ( \Delta = 0 ):
3.2.2Verilog Design 代码分析
该模块为 RGB 转 HSV 模块,其中内嵌了一个手写的除法器模块,divide 模块,当然读者也可以自己调用一个
除法器的 IP 去进行运算,在代码中的 Description 中详细说明的算法的流程以及化简的过程。
`timescale 1ns / 1ps
module RGB2HSV (
input
I_clk,
input
I_rst_n,
input
I_tlast,
input
I_tuser,
第 36页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
input
I_tdata,
[23:0]
input
I_tvalid,
output
I_tready,
output
O_tlast,
output
O_tuser,
output
Image processing course advanced(2024)
O_tdata,
[23:0]
output
O_tvalid,
input
O_tready
);
/*****************************************************************
Signal Declarations
*****************************************************************/
reg
[11:0]
I_tlast_r
;
reg
[11:0]
I_tuser_r
;
reg
[11:0]
I_tvalid_r
;
wire
[7:0]
red_in, green_in, blue_in;
assign {red_in, green_in, blue_in} = I_tdata;
reg
[7:0]
rgb_min, rgb_max;
reg
[8:0]
delta_ext;
reg
[1:0]
rgb_max_color;
reg
[7:0]
red_reg, green_reg, blue_reg;
wire
[7:0]
delta_rgb;
reg
[15:0]
delta_times_255;
reg
[15:0]
delta_times_6;
reg
[7:0]
rgb_max_reg;
wire
[10:0]
hue_temp;
reg
[23:0]
hue_numerator;
reg
[8*10-1:0]
rgb_max_shift_reg;
s_div_valid;
wire
wire
sat;
[7:0]
h_div_valid;
wire
wire
[7:0]
hue;
wire
[7:0]
val;
/*****************************************************************
Computation Logic
*****************************************************************/
// Stage 1: Compute min and max of R, G, B, and determine dominant color
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
rgb_min <= 8'd0;
rgb_max <= 8'd0;
第 37页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
delta_ext <= 9'd0;
rgb_max_color <= 2'd0;
{red_reg, green_reg, blue_reg} <= 24'd0;
end else if (I_tvalid) begin
// Compute minimum of R, G, B
rgb_min <= (red_in < green_in) ? ((red_in < blue_in) ? red_in : blue_in) : ((green_in
< blue_in) ? green_in : blue_in);
// Compute maximum of R, G, B and identify dominant color
if ((red_in > green_in) && (red_in > blue_in)) begin
rgb_max <= red_in;
rgb_max_color <= 2'd0; // Red is dominant
delta_ext <= (green_in > blue_in)?{1'b0, green_in} - {1'b0, blue_in}:0;
end else if ((green_in > red_in) && (green_in > blue_in)) begin
rgb_max <= green_in;
rgb_max_color <= 2'd1; // Green is dominant
delta_ext <= {1'b0, blue_in} - {1'b0, red_in};
end else begin
rgb_max <= blue_in;
rgb_max_color <= 2'd2; // Blue is dominant
delta_ext <= {1'b0, red_in} - {1'b0, green_in};
end
// Register inputs for next stages
{red_reg, green_reg, blue_reg} <= {red_in, green_in, blue_in};
end
end
// Compute delta between max and min RGB values
assign delta_rgb = rgb_max - rgb_min;
// Compute temporary hue value based on dominant color
assign hue_temp = (rgb_max_color == 2'd0) ? {2'b00, delta_ext} :
(rgb_max_color == 2'd1) ? ({delta_rgb, 1'b0}
+ {{2{delta_ext[8]}},
delta_ext}):
({delta_rgb, 2'b00} + {{2{delta_ext[8]}},
delta_ext});
// Stage 2: Compute intermediate values for S and H calculations
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
delta_times_255 <= 16'd0;
delta_times_6 <= 16'd0;
hue_numerator <= 24'd0;
rgb_max_reg <= 8'd0;
end else if (I_tvalid_r[0]) begin
delta_times_255 <= {delta_rgb, 8'b0} - delta_rgb;
delta_times_6
<= {delta_rgb, 2'b0} + {delta_rgb , 1'b0};
hue_numerator
<= (delta_rgb == 8'd0 || hue_temp[10]) ? 24'd0 : {hue_temp, 8'b0} 第 38页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
hue_temp;
end
rgb_max_reg <= rgb_max;
end
// Shift register to synchronize rgb_max over multiple cycles
always @(posedge I_clk) begin
rgb_max_shift_reg <= {rgb_max_shift_reg, rgb_max_reg};
end
// Instantiate dividers for Saturation and Hue calculations
wire [23:0] s_div_result;
wire [39:0] h_div_result;
div_gen_hsv div_gen_sat_inst (
.aclk(I_clk),
.s_axis_divisor_tvalid(I_tvalid_r[1]),
.s_axis_divisor_tdata(rgb_max_reg),
.s_axis_dividend_tvalid(s_div_valid),
.s_axis_dividend_tdata(delta_times_255),
.m_axis_dout_tvalid(),
.m_axis_dout_tdata(s_div_result)
);
div_gen_hsv_r0 div_gen_hue_inst (
.aclk(I_clk),
.s_axis_divisor_tvalid(I_tvalid_r[1]),
.s_axis_divisor_tdata(delta_times_6),
.s_axis_dividend_tvalid(h_div_valid),
.s_axis_dividend_tdata(hue_numerator),
.m_axis_dout_tvalid(),
.m_axis_dout_tdata(h_div_result)
);
// Extract Saturation and Hue from divider outputs
assign sat = s_div_result[15:8];
assign hue = h_div_result[23:16];
assign val = rgb_max_shift_reg[8*10-1:8*9]; // Delayed version of rgb_max
/*****************************************************************
Signal Synchronization
*****************************************************************/
// Shift registers to synchronize control signals (tlast, tuser, tvalid)
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
I_tlast_r <= 12'd0;
I_tuser_r <= 12'd0;
I_tvalid_r <= 12'd0;
end else begin
第 39页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
I_tlast_r <= {I_tlast_r[10:0], I_tlast};
I_tuser_r <= {I_tuser_r[10:0], I_tuser};
I_tvalid_r <= {I_tvalid_r[10:0], I_tvalid};
end
end
// Assign outputs
assign O_tlast = I_tlast_r[11];
assign O_tuser = I_tuser_r[11];
assign O_tvalid = I_tvalid_r[11];
assign O_tdata = {hue, sat, val};
assign I_tready = O_tready;
endmodule
3.2.3 IP 调用之除法器
在上述模块中的除法,调用了两个除法器就进行除法运算.,下面会给具体配置内容:
除法器 1:
第 40页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
除法器 2:
第 41页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
3.3HSV 转 RGB
3.3.1HSV 转 RGB 原理分析
HSV 到 RGB 的转换步骤
假设我们有一个颜色在 HSV 空间中表示为 ( H )(色调,0 到 360 度),( S )(饱和度,0 到 1),和 ( V )(明度,
0 到 1)。转换到 RGB 的步骤如下:
计算色调的区间:
色调 ( H ) 被分成六个主区间,每个区间对应一种主要颜色过渡。这是因为色环可以被分成红、黄、绿、青、蓝、
紫六个部分。
计算色调所在的区间:
计算色调在当前区间的相对位置:
第 42页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
计算中间变量:
计算三个中间变量,用于确定 RGB 值:
根据色调区间计算 RGB:
根据色调的区间,选择相应的 RGB 值:
Region 0: 红色到黄色过渡
Region 1: 黄色到绿色过渡
Region 2: 绿色到青色过渡
Region 3: 青色到蓝色过渡
Region 4: 蓝色到紫色过渡
Region 5: 紫色到红色过渡
第 43页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
归一化并转换为整数:
将计算得到的 ( R, G, B ) 归一化到 0 到 255 的范围,并转换为整数:
3.3.2Verilog Design 代码分析
******************************HSV 杞琑 GB**************************************
//H, S and V_stage3 input range = 0
//R, G and B output range = 0
0 - 1
0 - 255
if ( S == 0 )
{
R = V_stage3 * 255
G = V_stage3 * 255
B = V_stage3 * 255
}
else
{
H_scaled = H * 6
if ( H_scaled == 6 ) H_scaled = 0
H_int_stage2 = int( H_scaled )
chroma1 = V_stage3 * ( 1 - S )
chroma2 = V_stage3 * ( 1 - S * ( H_scaled - H_int_stage2 ) )
chroma3 = V_stage3 * ( 1 - S * ( 1 - ( H_scaled - H_int_stage2 ) ) )
if
( H_int_stage2 == 0 ) { R_out = V_stage3
; G_out = chroma3 ; B_out = chroma1 }
else if ( H_int_stage2 == 1 ) { R_out = chroma2
; G_out = V_stage3; B_out = chroma1 }
else if ( H_int_stage2 == 2 ) { R_out = chroma1
; G_out = V_stage3; B_out = chroma3 }
else if ( H_int_stage2 == 3 ) { R_out = chroma1
; G_out = chroma2 ; B_out = V_stage3}
else if ( H_int_stage2 == 4 ) { R_out = chroma3
; G_out = chroma1 ; B_out = V_stage3}
else
{ R_out = V_stage3
R = R_out * 255
G = G_out * 255
B = B_out * 255
}
第 44页
; G_out = chroma1 ; B_out = chroma2 }
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
*****************************************************************/
`timescale 1ns / 1ps
module HSV2RGB (
input
I_clk,
input
I_rst_n,
input
I_tlast,
input
I_tuser,
input
[23:0]
I_tdata,
input
I_tvalid,
output
I_tready,
output
O_tlast,
output
O_tuser,
output
[23:0]
O_tdata,
output
O_tvalid,
input
O_tready
);
/*****************************************************************
Signal Declarations
*****************************************************************/
reg
[3:0]
I_tlast_r
;
reg
[3:0]
I_tuser_r
;
reg
[3:0]
I_tvalid_r
;
wire
[7:0]
H_in, S_in, V_in;
assign
{H_in, S_in, V_in} = I_tdata;
wire
[10:0]
H_scaled;
reg
[2:0]
H_int_part;
reg
[7:0]
H_frac_part;
reg
[7:0]
V_stage1;
reg
[15:0]
V_mul_S;
S_is_zero;
reg
reg
[23:0]
VS_mul_H_frac;
reg
[15:0]
V_mul_S_stage2;
reg
[7:0]
V_stage2;
reg
[2:0]
H_int_stage1;
S_zero_stage1;
reg
reg
[7:0]
chroma1, chroma2, chroma3;
reg
[2:0]
H_int_stage2;
reg
[7:0]
V_stage3;
S_zero_stage2;
reg
reg
[7:0]
R_out, G_out, B_out;
第 45页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
/*****************************************************************
Conversion Logic
*****************************************************************/
// Compute H_scaled = H_in * 6
assign H_scaled = (H_in == 8'd255) ? 11'd0 : ((H_in << 2) + (H_in << 1));
// Pipeline Stage 1: Compute integer and fractional parts of H, V_mul_S, and detect zero S
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
H_int_part <= 3'd0;
H_frac_part <= 8'd0;
V_mul_S <= 16'd0;
V_stage1 <= 8'd0;
S_is_zero <= 1'b0;
end else if (I_tvalid) begin
H_int_part <= H_scaled[10:8];
H_frac_part <= H_scaled[7:0];
V_mul_S <= V_in * S_in;
V_stage1 <= V_in;
S_is_zero <= (S_in == 8'd0);
end
end
// Pipeline Stage 2: Compute intermediate products and propagate signals
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
VS_mul_H_frac <= 24'd0;
V_mul_S_stage2 <= 16'd0;
V_stage2 <= 8'd0;
H_int_stage1 <= 3'd0;
S_zero_stage1 <= 1'b0;
end else if (I_tvalid_r[0]) begin
VS_mul_H_frac <= V_mul_S * H_frac_part;
V_mul_S_stage2 <= V_mul_S;
V_stage2 <= V_stage1;
H_int_stage1 <= H_int_part;
S_zero_stage1 <= S_is_zero;
end
end
// Pipeline Stage 3: Compute chroma components and propagate signals
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
chroma1 <= 8'd0;
chroma2 <= 8'd0;
chroma3 <= 8'd0;
H_int_stage2 <= 3'd0;
V_stage3 <= 8'd0;
第 46页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
S_zero_stage2 <= 1'b0;
end else if (I_tvalid_r[1]) begin
chroma1 <= V_stage2 - V_mul_S_stage2[15:8];
chroma2 <= V_stage2 - VS_mul_H_frac[23:16];
chroma3 <= V_stage2 - V_mul_S_stage2[15:8] + VS_mul_H_frac[23:16];
H_int_stage2 <= H_int_stage1;
V_stage3 <= V_stage2;
S_zero_stage2 <= S_zero_stage1;
end
end
// Pipeline Stage 4: Determine RGB outputs
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
{R_out, G_out, B_out} <= 24'd0;
end else if (I_tvalid_r[2]) begin
if (S_zero_stage2) begin
{R_out, G_out, B_out} <= {3{V_stage3}};
end else begin
case (H_int_stage2)
3'd0: begin R_out <= V_stage3; G_out <= chroma3;
B_out <= chroma1; end
3'd1: begin R_out <= chroma2;
G_out <= V_stage3; B_out <= chroma1; end
3'd2: begin R_out <= chroma1;
G_out <= V_stage3; B_out <= chroma3; end
3'd3: begin R_out <= chroma1;
G_out <= chroma2;
B_out <= V_stage3;end
3'd4: begin R_out <= chroma3;
G_out <= chroma1;
B_out <= V_stage3;end
default: begin R_out <= V_stage3; G_out <= chroma1;
B_out <= chroma2; end
endcase
end
end
end
/*****************************************************************
Signal Synchronization
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[2:0],I_tlast};
I_tuser_r <= {I_tuser_r[2:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[2:0],I_tvalid};
end
end
assign
O_tlast
= I_tlast_r[3];
assign
O_tuser
= I_tuser_r[3];
assign
O_tvalid = I_tvalid_r[3];
第 47页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
assign O_tdata = {R_out, G_out, B_out};
assign I_tready = O_tready;
endmodule
3.4 图片仿真
在 FPGA 图像处理基础课程中,对于一些图像处理类的 demo 可以先用图片仿真去进行检测,这样不仅能大幅
度减少我们设计的时间,也能让我们从中快速发现错误,详情请参考米联客的 FPGA 图像处理基础课程。
3.4.1Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
*****************************************************************/
// Define the image resolution here
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE_RGB "../../../../picture_bmp/out/output_rgb.bmp"
`define OUTPUT_IMAGE_HSV "../../../../picture_bmp/out/output_hsv.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
第 48页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 1
module image_simulation();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_rgb_fd, output_hsv_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer rgb_offset, hsv_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
第 49页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
// Signals for data validity and image data
wire data_valid;
wire [`COLOR_DEPTH*3-1:0] input_rgb_data;
wire hsv_data_valid;
wire [`COLOR_DEPTH*3-1:0] hsv_data;
wire output_data_valid;
wire [`COLOR_DEPTH*3-1:0] output_rgb_data;
I_tlast;
reg
wire
I_tuser;
reg
I_tready;
wire
O_tlast_hsv ;
wire
O_tuser_hsv ;
wire
O_tready_hsv;
wire
O_tlast ;
wire
O_tuser ;
wire
O_tready;
reg
de_r0;
reg
data_req;
reg
flag_req;
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_output_valid, prev_hsv_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_red, output_green, output_blue;
wire [`COLOR_DEPTH-1:0] output_h, output_s, output_v;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
第 50页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - 1));
#(CLOCK_PERIOD * 2);
// Adjust file lengths to be multiples of 4 bytes (BMP format requirement)
$fseek(output_rgb_fd, 0, `SEEK_END);
$fseek(output_hsv_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_rgb_fd) % 4;
if (padding_bytes != 0) begin
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_rgb_fd, "%c", 0);
$fwrite(output_hsv_fd, "%c", 0);
end
end
// Close all files
$fclose(output_rgb_fd);
$fclose(output_hsv_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
第 51页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end
// Open output files for writing
output_rgb_fd = $fopen(`OUTPUT_IMAGE_RGB, "wb");
output_hsv_fd = $fopen(`OUTPUT_IMAGE_HSV, "wb");
// Write BMP header to output files
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_rgb_fd, "%c", bmp_header[i]);
$fwrite(output_hsv_fd, "%c", bmp_header[i]);
end
// Set file offsets to the beginning of the image data
rgb_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
hsv_offset = rgb_offset;
$fseek(output_rgb_fd, rgb_offset, 0);
$fseek(output_hsv_fd, hsv_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
RGB2HSV RGB2HSV
(
/* input
*/.I_clk
/* input
*/.I_rst_n (I_rst_n),
/* input
*/.I_tlast (I_tlast),
/* input
*/.I_tuser (I_tuser),
/* input
[23:0]
(I_clk),
*/.I_tdata (input_rgb_data),
/* input
*/.I_tvalid(data_valid),
/* output
*/.I_tready(O_tready_hsv),
/* output
*/.O_tlast (O_tlast_hsv),
/* output
*/.O_tuser (O_tuser_hsv),
/* output [23:0]
*/.O_tdata (hsv_data),
/* output
*/.O_tvalid(hsv_data_valid),
/* input
*/.O_tready(I_tready)
);
// Instantiate the HSV to RGB conversion module
HSV2RGB HSV2RGB
(
/* input
*/.I_clk
/* input
*/.I_rst_n (I_rst_n),
(I_clk),
第 52页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
/* input
*/.I_tlast (O_tlast_hsv),
/* input
*/.I_tuser (O_tuser_hsv),
/* input
[23:0]
Image processing course advanced(2024)
*/.I_tdata (hsv_data),
/* input
*/.I_tvalid(hsv_data_valid),
/* output
*/.I_tready(O_tready),
/* output
*/.O_tlast (O_tlast ),
/* output
*/.O_tuser (O_tuser ),
/* output [23:0]
*/.O_tdata (output_rgb_data),
/* output
*/.O_tvalid(output_data_valid),
/* input
*/.O_tready(O_tready_hsv)
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
// I_tuser <= 1'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
第 53页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1) ;
// Assemble input RGB data from individual color channels
assign input_rgb_data = {red_channel[memory_address], green_channel[memory_address],
blue_channel[memory_address]};
// Extract individual color components from output data
assign {output_h, output_s, output_v} = hsv_data;
assign {output_red, output_green, output_blue} = output_rgb_data;
// Write output data to files
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_output_valid <= 0;
prev_hsv_valid <= 0;
end else begin
prev_output_valid <= output_data_valid;
prev_hsv_valid <= hsv_data_valid;
// If HSV data is valid, write to HSV output files
if (hsv_data_valid) begin
$fwrite(output_hsv_fd, "%c", output_h);
$fwrite(output_hsv_fd, "%c", output_s);
$fwrite(output_hsv_fd, "%c", output_v);
end else if (prev_hsv_valid) begin
第 54页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
// Move file pointer to the previous line for BMP format
hsv_offset = hsv_offset - `IMAGE_WIDTH * 3;
$fseek(output_hsv_fd, hsv_offset, 0);
end
// If RGB output data is valid, write to RGB output file
if (output_data_valid) begin
$fwrite(output_rgb_fd, "%c", output_blue);
$fwrite(output_rgb_fd, "%c", output_green);
$fwrite(output_rgb_fd, "%c", output_red);
output_pixel_counter <= output_pixel_counter + 1;
end else if (prev_output_valid) begin
// Move file pointer to the previous line for BMP format
rgb_offset = rgb_offset - `IMAGE_WIDTH * 3;
$fseek(output_rgb_fd, rgb_offset, 0);
end
end
end
endmodule
3.5 仿真结果
3.5.1 波形仿真结果
第 55页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
3.5.2 图片仿真结果
RGB 图:
HSV 图:
第 56页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
文档结果显示:
3.6Python 实现
3.6.1Python 代码
import cv2
# 1.读取图像
file_path = '001.bmp'
rgb_image = cv2.imread(file_path)
# 2.将 RGB 图像转换为 HSV 图像
第 57页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
hsv_image = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2HSV)
# 3.将 HSV 图像转为 RGB 图像
rgb_image_again = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2RGB)
# 4.建立窗口
#cv2.WINDOW_NORMAL: 值为 0,表示创建一个可调整大小的窗口。你可以手动调整窗口的大小。
#cv2.WINDOW_AUTOSIZE: 值为 1,表示创建一个自动调整大小的窗口,窗口的大小会根据显示的图像自动调整,无法
手动调整窗口大小。
#cv2.WINDOW_FULLSCREEN: 表示创建一个全屏窗口。
#cv2.WINDOW_FREERATIO: 表示窗口的宽高比可以自由调整。
#cv2.WINDOW_KEEPRATIO: 表示窗口的宽高比保持不变。
cv2.namedWindow("rgb",0)
cv2.resizeWindow("rgb",300,180)
cv2.namedWindow("hsv",0)
cv2.resizeWindow("hsv",300,180)
cv2.namedWindow("rgb_again",0)
cv2.resizeWindow("rgb_again",300,180)
# 5.图像显示
cv2.imshow('rgb',rgb_image)
cv2.imshow('hsv',hsv_image)
cv2.imshow('rgb_again',rgb_image_again)
# 6.设置窗口显示时间,单位为毫秒(这里设置为 100 秒,可以根据需要调整)
cv2.waitKey(10000000)
# 7.关闭所有窗口
cv2.destroyAllWindows()
3.6.2 结果显示
3.7 总结
FPGA 所用的 RGB 转 HSV,与 Python 实际略有差异,但是经过了 matlab 的验证,其所显示的图像与 verilog
代码所给图像较为相似,不同的算法,可能会有不同的差异,当然调用不同的软件的算法库也是如此。
第 58页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
RGB 转 HSV 之后能明显的看到色彩分明,在 HSV 色彩空间之中我们可以单独调整亮度和饱和度还有色调,颜
色的分割和检测通常比在 RGB 空间中更容易。通过将 RGB 转换为 HSV,图像处理算法可以更有效地操作和分析
颜色信息,这在许多应用中都能带来显著的优势,HSV 模型提供了一种更自然和直观的方式来处理颜色,使得许多
图像处理任务变得更加简单和高效。
第 59页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
4.FPGA 实现并行视频接口转 Stream 接口
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
4.1 并行视频接口和 Stream 接口简介
FPGA 图像处理中的并行视频接口是一种用于传输视频数据的接口,允许多路数据同时传输,从而提高数据传
输速度和处理效率,这种接口非常适合于需要高吞吐量的应用,如高清视频处理。
它有如下的一些常见端口信号:
视频数据总线(DATA):
多位并行数据线,传输视频像素数据。
行同步(HSYNC):
指示一行数据的开始。
场同步(VSYNC):
指示一帧数据的开始。
像素时钟(PCLK):
用于同步数据传输的时钟信号。
数据使能(Data Enable):
指示当前时刻数据是否有效。
Stream 接口通常用于在模块之间传输数据流,它的典型协议有两种,一种是 AXI-Stream,这是 ARM 公司定义
的一种先进的高性能流接口协议,广泛用于 FPGA 设计中,并且 AXI-Stream 支持高吞吐量和低延迟的数据传输。
另一种是 Avalon-ST,这是 Intel(Altera)定义的流接口协议,类似于 AXI-Stream,支持高效的数据流传输。
常见的信号包括:
(数据总线)TDATA:
传输像素数据。
(数据有效信号)TVALID:
指示 TDATA 上的数据是否有效。
(准备接收信号)TREADY:
指示下游模块是否准备好接收数据。
(行结束信号)TLAST:
指示数据流的结束。
(字节有效信号)TKEEP:
指示哪些字节在 TDATA 中有效。
(用户定义信号/帧起始信号)TUSER:
用于传递额外的信息。
因为很多时候可能在个别模块中用到的是并行视频接口,但是后续和其他的模块对接需要用到 Stream 接口,这
个时候就需要使用并行视频接口转 Stream 接口的模块去进行转接,使不同接口模块之间能够成功连接,并且运行,
此章节将会展示两种不同的并行视频接口去转换成 Stream 接口,它们的不同之处在于一个是行同步和场同步信
号,另外一个是行数据有效和场数据有效,读者在使用的时候可以根据自己的需求去进行调用。
第 60页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
4.2 代码分析(行数据有效和场数据有效)
4.2.1Verilog Design 代码分析
module Parallel2Stream (
input
I_clk ,
// 时钟信号
input
I_rst_n,
// 同步复位,高有效
// 并行视频接口输入
input
wire
I_vsync,
// 场同步信号(高电平有效)
input
wire
I_hsync,
// 行同步信号(高电平有效)
input
wire
I_de,
// 数据有效信号
input
wire [23:0] I_rgb_data,
// RGB888 像素数据输入
// AXI-Stream 接口输出
input
I_tready,
wire
output wire [23:0] O_tdata,
// 准备好接收数据信号
// 数据总线
output wire
O_tvalid,
// 数据有效信号
output wire
O_tlast,
// 行末标志
output wire
O_tuser
// 帧起始标志
);
// 信号定义
reg
vsync_d, vsync_dd;
// vsync 延迟,用于检测上升沿
reg
hsync_d;
// hsync 延迟,用于检测下降沿
reg
de_d0,de_d1;
reg
de_r0,de_r1;
// de 延迟
reg [23:0] rgb_data_d0,rgb_data_d1;
reg
flag_start;
reg
frame_start_d0,frame_start_d1;
// 像素数据延迟
reg [12:0] cnt;
wire frame_start = (vsync_d == 1'b0) && (I_vsync == 1'b1); // vsync 上升沿检测
wire line_end
= (de_d0 == 1'b1) && (I_de == 1'b0); // hsync 下降沿检测
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
vsync_d
<= 1'b0;
vsync_dd
<= 1'b0;
end else begin
vsync_d
<= I_vsync;
vsync_dd
<= vsync_d;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
第 61页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
if(!I_rst_n) begin
frame_start_d0 <= 1'b0;
end else begin
frame_start_d0 <=(de_r0 == 1'b0) && (I_de == 1'b1) && (cnt == 0);
end
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
de_r0 <= 0;
end
else if(cnt == 0)begin
de_r0 <= I_de;
end
else if(cnt > 0)begin
de_r0 <= 0;
end
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
cnt <= 0;
end
else if(frame_start)
cnt <= 0;
else if(line_end)begin
cnt <= cnt + 1;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
frame_start_d1 <= 1'b0;
end
else begin
frame_start_d1 <= frame_start_d0;
end
end
assign O_tuser = frame_start_d1 ; // 帧起始标志
reg line_end_d;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
line_end_d <= 1'b0;
end else begin
line_end_d <= line_end;
end
end
第 62页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
assign O_tlast = line_end_d & I_tready; // 行末标志
// 数据有效和数据延迟,以对齐 tuser 和 tlast
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
de_d0
<= 'd0;
de_d1
<= 'd0;
rgb_data_d0 <= 'd0;
rgb_data_d1 <= 'd0;
end else if (I_tready) begin
de_d0
<= I_de;
de_d1
<= de_d0;
rgb_data_d0 <= I_rgb_data;
rgb_data_d1 <= rgb_data_d0;
end
end
// tvalid 和 tdata 生成
assign O_tvalid = de_d1;
assign O_tdata
= rgb_data_d1;
endmodule
4.2.2Verilog Simulation 代码分析
用计数器模拟数据输入,再模拟并行视频接口的信号输入。
module video_tb ();
reg I_clk = 1'b0;
reg I_rst_n;
parameter TIME = 2;
always
begin
#(TIME/2) I_clk = ~I_clk;
end
initial begin
I_rst_n = 1'b0;
#(TIME*10);
I_rst_n = 1'b1;
end
/*****************************************************************
macro definition
*****************************************************************/
第 63页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
`define pix_640_480
//`define pix_1280_720
`ifdef pix_640_480
`define H_SYNC
11'd96
//行同步
`define H_BACK
11'd48
//行显示后沿
`define H_DISP
11'd640
//行有效数据
`define H_FRONT
11'd16
//行显示前沿
`define H_TOTAL
11'd800
//行扫描周期
`define V_SYNC
11'd2
//场同步
`define V_BACK
11'd33
//场显示后沿
`define V_DISP
11'd480
//场有效数据
`define V_FRONT
11'd10
//场显示前沿
`define V_TOTAL
11'd525
//场扫描周期
`define H_SYNC
11'd40
//行同步
`define H_BACK
11'd220
//行显示后沿
`define H_DISP
11'd1280
//行有效数据
`define H_FRONT
11'd110
//行显示前沿
`define H_TOTAL
11'd1650
//行扫描周期
`define V_SYNC
11'd5
//场同步
`define V_BACK
11'd20
//场显示后沿
`define V_DISP
11'd720
//场有效数据
`define V_FRONT
11'd5
//场显示前沿
`define V_TOTAL
11'd750
//场扫描周期
`endif
`ifdef pix_1280_720
`endif
/*****************************************************************
instantiation
*****************************************************************/
wire
vsync
;
wire
hsync
;
wire
de
;
wire
[23:0]
rgb_data;
reg
[23:0]
rgb_cnt;
wire
[23:0]
tdata ;
wire
tvalid;
wire
tready;
wire
tlast ;
wire
tuser ;
Parallel2Stream Parallel2Stream(
/*input
*/ .I_clk
/*input
*/ .I_rst_n (I_rst_n),
(I_clk
),
// 时钟信号
// 同步复位,高有效
第 64页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
/*input wire
*/ .I_vsync
(vsync
),
// 场同步信号
/*input wire
*/ .I_hsync
(hsync
),
// 行同步信号
/*input wire
*/ .I_de
(de
),
// 数据有效信号
Image processing course advanced(2024)
/*input wire [23:0]*/ .I_rgb_data(rgb_data),
// RGB888 像素数据输入
/*output wire [23:0]*/ .O_tdata
(tdata ),
// 数据总线
/*output wire
*/ .O_tvalid
(tvalid),
// 数据有效信号
/*input wire
*/ .I_tready
(tready),
// 准备好接收数据信号
/*output wire
*/ .O_tlast
(tlast ),
// 行末标志
/*output wire
*/ .O_tuser
(tuser )
// 帧起始标志
);
/*****************************************************************
simulate
signal
*****************************************************************/
reg
de_r0;
reg
data_req;
reg
flag_de;
reg [12:0] h_cnt
;
reg [12:0] v_cnt
;
localparam h_total = `H_TOTAL - 1;
localparam v_total = `V_TOTAL - 1;
localparam count_image = (`H_DISP*`V_DISP) - 1;
rgb_data = rgb_cnt;
assign
initial begin
data_req = 1'b0;
#(TIME*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_de <= 0;
else
flag_de <= data_req;
end
//数据计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
rgb_cnt <= 'd0;
else if(rgb_cnt == count_image)
rgb_cnt <= 'b0;
else if(de)begin
rgb_cnt <= rgb_cnt + 1'b1;
end
end
//数据使能信号
第 65页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
//行计数器对像素时钟计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
h_cnt <= 'd0;
else if(de_r0)begin
if(h_cnt == h_total )
h_cnt <= 'd0;
else
h_cnt <= h_cnt + 1'b1;
end
end
//场计数器对行计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
v_cnt <= 'd0;
else if(de_r0)begin
if(h_cnt == h_total ) begin
if(v_cnt == v_total )
v_cnt <= 'd0;
else
v_cnt <= v_cnt + 1'b1;
end
end
end
assign hsync = (h_cnt < `H_SYNC) && (v_cnt < (`V_SYNC + `V_BACK + `V_DISP)) && (v_cnt > (`V_SYNC
+ `V_BACK - 1)) && (flag_de == 1) ;
assign de
= (h_cnt < (`H_SYNC + `H_BACK + `H_DISP)) && (h_cnt > (`H_SYNC + `H_BACK - 1)) && (v_cnt
< (`V_SYNC + `V_BACK + `V_DISP)) && (v_cnt > (`V_SYNC + `V_BACK - 1)) && (flag_de == 1);
assign vsync = (v_cnt < `V_SYNC) && (flag_de == 1);
assign tready= (v_cnt < (`V_SYNC + `V_BACK + `V_DISP)) && (v_cnt > (`V_SYNC + `V_BACK - 1)) && (flag_de
== 1);
endmodule
4.2.3 仿真结果
宏观观察:
第 66页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
Tuser 信号单独观察,可以发现该信号处于第一个数据,在该信号拉高的时刻,表示着这一帧的起始。
Tlast 信号单独观察,可以看见当 Tlast 信号拉高,代表着一行中最后一个数据的到来,它也是一行的结束信号的标
志。
第 67页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
4.3 代码分析(行数据有效和场数据有效)
4.3.1Verilog Design 代码分析
源代码如下:
module Parallel2Stream (
input
I_clk ,
// 时钟信号
input
I_rst_n,
// 同步复位,高有效
// 并行视频接口输入
input
wire
I_vs,
// 场数据有效信号(高电平有效)
input
wire
I_hs,
// 行数据有效信号(高电平有效)
input
wire
I_de,
input
wire [23:0] I_rgb_data,
// 数据有效信号
// RGB888 像素数据输入
// AXI-Stream 接口输出
input
I_tready,
wire
output wire [23:0]
O_tdata,
// 准备好接收数据信号
// 数据总线
output wire
O_tvalid,
// 数据有效信号
output wire
O_tlast,
// 行末标志
output wire
O_tuser
// 帧起始标志
);
// 信号定义
reg
vsync_d, vsync_dd;
// vsync 延迟,用于检测上升沿
reg
hsync_d;
// hsync 延迟,用于检测下降沿
reg
de_d0,de_d1;
// de 延迟
reg [23:0] rgb_data_d0,rgb_data_d1;
// 像素数据延迟
// tuser 生成:在帧的第一个有效像素时置高
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
vsync_d
<= 1'b0;
vsync_dd
<= 1'b0;
end else begin
vsync_d
<= I_vs;
vsync_dd
<= vsync_d;
end
end
wire frame_start = (vsync_d == 1'b1) && (vsync_dd == 1'b0); // vsync 上升沿检测
reg frame_start_d;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
frame_start_d <= 1'b0;
end else begin
第 68页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
frame_start_d <= frame_start;
end
end
assign O_tuser = frame_start_d & I_tready; // 帧起始标志
// tlast 生成:在每行的最后一个有效像素时置高
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
hsync_d <= 1'b0;
end else begin
hsync_d <= I_hs;
end
end
wire line_end = (hsync_d == 1'b1) && (I_hs == 1'b0); // hsync 下降沿检测
reg line_end_d;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
line_end_d <= 1'b0;
end else begin
line_end_d <= line_end;
end
end
assign O_tlast = line_end_d & I_tready; // 行末标志
// 数据有效和数据延迟,以对齐 tuser 和 tlast
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
de_d0
<= 'd0;
de_d1
<= 'd0;
rgb_data_d0 <= 'd0;
rgb_data_d1 <= 'd0;
end else if (I_tready) begin
de_d0
<= I_de;
de_d1
<= de_d0;
rgb_data_d0 <= I_rgb_data;
rgb_data_d1 <= rgb_data_d0;
end
end
// tvalid 和 tdata 生成
assign O_tvalid = de_d1;
assign O_tdata
= rgb_data_d1;
endmodule
第 69页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
4.3.2Verilog Simulation 代码分析
用计数器模拟数据输入,再模拟并行视频接口的信号输入。
module video_tb ();
reg I_clk = 1'b0;
reg I_rst_n;
parameter TIME = 2;
always
begin
#(TIME/2) I_clk = ~I_clk;
end
initial begin
I_rst_n = 1'b0;
#(TIME*10);
I_rst_n = 1'b1;
end
/*****************************************************************
macro definition
*****************************************************************/
`define pix_640_480
//`define pix_1280_720
`ifdef pix_640_480
`define H_SYNC
11'd96
//行同步
`define H_BACK
11'd48
//行显示后沿
`define H_DISP
11'd640
//行有效数据
`define H_FRONT
11'd16
//行显示前沿
`define H_TOTAL
11'd800
//行扫描周期
`define V_SYNC
11'd2
//场同步
`define V_BACK
11'd33
//场显示后沿
`define V_DISP
11'd480
//场有效数据
`define V_FRONT
11'd10
//场显示前沿
`define V_TOTAL
11'd525
//场扫描周期
`define H_SYNC
11'd40
//行同步
`define H_BACK
11'd220
//行显示后沿
`endif
`ifdef pix_1280_720
`define H_DISP
11'd1280
//行有效数据
`define H_FRONT
11'd110
//行显示前沿
`define H_TOTAL
11'd1650
//行扫描周期
`define V_SYNC
11'd5
//场同步
`define V_BACK
11'd20
//场显示后沿
第 70页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
`define V_DISP
11'd720
//场有效数据
`define V_FRONT
11'd5
//场显示前沿
`define V_TOTAL
11'd750
//场扫描周期
Image processing course advanced(2024)
`endif
/*****************************************************************
instantiation
*****************************************************************/
wire
I_vs;
wire
I_hs
;
de
;
wire
wire
[23:0]
rgb_data;
reg
[23:0]
rgb_cnt;
wire
[23:0]
tdata ;
wire
tvalid;
wire
tready;
wire
tlast ;
wire
tuser ;
Parallel2Stream Parallel2Stream(
/*input
*/ .I_clk
/*input
*/ .I_rst_n (I_rst_n),
/*input wire
*/ .I_vs
(I_vs),
/*input wire
*/ .I_hs
(I_hs
/*input wire
*/ .I_de
(de
(I_clk
// 时钟信号
),
// 同步复位,高有效
// 场同步信号
// 行同步信号
),
// 数据有效信号
),
/*input wire [23:0]*/ .I_rgb_data(rgb_data),
// RGB888 像素数据输入
/*output wire [23:0]*/ .O_tdata
(tdata ),
// 数据总线
/*output wire
*/ .O_tvalid
(tvalid),
// 数据有效信号
/*input wire
*/ .I_tready
(tready),
// 准备好接收数据信号
/*output wire
*/ .O_tlast
(tlast ),
// 行末标志
/*output wire
*/ .O_tuser
(tuser )
// 帧起始标志
);
/*****************************************************************
simulate
signal
*****************************************************************/
reg
de_r0;
reg
data_req;
reg
flag_de;
reg [12:0] h_cnt
;
reg [12:0] v_cnt
;
localparam h_total = `H_TOTAL - 1;
localparam v_total = `V_TOTAL - 1;
localparam count_image = (`H_DISP*`V_DISP) - 1;
assign
rgb_data = rgb_cnt;
initial begin
data_req = 1'b0;
#(TIME*30);
data_req = 1'b1;
end
第 71页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_de <= 0;
else
flag_de <= data_req;
end
//数据计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
rgb_cnt <= 'd0;
else if(rgb_cnt == count_image)
rgb_cnt <= 'b0;
else if(de)begin
rgb_cnt <= rgb_cnt + 1'b1;
end
end
//数据使能信号
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
//行计数器对像素时钟计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
h_cnt <= 'd0;
else if(de_r0)begin
if(h_cnt == h_total )
h_cnt <= 'd0;
else
h_cnt <= h_cnt + 1'b1;
end
end
//场计数器对行计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
v_cnt <= 'd0;
else if(de_r0)begin
if(h_cnt == h_total ) begin
if(v_cnt == v_total )
v_cnt <= 'd0;
else
v_cnt <= v_cnt + 1'b1;
end
end
end
第 72页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
assign I_hs
Image processing course advanced(2024)
= (h_cnt < (`H_SYNC + `H_BACK + `H_DISP)) && (h_cnt > (`H_SYNC + `H_BACK - 1)) && (v_cnt
< (`V_SYNC + `V_BACK + `V_DISP)) && (v_cnt > (`V_SYNC + `V_BACK - 1)) && (flag_de == 1);
assign de
= I_hs
;
assign I_vs= (v_cnt < (`V_SYNC + `V_BACK + `V_DISP)) && (v_cnt > (`V_SYNC + `V_BACK - 1)) && (flag_de
== 1);
assign tready= I_vs;
endmodule
4.3.3 仿真结果
仿真的结果如下图所示,上面显示了 Stream 接口传输的 5 个特定端口信号,它们也按照了一定的规范去进行传输。
宏观观察:
Tuser 信号单独观察,可以发现该信号处于第一个数据,在该信号拉高的时刻,表示着这一帧的起始。
第 73页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
Tlast 信号单独观察,可以看见当 Tlast 信号拉高,代表着一行中最后一个数据的到来,它也是一行的结束信号的标
志。
第 74页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
5.FPGA 实现 Stream 接口转并行视频接口
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
5.1 并行视频接口和 Stream 接口简介
FPGA 图像处理中的并行视频接口是一种用于传输视频数据的接口,允许多路数据同时传输,从而提高数据传
输速度和处理效率,这种接口非常适合于需要高吞吐量的应用,如高清视频处理。
它有如下的一些常见端口信号:
视频数据总线(DATA):
多位并行数据线,传输视频像素数据。
行同步(HSYNC):
指示一行数据的开始。
场同步(VSYNC):
指示一帧数据的开始。
像素时钟(PCLK):
用于同步数据传输的时钟信号。
数据使能(Data Enable):
指示当前时刻数据是否有效。
Stream 接口通常用于在模块之间传输数据流,它的典型协议有两种,一种是 AXI-Stream,这是 ARM 公司定义
的一种先进的高性能流接口协议,广泛用于 FPGA 设计中,并且 AXI-Stream 支持高吞吐量和低延迟的数据传输。
另一种是 Avalon-ST,这是 Intel(Altera)定义的流接口协议,类似于 AXI-Stream,支持高效的数据流传输。
常见的信号包括:
(数据总线)TDATA:
传输像素数据。
(数据有效信号)TVALID:
指示 TDATA 上的数据是否有效。
(准备接收信号)TREADY:
指示下游模块是否准备好接收数据。
(行结束信号)TLAST:
指示数据流的结束。
(字节有效信号)TKEEP:
指示哪些字节在 TDATA 中有效。
(用户定义信号/帧起始信号)TUSER:
用于传递额外的信息。
因为很多时候可能在个别模块中用到的是 Stream 接口,但是后续和其他的模块对接需要用到并行视频接口,这
个时候就需要使用 Stream 接口转并行视频接口的模块去进行转接,使不同接口模块之间能够成功连接,并且运行。
此章节只给出了并行视频数据的行场的数据有效信号,若读者想把其转换为行场同步信号,只需把行同步改为,
检测数据有效信号的上升沿检测即可,把场同步直接默认为 Tuser 信号,然后注意一下信号同步即可。
第 75页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
5.2 代码分析
5.2.1Verilog Design 代码分析
源代码如下:
`timescale 1ns/1ns
module Stream2Parallel #(
parameter WIDTH = 640,
parameter HEIGHT = 480
)
(
input
I_clk ,
// 时钟信号
input
I_rst_n,
// 同步复位,低有效
// AXI-Stream 接口输入
input
wire [23:0] I_tdata,
// 数据总线
input
wire
I_tvalid,
// 数据有效信号
output wire
I_tready,
// 准备好接收数据信号
input
wire
I_tlast,
// 行末标志
input
wire
I_tuser,
// 帧起始标志
output reg
O_vs,
// 场数据有效信号
output reg
O_hs,
// 行数据有效信号
output reg
O_de,
// 数据有效信号
output reg [23:0]
O_rgb_data
// RGB888 像素数据输出
// 并行视频接口输出
);
// tready 始终为高,表示随时可以接收数据
assign I_tready = 1'b1;
reg
[12:0] V_cnt;
// 数据有效信号和像素数据输出
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
O_de
<= 1'b0;
O_hs
<= 1'b0;
O_rgb_data <= 24'd0;
end else begin
O_de
<= I_tvalid;
O_hs
<= I_tvalid;
O_rgb_data <= I_tdata;
end
end
// vsync 生成:当检测到 I_tuser 高电平时,产生 vsync 上升沿
第 76页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
O_vs
<= 1'b0;
end
else if(V_cnt == HEIGHT)begin
O_vs <= 0;
end
else if(I_tuser)begin
O_vs <= 1;
end
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
V_cnt <= 0;
end
else if(I_tuser || (V_cnt == HEIGHT ))begin
V_cnt <= 0;
end
else if(I_tlast)begin
V_cnt <= V_cnt + 1;
end
end
endmodule
5.2.2Verilog Simulation 代码分析
由于提前使用 matlab 计算好了 log 系数,这里代码很简单直接查表就行。
module video_tb ();
reg I_clk = 1'b0;
reg I_rst_n;
parameter TIME = 2;
always
begin
#(TIME/2) I_clk = ~I_clk;
end
initial begin
I_rst_n = 1'b0;
#(TIME*10);
I_rst_n = 1'b1;
end
/*****************************************************************
macro definition
第 77页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
*****************************************************************/
`define pix_640_480
//`define pix_1920_1080
//`define pix_1280_720
`ifdef pix_1920_1080
`define IMG_WIDTH 1920
//Image width
`define IMG_HEIGHT
//Image height
1080
`define H_BLANK 720 //行消隐,仿真可自由设置
`define V_BLANK 45
//场消隐,仿真可自由设置
`endif
`ifdef pix_1280_720
`define IMG_WIDTH 1280
//Image width
`define IMG_HEIGHT
//Image height
720
`define H_BLANK 480
//行消隐,仿真可自由设置
`define V_BLANK 30
//场消隐,仿真可自由设置
`endif
`ifdef pix_640_480
`define IMG_WIDTH 640
//Image width
`define IMG_HEIGHT
//Image height
480
`define H_BLANK 200
//行消隐,仿真可自由设置
`define V_BLANK 30
//场消隐,仿真可自由设置
`endif
/*****************************************************************
instantiation
*****************************************************************/
I_tdata
;
reg
I_tvalid
;
wire
I_tready
;
wire
I_tlast
;
wire
I_tuser
;
wire
O_vs
;
wire
O_hs
;
wire
O_de
;
reg
[23:0]
wire
[23:0]
O_rgb_data;
Stream2Parallel #(
/*parameter */.WIDTH (640),
/*parameter */.HEIGHT(480)
)Stream2Parallel(
/*input
*/.I_clk
(I_clk
// 时钟信号
/*input
*/.I_rst_n
(I_rst_n),
/*input wire [23:0] */.I_tdata
(I_tdata
),
// 数据总线
/*input wire
*/.I_tvalid
(I_tvalid
),
// 数据有效信号
/*output wire
*/.I_tready
(I_tready ),
),
// 同步复位,低有效
第 78页
// 准备好接收数据信号
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
/*input wire
*/.I_tlast
(I_tlast
),
// 行末标志
/*input wire
*/.I_tuser
(I_tuser
),
// 帧起始标志
/*output reg
*/.O_vs
(O_vs
),
// 场数据有效信号
/*output reg
*/.O_hs
(O_hs
),
// 行数据有效信号
/*output reg
*/.O_de
(O_de
),
// 数据有效信号
/*output reg [23:0] */.O_rgb_data(O_rgb_data)
// RGB888 像素数据输出
);
/*****************************************************************
simulate
signal
*****************************************************************/
reg
de_r0;
reg
data_req;
reg
flag_de;
reg [12:0] h_cnt
;
reg [12:0] v_cnt
;
wire
HS;
wire
VS;
reg
VS_d0;
reg
HS_d0;
wire
I_tvalid_d0;
reg [23:0] rgb_cnt;
VS_d1;
reg
localparam h_total = `H_BLANK + `IMG_WIDTH;
localparam v_total = `V_BLANK + `IMG_HEIGHT;
localparam count_image = (`IMG_WIDTH*`IMG_HEIGHT) - 1;
initial begin
data_req = 1'b0;
#(TIME*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_de <= 0;
else
flag_de <= data_req;
end
//数据计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
rgb_cnt <= 'd0;
else if(rgb_cnt == count_image)
rgb_cnt <= 'b0;
else if(I_tvalid_d0)begin
rgb_cnt <= rgb_cnt + 1'b1;
end
end
第 79页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
I_tdata <= 'd0;
else begin
I_tdata <= rgb_cnt;
end
end
//数据使能信号
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
//行计数器对像素时钟计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
h_cnt <= 'd0;
else if(de_r0)begin
if(h_cnt == h_total - 1'b1)
h_cnt <= 'd0;
else
h_cnt <= h_cnt + 1'b1;
end
end
//场计数器对行计数
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
v_cnt <= 'd0;
else if(de_r0)begin
if(h_cnt == h_total - 1'b1) begin
if(v_cnt == v_total - 1'b1)
v_cnt <= 'd0;
else
v_cnt <= v_cnt + 1'b1;
end
end
end
assign HS = (h_cnt < `IMG_WIDTH) && (v_cnt < `IMG_HEIGHT) && (flag_de == 1);
assign I_tvalid_d0 = (h_cnt < `IMG_WIDTH) && (v_cnt < `IMG_HEIGHT) && (flag_de == 1);
assign VS = (v_cnt < `IMG_HEIGHT) && (flag_de == 1);
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
begin
VS_d0 <= 1'b0;
第 80页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
VS_d1 <= 1'b0;
end
else begin
VS_d0 <= VS;
VS_d1 <= VS_d0;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
HS_d0 <= 1'b0;
else
HS_d0 <= HS;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
I_tvalid <= 1'b0;
else
I_tvalid <= I_tvalid_d0;
end
assign I_tuser = (VS_d0 == 1'b1) && (VS_d1 == 1'b0);//上升沿检测
assign I_tlast = (HS_d0 == 1'b1) && (HS == 1'b0);//下降沿检测
endmodule
5.2.3 仿真结果
第 81页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 82页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
6.FPGA 实现行缓存设计(矩阵形成)
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
6.1 简介
FPGA 实现行缓存设计,一般用于矩阵的形成以及一些算法计算,行缓存是 FPGA 图像处理中
的基础模块,其设计直接影响系统的性能和效率,其主要用于处理需要多行数据的操作,如卷积、滤
波、缩放等。
6.2 原理讲解
此次采用两次行缓存去实现 3x3 矩阵,其大致的原理框架如下图所示:
下一行
fifo_Line_buffer 1
当前行
数据输入
fifo_Line_buffer 2
上一行
首先需要调用官方的 IP——FIFO Generator ,当然也可以自己写一个同步 FIFO,这里只讲述
如何去调用这个官方 IP。
首先第一步选择默认的 Native,因为 Native 类型一般用于非 SOC 逻辑设计,其他两种用于 SOC
逻辑设计,所以选择 Native 类型,第二个选择单时钟块 RAM。
第 83页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
接下来选择 First word Fall Through ,这个表示 FIFO 在读取数据的时候会立马执行,而不是延
迟一个周期再执行,如果选择的是 Standard FIFO 模式,则 FIFO 在读取数据的时候会延迟一个周期
再进行读取,
图中 Data Port Parameters 处用于设置读写端口的数据总线的宽度以及 FIFO 的深度。从上到下
依次是写数据宽度、写数据深度、读数据宽度 、读数据深度。
Reset Pin 处为是否采用复位引脚。
Reset Type 处为是否为异步复位。
Full Flags Reset Value 处为复位时 Full Flags 的状态为 0 还是为 1。
Dout Reset Value 处为复位时 Dout 数据线的状态。
如果需要了解的更加详细的话,可以去 XILIINX 官网参考 FIFO IP 的具体配置详情,以及原理介
绍。
第 84页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
后面的默认不做改变。
在行缓存处理中有一些关键点,这里选择的是中间行作为当前行,那么则需要考虑上一行和下一行,则其关键处就
在于第一行和最后一行,对于第一行来说,上一行可以给其赋中间行的值,对于最后一行,下一行可以给其赋中间
行的值;当然如果选择下一行作为当前行,则需要考虑倒数第二行和倒数第一行,对于倒数第二行,上一行可以给
它赋中间行的值;对于最后一行,上一行和中间行,可以给它们赋下一行的值,读者可以结合上面的框架图去分析,
这样更加便于理解。
6.3 代码分析
6.3.1Verilog Design 代码分析
image_line_buffer 模块是用来对缓存的行数据进行加工处理的,以下是 image_line_buffer 模块的代
码。
`timescale 1ns / 1ps
module image_line_buffer#(
parameter IMG_WIDTH = 640 ,
parameter IMG_HEIGHT = 480
)(
input
I_clk
,
input
I_rst_n
,
input wire
I_valid
,
input wire [23:0] I_data
,
O_valid
,
output reg
output reg [23:0] O_data
第 85页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
);
genvar
i;
integer j;
valid_d0 [2:0];
wire [0:0]
wire [23:0] data_d0
[2:0];
reg [10:0]
h_cnt;
reg [9:0]
v_cnt;
reg
ch_valid;
reg [23:0]
ch_data [2:0];
assign valid_d0[0] = I_valid;
assign data_d0[0]
= I_data;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
for(j=0;j<3;j=j+1)
ch_data[j] <= 0;
end else if(valid_d0[1]) begin
ch_data[1] <= data_d0[1];
if(v_cnt == 0) begin
ch_data[2] <= data_d0[1];
ch_data[0] <= data_d0[0];
end else if(v_cnt == IMG_HEIGHT -1) begin
ch_data[2] <= data_d0[2];
ch_data[0] <= data_d0[1];
end else begin
ch_data[2] <= data_d0[2];
ch_data[0] <= data_d0[0];
end
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
ch_valid <= 0;
h_cnt <= 0;
v_cnt <= 0;
end else begin
ch_valid <= valid_d0[1];
h_cnt
<= valid_d0[1] ? ((h_cnt == IMG_WIDTH - 1) ? 0 : h_cnt + 1) : h_cnt;
v_cnt
<= valid_d0[1]&&(h_cnt == IMG_WIDTH - 1) ? ((v_cnt == IMG_HEIGHT - 1) ? 0 : v_cnt
+ 1) : v_cnt;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
第 86页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
O_valid <= 0;
O_data <= 0;
end else begin
O_valid <= ch_valid;
O_data <= ch_data[1];
end
end
reg [23:0] c11,c21,c31,c12,c22,c32,c13,c23,c33;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{c11,c12,c13,
c21,c22,c23,
c31,c32,c33} <= 0;
end
else begin
c13 <= ch_data[2];
c23 <= ch_data[1];
c33 <= ch_data[0];
c12 <= c13;
c22 <= c23;
c32 <= c33;
c11 <= c12;
c21 <= c22;
c31 <= c32;
end
end
//杈撳叆 data[0]鍜宒 ata[1]
杈撳嚭 data[1]鍜宒 ata[2]
generate for(i=1;i<3;i=i+1)
begin:two_line_buffer
line_buffer#(
.IMG_WIDTH (IMG_WIDTH ),
.IMG_HEIGHT(IMG_HEIGHT
)
) line_buffer_r0(
.I_clk
( I_clk
),
.I_rst_n
( I_rst_n
),
.I_valid
( valid_d0[i-1]),
.I_data
( data_d0[i-1] ),
.O_valid
( valid_d0[i]
),
.O_data
( data_d0[i]
)
);
end
endgenerate
endmodule
第 87页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
line_buffer 模块(行缓存模块),主要进行行缓存。
module line_buffer#(
parameter IMG_WIDTH = 640 ,
parameter IMG_HEIGHT = 480
)(
input
I_clk
input
I_rst_n,
,
input
wire
I_valid,
input
wire
[23:0] I_data ,
O_valid,
output wire
[23:0] O_data
output wire
);
function integer clog2b(
input integer depth
);
begin
for(clog2b=0; depth>0; clog2b=clog2b+1)begin
depth = depth >> 1;
end
end
endfunction
reg [clog2b(IMG_WIDTH)-1:0]
wr_data_cnt;
rd_en;
wire
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
wr_data_cnt <= 0;
end
else if(I_valid) begin
wr_data_cnt <= (wr_data_cnt < IMG_WIDTH) ? (wr_data_cnt + 1'b1) : wr_data_cnt;
end
end
assign rd_en = I_valid&&(wr_data_cnt == IMG_WIDTH) ? 1'b1 : 1'b0;
assign O_valid = rd_en;
fifo_line_buffer your_instance_name (
),
// input wire clk
.rst(!I_rst_n),
// input wire rst
.clk(I_clk
.din(I_data),
// input wire [23 : 0] din
.wr_en(I_valid),
// input wire wr_en
.rd_en(rd_en),
.dout(O_data),
// output wire [23 : 0] dout
// output wire full
.full (),
.empty()
// input wire rd_en
// output wire empty
);
endmodule
第 88页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
6.3.2Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
// Define the image resolution here
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
第 89页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 1
module image_simulation();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`COLOR_DEPTH*3-1:0] input_rgb_data;
wire line_data_valid;
wire [`COLOR_DEPTH*3-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
reg
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
第 90页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
flag_req;
reg
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 1;
O_tready = 1;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - 1));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd) % 4;
if (padding_bytes != 0) begin
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
end
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
第 91页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
第 92页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
image_line_buffer#(
.IMG_WIDTH
(`IMAGE_WIDTH ),
.IMG_HEIGHT (`IMAGE_HEIGHT )
)
image_line_buffer(
/*input
*/.I_clk (I_clk
/*input
*/.I_rst_n(I_rst_n),
),
/*input
wire
*/.I_valid(data_valid),
/*input
wire
[23:0] */.I_data (input_rgb_data),
/*output wire
*/.O_valid(line_data_valid),
/*output wire
[23:0] */.O_data (line_data)
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
第 93页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address], green_channel[memory_address],
blue_channel[memory_address]};
// Extract individual color components from output data
assign {output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If line data is valid, write to output file
if (line_data_valid && O_tready) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
output_pixel_counter <= output_pixel_counter + 1;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
第 94页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
6.4 仿真及结果
6.4.1 仿真波形图结果
从仿真图中可以看出,ch_data 信号的[0][1][2]构成了一个 3x3 的矩阵。
第 95页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
6.4.2 仿真图片结果
原图:
经过两次 FIFO 行缓存后的图:
可以发现经过两次行缓存之后形成的图片与原图一摸一样,说明此次的 FIFO 行缓存并没有出现
数据的丢失。
6.5 总结
此篇主要是运用 FIFO 去进行行缓存形成 3X3 的矩阵,若想形成 4x4 或者 5x5 的矩阵,只需要
更改 image_line_buffer 模块中的 N,再对边界条件进行处理即可。
第 96页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
7.FPGA 实现双线性插值算法
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
7.1 双线性插值法算法简介
双线性插值是一种用于二维空间中的插值方法,常用于图像处理、计算机图形学和数值分析中。它通过在已知
数据点之间进行内插来估算未知数据点的值。具体来说,双线性插值是在矩形网格的四个相邻点之间进行的插值。
双线性插值的基本思想是在已知的四个相邻像素(或者数据点)之间进行插值,以估算出在这四个点组成的矩
形内部任意一点的值。假设我们有一个二维的网格,其中每个格点都有一个已知的值,双线性插值用于估算这个网
格中某一点(非格点)的值。
此章节只介绍关于双线性插值算法的原理,后面两章会介绍其相关应用。
7.2 原理
双线性插值的基本思想是将二维插值问题分解为两次一维线性插值。假设我们有一个矩形网格,其四个顶点的
坐标分别为 ((x_1, y_1), (x_1, y_2), (x_2, y_1), (x_2, y_2)),对应的函数值为 (Q_{11}, Q_{12}, Q_{21}, Q_{22})。我
们希望在这个矩形内插值到点 ((x, y)) 的值 (Q(x, y))。
算法步骤:
水平插值
线性插值沿 x 方向:
第 97页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
首先对 ( x ) 方向进行线性插值,求出 ( y_1 ) 和 ( y_2 ) 对应的两条边上的插值:
垂直插值
线性插值沿 y 方向:
然后对 ( y ) 方向进行线性插值,求出插值点 ( (x, y) ) 的值:
上述就是双线性插值基本算法步骤,它有以下几个特性:
线性假设:双线性插值假设在小范围内,函数值在两个方向上都是线性变化的。
局部性:插值仅依赖于目标点周围的四个网格点,适合局部平滑的情况。
效率:计算相对简单,只需进行几次乘法和加法运算。
双线性插值广泛应用于图像缩放、变形、纹理映射等领域。在图像处理中,它用于在放大或缩小图像时平滑像
素值,以减少锯齿效应。尽管双线性插值比最近邻插值更复杂,但它能够提供更平滑的结果,是许多应用中的常用
选择。
7.3 模拟分析
以下会基于 Bayer 格式去对双线性插值进行详细的分析,以便读者能更好的理解。这里使用 Bayer 格式中的
BGGR 格式去分析。
首先我们要明白如何去看所用相机的 Bayer 格式是属于哪一种,我们把第一行一个数据做为第一个,第一行第
二个数据作为第二个,第二行第一个数据作为第三个,第二行第二个数据作为第四个,例如:
这个的就是 bayer 格式就是 RGGB,但是有的相机的数据是从左上角开始的,那么它的 Bayer 格式就应该是
GRBG,所以我们得注意,它的 Bayer 格式的确定是取决于它到底是从哪里开始的。
下图中贝尔格式为 BGGR 格式,观察图中规律不难得出规律:依照 BGGR 一直重复排列,因此想要计算对应
的 RGB 值,我们需要分清 BGGR 的位置,因为他们四个计算方法不一样,因此采用 bayer_xpos(列)和 bayer_ypos
(行)进行排列。当 bayer_xpos==0 和 bayer_ypos==0,代表需要计算的是 B 位置的 RGB;当 bayer_xpos==1 和
bayer_ypos==0,代表需要计算的是 B 右边位置 G 的 RGB;当 bayer_xpos==0 和 bayer_ypos==1,代表需要计算的是
B 下面位置 G 的 RGB;当 bayer_xpos==1 和 bayer_ypos==1,代表需要计算的是 R 位置的 RGB;
bayer_xpos==0 和 bayer_ypos==0
第 98页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
具体的,红色框图中 3x3 的算子用 0~9 进行位置编号(便于算法理解),当我们要计算红色框图中 B4 的 RGB
值时,方法如下:
R = (R0+R2+R6+R8)/4 ;
G = (G1+G3+G5+G7)/4;
B = (B4)
bayer_xpos==1 和 bayer_ypos==0
当我们要计算红色框图中 G4 的 RGB 值时,方法如下:
R = (R1+R7)/2 ;
G = G4
B = (B3+B5)/2
bayer_xpos==0 和 bayer_ypos==1
当我们要计算红色框图中 G4 的 RGB 值时,方法如下:
R = (R3+R5)/2 ;
G = G4
B = (B1+B7)/2
bayer_xpos==1 和 bayer_ypos==1
第 99页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
当我们要计算红色框图中 R4 的 RGB 值时,方法如下:
R = R4
G = (G1+G3+G5+G7)/4
B = (B0+B2+B6+B8)/4
若是用的 Bayer 格式是其他的,则更改 bayer_xpos 和 bayer_ypos 即可。
第 100页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
8.FPGA 实现 Bayer 格式原始图像去马赛克处理
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
8.1 简介
去马赛克(Demosaicing)算法是一种用于从拜耳滤色器阵列(Bayer Filter Array)生成全彩色图像的技术。在
大多数数字相机中,图像传感器覆盖有拜耳滤色器阵列,这种滤色器阵列以红、绿、蓝三色滤色器的特定模式排列,
使得每个像素只能记录其中一种颜色。因此,传感器输出的原始图像数据称为拜耳图像,它只包含单色信息。去马
赛克算法的任务就是将这些单色信息转换成完整的 RGB 彩色图像,下面将详细的介绍它的情况。
拜耳滤色器阵列:
拜耳滤色器阵列通常以 2x2 的重复模式排列,其中包含两个绿色、一个红色和一个蓝色滤色器。这种设计是基
于人眼对绿色更为敏感,因此绿色滤色器的数量较多,它的格式大致分为四种,如下图所示,分别是 GBRG、BGGR、
GRBG、RGGB。
去马赛克算法的目标:
去马赛克算法的主要目标是利用周围像素的信息来估算每个像素的完整 RGB 值,以生成视觉上自然和细节丰
富的彩色图像。
常见去马赛克算法:
最邻近插值(Nearest Neighbor Interpolation):
这种方法简单快速,但结果图像的质量较差,容易出现色块和伪影。它仅仅是将每个缺失的颜色分量用相邻像
素的已知颜色分量填充。
双线性插值(Bilinear Interpolation):
使用线性插值方法来估算缺失的颜色分量,计算效率高。
高质量线性插值(High-Quality Linear Interpolation):
第 101页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
在双线性插值的基础上加入更多的颜色信息和方向信息,以提高图像的质量。
自适应插值(Adaptive Interpolation):
根据图像的局部特性(如边缘方向)来调整插值策略,以减少伪影和提升边缘细节。
频域方法:
利用傅里叶变换等频域分析技术来处理图像,通常能有效地减少伪影和锯齿现象,但计算复杂度较高。
深度学习方法:
近年来,基于卷积神经网络(CNN)的去马赛克方法展现出优异的性能,能够更好地保留图像细节和减少伪影。
不过本章所用的去马赛克算法为双线性插值算法。
8.2 去马赛克算法详述
此 demo 所使用的摄像头的 bayer 格式为 BGGR,所以就以 BGGR 格式为主来叙述,且采用的是一个时钟传输
四个像素数据,这种方式可以在一个时钟周期内传输更多的数据,因此总的数据吞吐量更高。适合高分辨率和高帧
率的应用,因为它能更有效地利用总线带宽,并且达到一个超低延迟的效果。
8.2.1 主要 IP
详细分析:
输入和输出信号:
AXI4-Stream Video Interface:
axi4s_video_tdest[9:0]: 数据流目的地标识符,用于多流处理。
axi4s_video_tdata[39:0]: 视频数据通道,包含像素数据,因为 MIPI 端选择的是 ROW10,且一个时钟传输 4 个 RGB,
所以这边接收到的数据是一个 40 位的数据。
axi4s_video_tlast: 行结束信号,指示当前行的最后一个像素。
axi4s_video_tuser: 用户信号,通常用于帧同步。
axi4s_video_tvalid: 数据有效信号,指示当前数据有效。
axi4s_video_tready: 准备接收信号,指示模块可以接收数据。
第 102页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
时钟和复位信号:
I_clk: AXI4-Stream 接口的时钟信号。
I_rst_n: AXI4-Stream 接口的异步复位信号,低电平有效。
输出信号:
bayer_ypos: 当前行的 Y 坐标,用于拜耳图像处理。
matrix_last_line[95:0]: 上一行的 3x3 矩阵数据。
matrix_cur_line[95:0]: 当前行的 3x3 矩阵数据。
matrix_next_line[95:0]: 下一行的 3x3 矩阵数据。
O_tlast: 行结束信号,指示当前行的最后一个像素。
O_tuser: 用户信号,通常用于帧同步。
O_tvalid: 数据有效信号,指示当前数据有效。
O_tready: 准备接收信号,指示下游模块可以接收数据。
功能描述
行缓存: 该模块实现了一个行缓存,这里使用了 BRAM IP 去进行一个行缓存,更加方便在其他的平台去进行部署,
并且在使用了 FIFO 时,也对 FIFO 的复位进行处理,增强视频的稳定性,用于存储当前行及其上下两行的数据。这
是实现 3x3 矩阵块处理的基础。
3x3 矩阵形成: 模块将输入的拜耳图像数据组织成 3x3 的矩阵块,输出三行的矩阵数据(上一行、当前行、下一行),
以便于进行后续的去马赛克算法。
同步与控制: 使用 AXI4-Stream 接口信号(tvalid、tready、tlast、tuser)来同步数据流和控制数据传输,确保数据的
正确性和完整性。
详细分析:
这个模块实现了使用双线性插值的去马赛克算法,它从 3x3 行缓存模块中接收数据,并输出去马赛克后的 RGB
图像数据输入信号,下面说说它的各个信号:
时钟和复位信号:
I_clk: 模块的输入时钟信号,用于同步内部逻辑。
I_rst_n: 模块的复位信号,低电平有效,用于初始化模块状态。
图像数据和控制信号:
bayer_ypos: 当前行的 Y 坐标,用于处理拜耳图像的行信息。
matrix_last_line[95:0]: 上一行的 3x3 矩阵数据。
第 103页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
matrix_cur_line[95:0]: 当前行的 3x3 矩阵数据。
matrix_next_line[95:0]: 下一行的 3x3 矩阵数据。
matrix_valid: 矩阵数据有效信号,指示输入数据有效。
输出信号:
O_data[127:0]: 输出数据通道,包含去马赛克后的 RGB 像素数据。
O_tlast:行结束信号,指示当前行的最后一个像素。
O_tuser: 用户信号,通常用于帧同步。
O_tvalid: 数据有效信号,指示输出数据有效。
O_tready: 准备接收信号,指示下游模块可以接收数据。
功能描述
双线性插值:
使用 3x3 矩阵中的像素数据,通过双线性插值计算出每个像素的完整 RGB 值,双线性插值通过对相邻像素进行加
权平均来计算缺失的颜色分量。
数据同步与控制:
通过 matrix_valid 信号同步输入数据,并使用 AXI4-Stream 接口信号(如 TVALID、TREADY、TLAST、TUSER)
管理输出数据流,确保数据的正确传输和同步。
高效数据传输:
使用 ROW10 模式,一个时钟周期内传输 4 个像素数据,提高了数据吞吐量和处理效率,适合高分辨率和高帧率应
用。
8.2.2raw_matrix_3x3_buffer 模块
该模块总共分为三个模块,其具体的信号传输如下图的模块框图所示:
本框图实现的功能为:从 AXI Stream 数据流转换为 native 格式并进行图像处理的系统。输入数据以 AXI
Stream 格式传入,经过 axis2native 模块转换为 native 格式后,通过 异步 FIFO 实现时钟域的跨越,从 AXI 时
第 104页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
钟域切换到 native 时钟域。随后,数据依次进入 同步 FIFO01 和 同步 FIFO02 进行缓冲和同步。xpos_cnt 和
ypos_cnt 模块负责记录当前像素的 X、Y 位置,以跟踪图像的处理进度。接着,数据进入边界复制模块,处理图
像边缘的特殊情况,并通过 Matrix_3x3_buffer 生成 3x3 矩阵数据用于图像卷积或滤波等操作。输出信号包括图像
行数指示的 bayer_ypos、矩阵有效信号 Matrix_valid 以及矩阵的最后一行、当前行和下一行的数据,位宽为 96 位。
整个系统通过 FIFO 缓冲与边界处理模块的协作,实现高效的数据传输与图像处理。
边界复制
下面将详细讲述边界复制模块。
在图像处理过程中,常常需要对图像进行滤波操作,进行滤波操作需要使用算子模板,也可以称之为扫描窗模
板,一般有 3x3、 5x5、 7x7 等模板形式。本文重在阐述算子模板的概念及使用 verilog 来描述其产生过程。下面
咱们从图像上来认识算子模板如图所示,展示了一个宽度为 15 个像素,高度为 8 个像素的图片,每个白色方块
代表一个像素。
去马赛克算法采用 3x3 模板实现 4K 分辨率(一个时钟 4 个像素点)的去马赛克算法,由于一个时钟 4 个 R 像
素点,所以形成的 3x3 矩阵,其中的每一个小块是由 4 个像素点组成的,即实际上是形成了一个 3x12 的矩阵。如
图所示,灰色代表图像的边界,蓝色框表示 3x3 的模板,对整幅图像进行扫窗操作,在图之中标注了第一个和最后
一个模板扫描的操作位置。
我们从图中可以观察到边界一行的像素是无法进行运算的,这个也是扫窗的一个缺点,无法对边界进行处理,
而且随着算子的变大边界无法处理的像素也会变多。后面进行具体操作时,会提出一种补充处理的方法。如图所示,
对浅灰色的边界进行扩展,就是图中的深灰色部分内容,一般简单处理,有复制边界为零的,也可以将原来的边界
进行复制。
第 105页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
具体方法如下:
1.左上角
中心像素:左上角的中心像素是 0。
边界复制:对于没有邻居的部分,比如左上角的红色 0,它表示这个像素没有左上角的邻居,所以我们用
自己来填充。这就像前面提到的“边界复制”概念:如果某个方向没有像素,就复制最近的像素值来填补。
左边和上边都是空的,所以都用 0 来填充。
右边和下边有像素,所以 1 和 2 就是复制的邻居值。
2.右下角
中心像素:右下角的中心点是 3。
边界复制:与左上角类似,右下角的像素需要对右边和下边的边界进行填充。由于图像的右边和下边没有像素,
缺少的部分被复制相邻的像素值。
右边没有像素,用 1 和 3 来填补。
下边没有像素,也用 2 和 3 来填充。
右上角与左下角方法类似,这里不再叙述。
注:在对边界进行处理的时候,对于左右两个侧边,并不是用 4 个像素点去处理,而是用 1 个像素点去进行处理,
比如上图的第一个数据(左上角),正常情况下,根据边界复制法的规则,它的左侧的数据,应当也和它一样,也
就是也是 4 个像素点,但其实应当采用这 4 个像素点最左侧的第一个像素点即可。
8.2.3bilinear_interpolati 模块
bilinear_interpolation 内部功能框图:
第 106页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
该框图展示了一个完整的图像处理流程:从输入 Bayer 格式数据开始,经过双线性插值生成 RGB 数据,再
通过 AXI Stream 接口输出,整个过程包括数据格式转换和插值计算。
上一章已经讲述了双线性插值的算法流程,此处再次详述一下。
下图中贝尔格式为 BGGR 格式,观察图中规律不难得出规律:依照 BGGR 一直重复排列,因此想要计算对应
的 RGB 值,我们需要分清 BGGR 的位置,因为他们四个计算方法不一样,因此采用 bayer_xpos 和 bayer_ypos 进行
排列。当 bayer_xpos==0 和 bayer_ypos==0,代表需要计算的是 B 位置的 RGB;当 bayer_xpos==1 和 bayer_ypos==0,
代表需要计算的是 B 右边位置 G 的 RGB;当 bayer_xpos==0 和 bayer_ypos==1,代表需要计算的是 B 下面位置 G 的
RGB;当 bayer_xpos==1 和 bayer_ypos==1,代表需要计算的是 R 位置的 RGB;
bayer_xpos==0 和 bayer_ypos==0
具体的,红色框图中 3x3 的算子用 0~9 进行位置编号(便于算法理解),当我们要计算红色框图中 B4 的 RGB
值时,方法如下:
R = (R0+R2+R6+R8)/4 ;
G = (G1+G3+G5+G7)/4;
B = (B4)
bayer_xpos==1 和 bayer_ypos==0
第 107页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
当我们要计算红色框图中 G4 的 RGB 值时,方法如下:
R = (R1+R7)/2 ;
G = G4
B = (B3+B5)/2
bayer_xpos==0 和 bayer_ypos==1
当我们要计算红色框图中 G4 的 RGB 值时,方法如下:
R = (R3+R5)/2 ;
G = G4
B = (B1+B7)/2
bayer_xpos==1 和 bayer_ypos==1
当我们要计算红色框图中 R4 的 RGB 值时,方法如下:
R = R4
G = (G1+G3+G5+G7)/4
第 108页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
B = (B0+B2+B6+B8)/4
8.2.4 双线性插值算法(单个时钟传输四个像素点)
这里将着重讲述在如果一个时钟需要传输 4 个像素点的时候,如何去进行双线性插值算法。
当一个时钟传输一个像素点,这个时候进行算法运算,我们只需要一个 3x3 矩阵,便可以进行一个双线性插值
的算法计算,但是现在一个时钟传输四个像素点,所以我们需要 4 个 3x3 的矩阵来运算,再加上矩阵之间有相互重
叠之处,所以只需要一个 3x6 的矩阵即可,如上图中红色边框所画的矩阵,之所以选择中间的数据作为矩阵,是因
为中间的数据所包含的颜色数据最多也是最齐全的,边缘的数据通常可能会出现偏差或者不齐全的问题,下面详细
讲讲双线性插值算法。
此处还是以 BGGR 为例,且当前只会出现两种情况,上图显示的为第一种,下面将详细讲述这一种将如何计算。
我们将输入数据分为 A,B,C 三组,数据依次从 C,B,A 的流程进入。
以 B 为计算基准,B 中有数据(matrix_valid)时才计算。分别计算 G17,R18,G19,R20;
G17 位置的 RGB 为:
R=(R16+R18)/2
G=(G17)
B=(B5+B29)/2
R18 位置的 RGB 为:
R=(R18)
G=(G6+G17+G19+G30)/4
B=(B5+B6+B29+B31)/4
G19 位置的 RGB 为:
R=(R18+R20)/2
G=(G19)
B=(B31+B7)/2
R20 位置的 RGB 为:
R=(R20)
G=(G8+G19+G21+G32)/4
B=(B7+B9+B31+B33)/4
下面将讲述第二种情况:
第 109页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
我们将输入数据分为 A,B,C 三组,数据依次从 C,B,A 的流程进入。
以 B 为计算基准,B 中有数据(matrix_valid)时才计算。分别计算 B17,G18,B19,G20;
B17 位置的 RGB 为:
R=(R4+R6+R28+R30)/4
G=(G5+G16+G18+G29)/4
B=B17
G18 位置的 RGB 为:
R=(R6+R30)/2
G=G18
B=(B5+B6+B29+B31)/4
B19 位置的 RGB 为:
R=(R6+R8+R30+R32)/2
G=(G7+G18+G20+G31)/4
B=B19
G20 位置的 RGB 为:
R=(R8+R32)/2
G=G20
B=(B19+B21)/2
这个是就是 BGGR 格式的情况了,后续的其他三种 Bayer 格式以此类推即可得出。
8.3 相关 IP 调用详情
下面是整个工程的模块图:
第 110页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
8.3.1 去马赛克模块 IP 调用
raw_matrix_3x3_buffer 模块:
这个模块的 IP 调用只需要注意修改自己所需的分辨率即可
第 111页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
bilinear_interpolati 模块:
这个模块的调用,除了需要注意修改自己所需的分辨率,还需要注意更改 Bayer 格式,读者可以查看自己所用
摄像头的相关手册,里面会讲述它的 Bayer 格式。
第 112页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
8.3.2 其他 IP 调用
MIPI CSI-2 RX Subsystem IP:
第 113页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 114页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Processor System Reset 模块:
第 115页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Clocking Wizard 模块(clk_wiz_1)
第 116页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 117页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Clocking Wizard 模块(clk_wiz_2)
第 118页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 119页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Uifdma_dbuf_v4_0 模块:
第 120页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Video Timinig Controller 模块:
第 121页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 122页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
AXI4-Stream to Video Out 模块:
第 123页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
这几个都是较为重要的模块,当然工程中还有其他的几个模块,就没有再列举出来了,详情可以观看 FPGA 高
级图像处理篇的对应 demo。
8.4 代码分析
8.4.1 mipi_to_raw_converter 模块代码分析
该模块主要是用于接口转变和数据接收,且选择了 ROW10 数据的高 8 位接收,作为 RGB 的颜色数据,因为
高位所含的颜色信息更多。
`timescale 1ns/1ns
module mipi_to_raw_converter
(
input
I_clk
input
I_rst_n ,
,
input
[39:0]
I_raw_tdata ,
input
[ 9:0]
I_raw_tdest ,
input
I_raw_tlast ,
input
I_raw_tvalid,
第 124页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
input
I_raw_tuser ,
output
I_raw_tready,
Image processing course advanced(2024)
// 输出 RAW10 数据
output
O_raw_tdata ,
[31:0]
output
O_raw_tlast ,
output
O_raw_tvalid,
output
O_raw_tuser ,
input
O_raw_tready
);
reg
I_tlast_r0;
reg
I_tuser_r0;
reg
I_tvalid_r0;
reg
[31:0]
raw_data_r0;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
raw_data_r0 <= 0;
else if(I_raw_tvalid)begin
raw_data_r0 <= {I_raw_tdata[9:2], I_raw_tdata[19:12], I_raw_tdata[29:22],
I_raw_tdata[39:32]};
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{I_tlast_r0,I_tuser_r0,I_tvalid_r0} <= 0;
end
else begin
I_tlast_r0 <= I_raw_tlast;
I_tuser_r0 <= I_raw_tuser;
I_tvalid_r0 <= I_raw_tvalid;
end
end
assign
O_raw_tlast
= I_tlast_r0;
assign
O_raw_tuser
= I_tuser_r0;
assign
O_raw_tvalid = I_tvalid_r0;
assign
O_raw_tdata
assign
I_raw_tready = O_raw_tready;
= raw_data_r0;
endmodule
第 125页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
8.4.2line_buffer 模块代码分析
这个是行缓存模块,用的是 bram 去缓存,让这个算法更加方便去各个平台部署,且这里把前端 tuser 信号沿用
了,增强视频的稳定性。
`timescale 1ns / 1ps
module line_buffer_demosaic#(
parameter IMG_HEIGHT = 1080,
parameter IMG_WIDTH = 1920
)
(
input
I_clk ,
input
I_rst_n,
input
I_tuser,
input
wire
input
wire
I_valid,
[32:0]
I_data ,
O_valid,
output wire
output wire
[32:0]
O_data
);
wire
rd_en;
reg [10:0]
addra;
reg [10:0]
addrb;
reg [32:0]
data_d0;
reg
valid_d0;
localparam IMG_WIDTH_4x = (IMG_WIDTH>>2);
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
data_d0
<= 0;
valid_d0 <= 0;
end else begin
data_d0
<= I_data;
valid_d0 <= I_valid;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n || I_tuser) begin
addra <= 0;
end
else if(valid_d0)begin
addra <= (addra == IMG_WIDTH_4x -1) ? 'b0 : addra + 1'b1;
end
end
reg tlast_lock_d0;
always @(posedge I_clk or negedge I_rst_n) begin
第 126页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
if(!I_rst_n || I_tuser) begin
tlast_lock_d0 <= 'b0;
end
else if((tlast_lock_d0 == 'b0) & (addra == IMG_WIDTH_4x -1))
tlast_lock_d0 <= 'b1;
end
assign rd_en = I_valid&&tlast_lock_d0 ? 1'b1 : 1'b0;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n || I_tuser) begin
addrb <= 0;
end else begin
addrb <= rd_en ?(addrb == IMG_WIDTH_4x - 1)? 'b0 : addrb + 1'b1 : addrb;
end
end
assign O_valid = rd_en;
blk_mem_gen_demosaic blk_mem_gen_demosaic_r0 (
.clka (I_clk
.wea
),
// input wire clka
(valid_d0), // input wire [0 : 0] wea
),
// input wire [10 : 0] addra
.dina (data_d0),
// input wire [33 : 0] dina
.clkb (I_clk
),
// input wire clkb
.addrb(addrb
),
// input wire [10 : 0] addrb
.doutb(O_data )
// output wire [33 : 0] doutb
.addra(addra
);
endmodule
8.4.3raw_matrix_3x3_buffer 模块代码分析
此处给出部分关键代码,关键是在于其边界复制,需要注意的是,在进行边界复制的时候,左右两侧的数据只
赋一列即可,其余三列赋 0,以便后续的计算,还有 fifo 的复位需要对其进行谨慎处理。
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
matrix_last_line_buffer <= 'b0 ;
matrix_cur_line_buffer
<= 'b0 ;
matrix_next_line_buffer <= 'b0 ;
end else if(valid[0] | ch_valid) begin
if(v_cnt == 0) begin
if(h_cnt == 0) begin
matrix_last_line_buffer <= {{24{1'b0}}, data[0][31:24], data[0][31:0],
data[0][31:0]} ;
matrix_cur_line_buffer
<= {{24{1'b0}}, data[0][31:24], data[0][31:0],
data[0][31:0]} ;
matrix_next_line_buffer <= {{24{1'b0}}, data[0][31:24], data[0][31:0],
第 127页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
data[0][31:0]} ;
end
else if(h_cnt == (IMG_WIDTH_4x - 1))begin
matrix_last_line_buffer <= {matrix_next_line_buffer [63:0],
matrix_next_line_buffer[7:0], {24{1'b0}}} ;
matrix_cur_line_buffer
<= {matrix_next_line_buffer [63:0],
matrix_next_line_buffer[7:0], {24{1'b0}}} ;
matrix_next_line_buffer <= {matrix_next_line_buffer [63:0],
matrix_next_line_buffer[7:0], {24{1'b0}}} ;
end
else begin
matrix_last_line_buffer <= {matrix_next_line_buffer[63:0], data[0][31:0]} ;
matrix_cur_line_buffer
<= {matrix_next_line_buffer[63:0], data[0][31:0]} ;
matrix_next_line_buffer <= {matrix_next_line_buffer[63:0], data[0][31:0]} ;
end
end
if(v_cnt == 1) begin
if(h_cnt == 0) begin
matrix_last_line_buffer <= {{24{1'b0}}, data[1][31:24], data[1][31:0],
data[1][31:0]} ;
matrix_cur_line_buffer
<= {{24{1'b0}}, data[1][31:24], data[1][31:0],
data[1][31:0]} ;
matrix_next_line_buffer <= {{24{1'b0}}, data[0][31:24], data[0][31:0],
data[0][31:0]} ;
end
else if(h_cnt == (IMG_WIDTH_4x - 1))begin
matrix_last_line_buffer <= {matrix_cur_line_buffer [63:0],
matrix_cur_line_buffer[7:0], {24{1'b0}}} ;
matrix_cur_line_buffer
<= {matrix_cur_line_buffer [63:0],
matrix_cur_line_buffer[7:0], {24{1'b0}}} ;
matrix_next_line_buffer <= {matrix_next_line_buffer [63:0],
matrix_next_line_buffer[7:0], {24{1'b0}}} ;
end
else begin
matrix_last_line_buffer <= {matrix_cur_line_buffer[63:0],
data[1][31:0]} ;
matrix_cur_line_buffer
data[1][31:0]} ;
<= {matrix_cur_line_buffer[63:0],
matrix_next_line_buffer <= {matrix_next_line_buffer[63:0], data[0][31:0]} ;
end
end
else begin
if(h_cnt == 0) begin
matrix_last_line_buffer <= {{24{1'b0}},data[2][31:24], data[2][31:0],
data[2][31:0]} ;
matrix_cur_line_buffer
<= {{24{1'b0}},data[1][31:24], data[1][31:0],
data[1][31:0]} ;
matrix_next_line_buffer <= {{24{1'b0}},data[0][31:24], data[0][31:0],
data[0][31:0]} ;
end
else if(h_cnt == (IMG_WIDTH_4x - 1))begin
第 128页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
matrix_last_line_buffer <= {matrix_last_line_buffer[63:0],
matrix_last_line_buffer[7:0], {24{1'b0}}} ;
matrix_cur_line_buffer
<= {matrix_cur_line_buffer [63:0], matrix_cur_line_buffer
[7:0], {24{1'b0}}} ;
matrix_next_line_buffer <= {matrix_next_line_buffer[63:0],
matrix_next_line_buffer[7:0], {24{1'b0}}} ;
end
else begin
matrix_last_line_buffer <= {matrix_last_line_buffer[63:0], data[2][31:0]} ;
matrix_cur_line_buffer
<= {matrix_cur_line_buffer [63:0], data[1][31:0]} ;
matrix_next_line_buffer <= {matrix_next_line_buffer[63:0], data[0][31:0]} ;
end
end
end
else begin
matrix_last_line_buffer <= 'b0 ;
matrix_cur_line_buffer
<= 'b0 ;
matrix_next_line_buffer <= 'b0 ;
end
End
/////////////////////////////////////////////
/////////////////////////////////////////////
//fifo 处理
R_REQ;
reg
reg [11:0] R_bcnt;
R_MS;
reg [0:0]
wire [11:0] data_count; // R_bcnt and wr_data_cnt's width is equal
empty;
wire
localparam S_DATA1 = 0;
localparam S_DATA2 = 1;
reg [7:0] rst_cnt
;
reg
fifo_rst_done;
reg
fifo_rst_lock;
// As long as FIFO is filled with IMG_WIDTH data, read IMG_WIDTH data continuously
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
R_MS
<= S_DATA1;
next_line_data_valid <= 0;
R_bcnt
<= 0;
end
else begin
case(R_MS)
S_DATA1:begin
第 129页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
R_bcnt <= 0;
if(R_REQ )begin
next_line_data_valid <= 1'b1;
R_MS
<= S_DATA2;
end
else
begin
next_line_data_valid <= 1'b0;
end
end
S_DATA2:begin
if(R_bcnt == MATRIX_WIDTH)begin
next_line_data_valid <= 1'b0;
R_MS
<= S_DATA1;
R_bcnt <= 0;
end
else begin
next_line_data_valid <= 1'b1;
R_bcnt
<= R_bcnt + 'd1;
end
end
default: R_MS <= S_DATA1;
endcase
end
end
always@(posedge I_clk)
R_REQ <= (data_count > MATRIX_WIDTH);
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
rst_cnt
<= 0;
fifo_rst_done <= 0;
fifo_rst_lock <= 0;
end
else if(O_raw_tuser_d0 & (empty == 1'b0))begin
fifo_rst_lock <= 1;
fifo_rst_done <= 0;
rst_cnt
<= 0;
end
else if(fifo_rst_lock & (rst_cnt[7] == 0))
rst_cnt <= rst_cnt + 1'b1;
else begin
rst_cnt
<= 0;
fifo_rst_done <= 1;
fifo_rst_lock <= 0;
end
end
reg O_raw_tlast_d1;
reg fifo_async_en;
第 130页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
O_raw_tlast_d1 <= 0;
end
else
O_raw_tlast_d1 <= O_raw_tlast_d0;
end
reg [13:0] ycnt;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
ycnt
<= 0;
fifo_async_en <= 1'b0;
end
else if(O_raw_tuser_d0 & (empty == 1'b0))begin
fifo_async_en <=0;
ycnt <= 0;
end
else if( O_raw_tuser_d0 & fifo_rst_done)begin
fifo_async_en <= 1'b1;
end
else if(~O_raw_tlast_d1 & O_raw_tlast_d0 & fifo_async_en)begin
if(ycnt == IMG_HEIGHT - 1)begin
ycnt <=0;
fifo_async_en <= 1'b0;
end
else
ycnt <=
ycnt + 1'b1;
end
end
wire
fifo_rst = (rst_cnt >0) & (rst_cnt <100) ;
wire [32:0]
raw_data_r0 = {O_raw_tuser_d0,raw_data};
wire
raw_data_valid_d = raw_data_valid & fifo_rst_done & (fifo_async_en |
O_raw_tuser_d0);
fifo_generator_demosaic your_instance_name (
// input wire clk
.clk(I_clk),
.rst((I_rst_n == 0) | fifo_rst),
// input wire rst
// input wire [32 : 0] din
.din(raw_data_r0),
.wr_en(raw_data_valid_d),
// input wire wr_en
// input wire rd_en
.rd_en(next_line_data_valid),
.dout(next_line_data),
.full(),
// output wire [32 : 0] dout
// output wire full
.empty(empty),
// output wire empty
.data_count(data_count)
// output wire [11 : 0] data_count
);
第 131页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
8.4.4bilinear_interpolation 模块代码分析
此模块只给出了核心部分的代码(BGGR 部分),读者可以拿这块代码对照上文中 8.2.4 双线性插值算法中所
讲述的去理解,当然也可以沿用第六章的行缓存生成的矩阵,不对边界进行处理,对于一般的图像来说,对于边界条
件的处理其实并不严苛。
/*****************************************************************
BAYER_MODE_BGGR
*****************************************************************/
// mipi cs500 raw
generate if(BAYER_MODE == BGGR) begin : BAYER_MODE_BGGR
// R Channel
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{r0_sum_part0, r0_sum_part1} <= 'd0 ;
r1_sum_part0
<= 'd0 ;
{r2_sum_part0, r2_sum_part1}
r3_sum_part0
<= 'd0 ;
<= 'd0 ;
valid_r0 <= 'd0 ;
end
else begin
valid_r0 <= I_tvalid ;
if(I_tvalid) begin
if(bayer_ypos) begin
r0_sum_part0 <= matrix13 + matrix15 ;
r0_sum_part1 <= 'd0 ;
r1_sum_part0 <= matrix15 ;
r2_sum_part0 <= matrix15 + matrix17 ;
r2_sum_part1 <= 'd0 ;
r3_sum_part0 <= matrix17 ;
end
else begin
r0_sum_part0 <= matrix03 + matrix05 ;
r0_sum_part1 <= matrix23 + matrix25 ;
r1_sum_part0 <= matrix05 + matrix25 ;
r2_sum_part0 <= matrix05 + matrix07 ;
r2_sum_part1 <= matrix25 + matrix27 ;
r3_sum_part0 <= matrix07 + matrix27 ;
end
end
end
end
第 132页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
// G Channel
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{g0_sum_part0, g0_sum_part1} <= 'b0 ;
{g1_sum_part0, g1_sum_part1} <= 'b0 ;
{g2_sum_part0, g2_sum_part1} <= 'b0 ;
{g3_sum_part0, g3_sum_part1} <= 'b0 ;
end
else begin
if(I_tvalid) begin
if(bayer_ypos) begin
g0_sum_part0 <= matrix14 ;
g0_sum_part1 <= 'd0 ;
g1_sum_part0 <= matrix05 + matrix25 ;
g1_sum_part1 <= matrix14 + matrix16 ;
g2_sum_part0 <= matrix16;
g2_sum_part1 <= 'd0 ;
g3_sum_part0 <= matrix07 + matrix27 ;
g3_sum_part1 <= matrix16 + matrix18 ;
end
else begin
g0_sum_part0 <= matrix04 + matrix24 ;
g0_sum_part1 <= matrix13 + matrix15 ;
g1_sum_part0 <= matrix15 ;
g1_sum_part1 <= 'd0 ;
g2_sum_part0 <= matrix06 + matrix26 ;
g2_sum_part1 <= matrix15 + matrix17 ;
g3_sum_part0 <= matrix17 ;
g3_sum_part1 <= 'd0 ;
end
end
end
end
//B Channel
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
b0_sum_part0 <= 'd0 ;
{b1_sum_part0, b1_sum_part1} <= 'd0 ;
b2_sum_part0 <= 'd0 ;
{b3_sum_part0, b3_sum_part1} <= 'd0 ;
end
else begin
if(I_tvalid) begin
第 133页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
if(bayer_ypos) begin
b0_sum_part0 <= matrix04 + matrix24 ;
b1_sum_part0 <= matrix04 + matrix06 ;
b1_sum_part1 <= matrix24 + matrix26 ;
b2_sum_part0 <= matrix06 + matrix26 ;
b3_sum_part0 <= matrix06 + matrix08 ;
b3_sum_part1 <= matrix26 + matrix28 ;
end
else begin
b0_sum_part0 <= matrix14 ;
b1_sum_part0 <= matrix14 + matrix16 ;
b1_sum_part1 <= 'd0 ;
b2_sum_part0 <= matrix16 ;
b3_sum_part0 <= matrix16 + matrix18 ;
b3_sum_part1 <= 'd0 ;
end
end
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{r0_matrix_plus, g0_matrix_plus, b0_matrix_plus} <= 'd0 ;
{r1_matrix_plus, g1_matrix_plus, b1_matrix_plus} <= 'd0 ;
{r2_matrix_plus, g2_matrix_plus, b2_matrix_plus} <= 'd0 ;
{r3_matrix_plus, g3_matrix_plus, b3_matrix_plus} <= 'd0 ;
valid_r1 <= 'd0 ;
end
else begin
valid_r1 <= valid_r0 ;
if(valid_r0) begin
r0_matrix_plus <= r0_sum_part0 + r0_sum_part1 ;
r1_matrix_plus <= r1_sum_part0 ;
r2_matrix_plus <= r2_sum_part0 + r2_sum_part1 ;
r3_matrix_plus <= r3_sum_part0 ;
g0_matrix_plus <= g0_sum_part0 + g0_sum_part1 ;
g1_matrix_plus <= g1_sum_part0 + g1_sum_part1 ;
g2_matrix_plus <= g2_sum_part0 + g2_sum_part1 ;
g3_matrix_plus <= g3_sum_part0 + g3_sum_part1 ;
b0_matrix_plus <= b0_sum_part0 ;
b1_matrix_plus <= b1_sum_part0 + b1_sum_part1 ;
第 134页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
b2_matrix_plus <= b2_sum_part0 ;
b3_matrix_plus <= b3_sum_part0 + b3_sum_part1 ;
end
end
end
// pipleline 1
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{r0_mean, g0_mean, b0_mean} <= 'd0 ;
{r1_mean, g1_mean, b1_mean} <= 'd0 ;
{r2_mean, g2_mean, b2_mean} <= 'd0 ;
{r3_mean, g3_mean, b3_mean} <= 'd0 ;
valid_r2 <= 'd0 ;
end
else begin
valid_r2 <= valid_r1 ;
if(valid_r1) begin
r0_mean <= bayer_ypos_r1 ? r0_matrix_plus >> 1 : r0_matrix_plus >> 2 ;
g0_mean <= bayer_ypos_r1 ? g0_matrix_plus
: g0_matrix_plus >> 2 ;
b0_mean <= bayer_ypos_r1 ? b0_matrix_plus >> 1 : b0_matrix_plus
r1_mean <= bayer_ypos_r1 ? r1_matrix_plus
;
: r1_matrix_plus >> 1 ;
g1_mean <= bayer_ypos_r1 ? g1_matrix_plus >> 2 : g1_matrix_plus ;
b1_mean <= bayer_ypos_r1 ? b1_matrix_plus >> 2 : b1_matrix_plus >> 1 ;
r2_mean <= bayer_ypos_r1 ? r2_matrix_plus >> 1 : r2_matrix_plus >> 2;
g2_mean <= bayer_ypos_r1 ? g2_matrix_plus
: g2_matrix_plus >> 2;
b2_mean <= bayer_ypos_r1 ? b2_matrix_plus >> 1 : b2_matrix_plus ;
r3_mean <= bayer_ypos_r1 ? r3_matrix_plus
: r3_matrix_plus >> 1 ;
g3_mean <= bayer_ypos_r1 ? g3_matrix_plus >> 2 : g3_matrix_plus ;
b3_mean <= bayer_ypos_r1 ? b3_matrix_plus >> 2 : b3_matrix_plus >> 1 ;
end
end
end
end
第 135页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
8.5 上板结果
8.5.1 接线图
8.5.2 结果显示
第 136页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见整个图像都是偏绿的,这个就是图像去马赛克之后的样子,后续会经过一系列算法让其呈现的图像变
成我们平常所见的样子。
8.6Python 实现
很多读者可能会担心没有关于 Bayer 格式的灰度图像,无法去用 Python 进行验证,这里作者用 Python 写了一
个可以把彩色图像(也就是我们平常所用相机拍的图)转化为 Bayer 格式的灰度图,这样我们可以直接拿这个经过
转化的图去验证。
8.6.1Python 代码分析
该模块主要用于把彩色图像转变为 Bayer 格式的灰度图,以便我们进行后续的算法验证所用。
import cv2
import numpy as np
def generate_bayer_image(color_img):
"""
将彩色图像转换为拜耳模式的灰度图像。
参数:
- color_img: 原始彩色图像。
返回:
- bayer_img: 拜耳模式的灰度图像。
"""
height, width, _ = color_img.shape
# 初始化拜耳图像
第 137页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
bayer_img = np.zeros((height, width), dtype=np.uint8)
# RGGB 拜耳模式
# R 位置(偶数行,偶数列)
bayer_img[0::2, 0::2] = color_img[0::2, 0::2, 2]
# G 位置(偶数行,奇数列)
bayer_img[0::2, 1::2] = color_img[0::2, 1::2, 1]
# G 位置(奇数行,偶数列)
bayer_img[1::2, 0::2] = color_img[1::2, 0::2, 1]
# B 位置(奇数行,奇数列)
bayer_img[1::2, 1::2] = color_img[1::2, 1::2, 0]
return bayer_img
# 示例代码,生成拜耳图像
if __name__ == "__main__":
import cv2
import numpy as np
# 读取彩色图像
color_image = cv2.imread('001.bmp')
# 检查图像是否成功读取
if color_image is None:
print("无法读取图像,请检查文件路径和文件名是否正确。")
else:
# 生成拜耳图像
bayer_image = generate_bayer_image(color_image)
# 保存拜耳图像
cv2.imwrite('bayer_image.png', bayer_image)
print("拜耳图像已成功保存为 'bayer_image.png'。")
# 后续可以对 bayer_image 进行去马赛克处理
该模块为 Demosiac 模块,直接输入 Bayer 格式的灰度图像,就可以得到经过马赛克算法处理后的图了。
import cv2
import numpy as np
def demosaic_bilinear_improved(bayer_img):
"""
改进的双线性插值去马赛克算法,减少色差和提升图像质量。
参数:
- bayer_img: 原始拜耳模式图像,单通道灰度图像。
返回:
- rgb_img: 去马赛克后的 RGB 彩色图像。
"""
第 138页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
# 获取图像的高和宽
height, width = bayer_img.shape
# 初始化 R、G、B 通道
R = np.zeros((height, width), dtype=np.float32)
G = np.zeros((height, width), dtype=np.float32)
B = np.zeros((height, width), dtype=np.float32)
# 假设使用 RGGB 模式的拜耳滤色器阵列
# 分离已知的颜色值
R[0::2, 0::2] = bayer_img[0::2, 0::2]
# 红色像素位置
G[0::2, 1::2] = bayer_img[0::2, 1::2]
# 绿色像素位置
G[1::2, 0::2] = bayer_img[1::2, 0::2]
# 绿色像素位置
B[1::2, 1::2] = bayer_img[1::2, 1::2]
# 蓝色像素位置
# 创建填充图像,以便处理边缘情况
R_padded = np.pad(R, ((2, 2), (2, 2)), 'symmetric')
G_padded = np.pad(G, ((2, 2), (2, 2)), 'symmetric')
B_padded = np.pad(B, ((2, 2), (2, 2)), 'symmetric')
# 定义用于插值的卷积核
kernel_G_at_RB = np.array([[0, 0.25, 0],
[0.25, 1, 0.25],
[0, 0.25, 0]], dtype=np.float32)
kernel_RB_at_G = np.array([[0.25, 0.5, 0.25],
[0.5, 1, 0.5],
[0.25, 0.5, 0.25]], dtype=np.float32) / 4
kernel_RB_at_RB = np.array([[0.25, 0.5, 0.25],
[0.5, 1, 0.5],
[0.25, 0.5, 0.25]], dtype=np.float32) / 4
# 插值绿色通道
G_interp = G.copy()
missing_G_at_RB = (G == 0)
G_interp[missing_G_at_RB] = cv2.filter2D(G_padded, -1, kernel_G_at_RB)[2:-2,
2:-2][missing_G_at_RB]
# 插值红色通道
R_interp = R.copy()
missing_R = (R == 0)
R_interp[missing_R] = cv2.filter2D(R_padded, -1, kernel_RB_at_RB)[2:-2, 2:-2][missing_R]
# 插值蓝色通道
B_interp = B.copy()
missing_B = (B == 0)
B_interp[missing_B] = cv2.filter2D(B_padded, -1, kernel_RB_at_RB)[2:-2, 2:-2][missing_B]
第 139页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
# 合并三个通道
rgb_img = cv2.merge([B_interp, G_interp, R_interp])
rgb_img = np.clip(rgb_img, 0, 255).astype(np.uint8)
return rgb_img
# 示例代码,读取拜耳图像并进行去马赛克处理
if __name__ == "__main__":
# 读取原始拜耳图像(单通道灰度图像)
bayer_image = cv2.imread('bayer_image.png', cv2.IMREAD_GRAYSCALE)
# 检查图像是否成功读取
if bayer_image is None:
print("无法读取拜耳图像,请检查文件路径。")
else:
# 进行去马赛克处理
demosaiced_image = demosaic_bilinear_improved(bayer_image)
# 显示结果
cv2.imshow('Original Bayer Image', bayer_image)
cv2.imshow('Demosaiced Image', demosaiced_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果
cv2.imwrite('demosaiced_image.png', demosaiced_image)
8.6.2 结果显示
可以发现第二个图是用 Python 形成的 bayer 格式的灰度图,第三个图是经过去马赛克处理的图,图像整体呈现
绿色,需要后续的算法进行处理。
第 140页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
9.FPGA 实现图像自动白平衡处理
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
9.1 图像自动白平衡算法简介
自动白平衡(Auto White Balance,简称 WB)是图像处理中的一个重要步骤,主要用于校正图像中的颜色,使
得图像在不同的光照条件下都能呈现出自然的色彩。ISP(Image Signal Processor)中的白平衡处理是通过调整图像
的红、绿、蓝(RGB)通道的增益来实现的。
可是一般的图像传感器是没有自动白平衡这个功能的,这就需要我们去做一个自动白平衡算法去对它进行一个
调整。我们可以这么理解,由于白色不含任何色度信息,其显色效果最佳,因此它为被选定为基准色。如果选择黄
色或者是蓝色为基准色,那么在不同的光源下,基准色会存在误差,光源的颜色就很难区分出来了,就更谈不上矫
正了。
9.2 图像自动白平衡算法原理
以下是 ISP 白平衡的详细工作原理和步骤:
此处用的是灰度世界算法,但是在此基础上对其各个点进行了限制,并且对于绿色,并没有去给其增益,而是
维持其本来输入的数据值以输出。
该法是以灰度世界假设为基础的,该假设认为对于一副彩色图像,其 R、G、B 三分量的平均值趋向于同一个
灰度 K,现在需要确定该灰度,并且算出通道增益,最后用各分量的通道增益去乘以其本身即可。下面是算法的过
程:
第一步:计算出 K 的值
�� = (����� + ����� + �����)/�
�� = (����� + ����� + �����)/�
�� = (����� + ����� + �����)/�
Raver、Gaver、Baver 分别表示红、绿、蓝三通道的平均值。
第二步:计算出各通道的增益
K_R=Kg/Kb ;
K_B=Kg/Kr ;
第三步:根据 Von Kries 对角模型,对于图像中的每个像素的 R、B 都去给他们用相应的增益去乘,其中的 G,也就
是绿色给它直接使用原始数据即可,因为人眼对绿色最为敏感,如果此处的绿色也对其进行增益,可能会导致出来
的图像,在出现大块单一颜色的时候,可能会出现明显偏色的情况。
第 141页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Rnew
= R * K_R;
Gnew
= G ;
Bnew
= B * K_B;
Image processing course advanced(2024)
这里需要注意的一个点,就是得到的值可能会存在溢出的情况(也就是 R、G、B 三通道的值可能会有大于 255
的),我选择的处理方法是把溢出的值的直接设置为 255,不过这样出来的图像可能会整体偏白色,也就是冷色调
图像。
还有需要注意的点就是代码中的除法尽量都使用除法器去除,不然容易出现错误,导致最终的延迟时间大大增
加,在一些要求高频率的时刻,会导致所呈现的图像出现较多噪点,最终所呈现出来的图像,也是不尽人意。
9.3 代码分析
9.3.1Verilog Design 代码分析
源代码如下,此代码以绿色作为主基调,用绿色作为被除数,如此解决了去马赛克之后图片整体呈现绿色的问
题,也就不用再去消耗其他资源去再写一个绿平衡算法。
module awb
#(
parameter [12:0] H_SIZE = 640,
parameter [12:0] V_SIZE = 480
)
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
input [95:0]
I_tdata
,
input
I_tvalid ,
output
I_tready ,
output
O_tlast
,
output
O_tuser
,
output [95:0]
O_tdata
,
output
O_tvalid ,
input
O_tready
,
);
/*****************************************************************
中间信号
*****************************************************************/
reg
[3:0]
I_tlast_r
;
reg
[3:0]
I_tuser_r
;
第 142页
常州米联客信息科技有限公司
reg
米联客(MILIANKE)www.uisrc.com www.milianke.com
I_tvalid_r
[3:0]
;
wire [23:0] I_tdata_r1 = I_tdata[23:0] ;
wire [23:0] I_tdata_r2 = I_tdata[47:24];
wire [23:0] I_tdata_r3 = I_tdata[71:48];
wire [23:0] I_tdata_r4 = I_tdata[95:72];
wire [7:0]
rgb888_r_r1 = I_tdata_r1[16+:8];
wire [7:0]
rgb888_g_r1 = I_tdata_r1[8+:8] ;
wire [7:0]
rgb888_b_r1 = I_tdata_r1[0+:8] ;
wire [7:0]
rgb888_r_r2 = I_tdata_r2[16+:8];
wire [7:0]
rgb888_g_r2 = I_tdata_r2[8+:8] ;
wire [7:0]
rgb888_b_r2 = I_tdata_r2[0+:8] ;
wire [7:0]
rgb888_r_r3 = I_tdata_r3[16+:8];
wire [7:0]
rgb888_g_r3 = I_tdata_r3[8+:8] ;
wire [7:0]
rgb888_b_r3 = I_tdata_r3[0+:8] ;
wire [7:0]
rgb888_r_r4 = I_tdata_r4[16+:8];
wire [7:0]
rgb888_g_r4 = I_tdata_r4[8+:8] ;
wire [7:0]
rgb888_b_r4 = I_tdata_r4[0+:8] ;
//累加 RGB 通道的值
reg [31:0] sum_r_r1;
reg [31:0] sum_g_r1;
reg [31:0] sum_b_r1;
reg [31:0] sum_r_r2;
reg [31:0] sum_g_r2;
reg [31:0] sum_b_r2;
reg [31:0] sum_r_r3;
reg [31:0] sum_g_r3;
reg [31:0] sum_b_r3;
reg [31:0] sum_r_r4;
reg [31:0] sum_g_r4;
reg [31:0] sum_b_r4;
wire flag;
reg [35:0] R_avg_3x [3:0];
reg [35:0] G_avg_3x [3:0];
reg [35:0] B_avg_3x [3:0];
/*****************************************************************
平均值计算
*****************************************************************/
第 143页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
assign flag = I_tuser_r[1] ^ I_tuser;
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
sum_r_r1 <= 0;
sum_g_r1 <= 0;
sum_b_r1 <= 0;
sum_r_r2 <= 0;
sum_g_r2 <= 0;
sum_b_r2 <= 0;
sum_r_r3 <= 0;
sum_g_r3 <= 0;
sum_b_r3 <= 0;
sum_r_r4 <= 0;
sum_g_r4 <= 0;
sum_b_r4 <= 0;
end
else if(flag)begin
sum_r_r1 <= 0;
sum_g_r1 <= 0;
sum_b_r1 <= 0;
sum_r_r2 <= 0;
sum_g_r2 <= 0;
sum_b_r2 <= 0;
sum_r_r3 <= 0;
sum_g_r3 <= 0;
sum_b_r3 <= 0;
sum_r_r4 <= 0;
sum_g_r4 <= 0;
sum_b_r4 <= 0;
end
else if(I_tvalid) begin
sum_r_r1 <= sum_r_r1 + rgb888_r_r1;
sum_g_r1 <= sum_g_r1 + rgb888_g_r1;
sum_b_r1 <= sum_b_r1 + rgb888_b_r1;
sum_r_r2 <= sum_r_r2 + rgb888_r_r2;
sum_g_r2 <= sum_g_r2 + rgb888_g_r2;
sum_b_r2 <= sum_b_r2 + rgb888_b_r2;
sum_r_r3 <= sum_r_r3 + rgb888_r_r3;
sum_g_r3 <= sum_g_r3 + rgb888_g_r3;
sum_b_r3 <= sum_b_r3 + rgb888_b_r3;
第 144页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
sum_r_r4 <= sum_r_r4 + rgb888_r_r4;
sum_g_r4 <= sum_g_r4 + rgb888_g_r4;
sum_b_r4 <= sum_b_r4 + rgb888_b_r4;
end
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
R_avg_3x[0] <= 3;
G_avg_3x[0] <= 3;
B_avg_3x[0] <= 3;
R_avg_3x[1] <= 3;
G_avg_3x[1] <= 3;
B_avg_3x[1] <= 3;
R_avg_3x[2] <= 3;
G_avg_3x[2] <= 3;
B_avg_3x[2] <= 3;
R_avg_3x[3] <= 3;
G_avg_3x[3] <= 3;
B_avg_3x[3] <= 3;
end
else if(flag)begin
R_avg_3x[0] <= 3;
G_avg_3x[0] <= 3;
B_avg_3x[0] <= 3;
R_avg_3x[1] <= 3;
G_avg_3x[1] <= 3;
B_avg_3x[1] <= 3;
R_avg_3x[2] <= 3;
G_avg_3x[2] <= 3;
B_avg_3x[2] <= 3;
R_avg_3x[3] <= 3;
G_avg_3x[3] <= 3;
B_avg_3x[3] <= 3;
end
else if(I_tvalid_r[0]) begin
R_avg_3x[0] <= {sum_r_r1,1'b0} + sum_r_r1;
G_avg_3x[0] <= {sum_g_r1,1'b0} + sum_g_r1;
B_avg_3x[0] <= {sum_b_r1,1'b0} + sum_b_r1;
R_avg_3x[1] <= {sum_r_r2,1'b0} + sum_r_r2;
G_avg_3x[1] <= {sum_g_r2,1'b0} + sum_g_r2;
第 145页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
B_avg_3x[1] <= {sum_b_r2,1'b0} + sum_b_r2;
R_avg_3x[2] <= {sum_r_r3,1'b0} + sum_r_r3;
G_avg_3x[2] <= {sum_g_r3,1'b0} + sum_g_r3;
B_avg_3x[2] <= {sum_b_r3,1'b0} + sum_b_r3;
R_avg_3x[3] <= {sum_r_r4,1'b0} + sum_r_r4;
G_avg_3x[3] <= {sum_g_r4,1'b0} + sum_g_r4;
B_avg_3x[3] <= {sum_b_r4,1'b0} + sum_b_r4;
end
else begin
R_avg_3x[0] <= R_avg_3x[0];
G_avg_3x[0] <= G_avg_3x[0];
B_avg_3x[0] <= B_avg_3x[0];
R_avg_3x[1] <= R_avg_3x[1];
G_avg_3x[1] <= G_avg_3x[1];
B_avg_3x[1] <= B_avg_3x[1];
R_avg_3x[2] <= R_avg_3x[2];
G_avg_3x[2] <= G_avg_3x[2];
B_avg_3x[2] <= B_avg_3x[2];
R_avg_3x[3] <= R_avg_3x[3];
G_avg_3x[3] <= G_avg_3x[3];
B_avg_3x[3] <= B_avg_3x[3];
end
end
/*****************************************************************
计算增益
*****************************************************************/
wire [87:0]
dout_R [3:0];
wire [87:0]
dout_B [3:0];
wire
done [3:0];
wire [47:0]
in_r_x1;
wire [47:0]
in_b_x1;
assign in_r_x1 = dout_R[0][87:40];
assign in_b_x1 = dout_B[0][87:40];
wire [47:0]
in_r_x2;
wire [47:0]
in_b_x2;
assign in_r_x2 = dout_R[1][87:40];
assign in_b_x2 = dout_B[1][87:40];
第 146页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
wire [47:0]
in_r_x3;
wire [47:0]
in_b_x3;
Image processing course advanced(2024)
assign in_r_x3 = dout_R[2][87:40];
assign in_b_x3 = dout_B[2][87:40];
wire [47:0]
in_r_x4;
wire [47:0]
in_b_x4;
assign in_r_x4 = dout_R[3][87:40];
assign in_b_x4 = dout_B[3][87:40];
/*****************************************************************
可解决绿平衡问题
*****************************************************************/
genvar i;
generate
for(i = 0; i < 4; i = i + 1)
begin: div_gen
div_gen_awb div_gen_G_R_r1 (
// input wire aclk
.aclk(I_clk),
.s_axis_divisor_tvalid(I_tvalid_r[1]),
// input wire s_axis_divisor_tvalid
.s_axis_divisor_tdata(R_avg_3x[i]),
// input wire [31 : 0] s_axis_divisor_tdata
.s_axis_dividend_tvalid(I_tvalid_r[1]),
// input wire s_axis_dividend_tvalid
.s_axis_dividend_tdata({G_avg_3x[i],12'd0}),
// input wire [47 : 0] s_axis_dividend_tdata
// output wire m_axis_dout_tvalid
.m_axis_dout_tvalid(done[i]),
// output wire [79 : 0] m_axis_dout_tdata
.m_axis_dout_tdata(dout_R[i])
);
div_gen_awb div_gen_G_B_r1 (
// input wire aclk
.aclk(I_clk),
.s_axis_divisor_tvalid(I_tvalid_r[1]),
// input wire s_axis_divisor_tvalid
.s_axis_divisor_tdata(B_avg_3x[i]),
// input wire [31 : 0] s_axis_divisor_tdata
.s_axis_dividend_tvalid(I_tvalid_r[1]),
// input wire s_axis_dividend_tvalid
.s_axis_dividend_tdata({G_avg_3x[i],12'd0}),
.m_axis_dout_tvalid(),
.m_axis_dout_tdata(dout_B[i])
// input wire [47 : 0] s_axis_dividend_tdata
// output wire m_axis_dout_tvalid
// output wire [79 : 0] m_axis_dout_tdata
);
end
endgenerate
/*****************************************************************
增益限制
*****************************************************************/
reg [15:0]
in_r_r1;
reg [15:0]
in_b_r1;
第 147页
常州米联客信息科技有限公司
reg [15:0]
in_r_r2;
reg [15:0]
in_b_r2;
reg [15:0]
in_r_r3;
reg [15:0]
in_b_r3;
reg [15:0]
in_r_r4;
reg [15:0]
in_b_r4;
米联客(MILIANKE)www.uisrc.com www.milianke.com
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
in_r_r1 <= 16'h1000;
in_b_r1 <= 16'h1000;
end
else if(flag)begin
in_r_r1 <= 16'h1000;
in_b_r1 <= 16'h1000;
end
else if(done[0])begin
if(|in_r_x1[47:16])
in_r_r1 <= 16'hffff;
else
in_r_r1 <= in_r_x1[15:0];
if(|in_b_x1[47:16])
in_b_r1 <= 16'hffff;
else
in_b_r1 <= in_b_x1[15:0];
end
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
in_r_r2 <= 16'h1000;
in_b_r2 <= 16'h1000;
end
else if(flag)begin
in_r_r2 <= 16'h1000;
in_b_r2 <= 16'h1000;
end
else if(done[1])begin
if(|in_r_x2[47:16])
in_r_r2 <= 16'hffff;
else
in_r_r2 <= in_r_x2[15:0];
if(|in_b_x2[47:16])
in_b_r2 <= 16'hffff;
else
in_b_r2 <= in_b_x2[15:0];
end
end
第 148页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
in_r_r3 <= 16'h1000;
in_b_r3 <= 16'h1000;
end
else if(flag)begin
in_r_r3 <= 16'h1000;
in_b_r3 <= 16'h1000;
end
else if(done[2])begin
if(|in_r_x3[47:16])
in_r_r3 <= 16'hffff;
else
in_r_r3 <= in_r_x3[15:0];
if(|in_b_x3[47:16])
in_b_r3 <= 16'hffff;
else
in_b_r3 <= in_b_x3[15:0];
end
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
in_r_r4 <= 16'h1000;
in_b_r4 <= 16'h1000;
end
else if(flag)begin
in_r_r4 <= 16'h1000;
in_b_r4 <= 16'h1000;
end
else if(done[3])begin
if(|in_r_x4[47:16])
in_r_r4 <= 16'hffff;
else
in_r_r4 <= in_r_x4[15:0];
if(|in_b_x4[47:16])
in_b_r4 <= 16'hffff;
else
in_b_r4 <= in_b_x4[15:0];
end
end
/*****************************************************************
附上增益
*****************************************************************/
reg [23:0] R_new_r1;
reg [23:0] G_new_r1;
第 149页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
reg [23:0] B_new_r1;
reg [23:0] R_new_r2;
reg [23:0] G_new_r2;
reg [23:0] B_new_r2;
reg [23:0] R_new_r3;
reg [23:0] G_new_r3;
reg [23:0] B_new_r3;
reg [23:0] R_new_r4;
reg [23:0] G_new_r4;
reg [23:0] B_new_r4;
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
R_new_r1 <= 0;
G_new_r1 <= 0;
B_new_r1 <= 0;
R_new_r2 <= 0;
G_new_r2 <= 0;
B_new_r2 <= 0;
R_new_r3 <= 0;
G_new_r3 <= 0;
B_new_r3 <= 0;
R_new_r4 <= 0;
G_new_r4 <= 0;
B_new_r4 <= 0;
end
else
begin
R_new_r1 <= in_r_r1 * rgb888_r_r1;
G_new_r1 <= rgb888_g_r1;
B_new_r1 <= in_b_r1 * rgb888_b_r1;
R_new_r2 <= in_r_r2 * rgb888_r_r2;
G_new_r2 <= rgb888_g_r2;
B_new_r2 <= in_b_r2 * rgb888_b_r2;
R_new_r3 <= in_r_r3 * rgb888_r_r3;
G_new_r3 <= rgb888_g_r3;
B_new_r3 <= in_b_r3 * rgb888_b_r3;
R_new_r4 <= in_r_r4 * rgb888_r_r4;
G_new_r4 <= rgb888_g_r4;
B_new_r4 <= in_b_r4 * rgb888_b_r4;
end
第 150页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
end
/*****************************************************************
限制溢出
*****************************************************************/
wire [7:0] R_new_x1;
wire [7:0] G_new_x1;
wire [7:0] B_new_x1;
wire [7:0] R_new_x2;
wire [7:0] G_new_x2;
wire [7:0] B_new_x2;
wire [7:0] R_new_x3;
wire [7:0] G_new_x3;
wire [7:0] B_new_x3;
wire [7:0] R_new_x4;
wire [7:0] G_new_x4;
wire [7:0] B_new_x4;
assign R_new_x1 = (R_new_r1[23:20])?255:R_new_r1[19:12];
assign G_new_x1 =
G_new_r1;
assign B_new_x1 = (B_new_r1[23:20])?255:B_new_r1[19:12];
assign R_new_x2 = (R_new_r2[23:20])?255:R_new_r2[19:12];
assign G_new_x2 =
G_new_r2;
assign B_new_x2 = (B_new_r2[23:20])?255:B_new_r2[19:12];
assign R_new_x3 = (R_new_r3[23:20])?255:R_new_r3[19:12];
assign G_new_x3 =
G_new_r3;
assign B_new_x3 = (B_new_r3[23:20])?255:B_new_r3[19:12];
assign R_new_x4 = (R_new_r4[23:20])?255:R_new_r4[19:12];
assign G_new_x4 =
G_new_r4;
assign B_new_x4 = (B_new_r4[23:20])?255:B_new_r4[19:12];
/*****************************************************************
同步信号
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[2:0],I_tlast};
I_tuser_r <= {I_tuser_r[2:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[2:0],I_tvalid};
第 151页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end
end
assign
O_tlast
= I_tlast_r[3];
assign
O_tuser
= I_tuser_r[3];
assign
O_tvalid = I_tvalid_r[3];
assign
O_tdata = {R_new_x4,G_new_x4,B_new_x4,
R_new_x3,G_new_x3,B_new_x3,
R_new_x2,G_new_x2,B_new_x2,
R_new_x1,G_new_x1,B_new_x1};
// assign O_t_data = {R_new[7-:5],G_new[7-:6],B_new[7-:5]};
assign
I_tready = O_tready;
endmodule
9.3.2Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
// Define the image resolution here
`define RESOLUTION_300_220
// `define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/002.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
第 152页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_300_220
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
`define VERTICAL_BLANKING 40
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_tb();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
第 153页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
第 154页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
第 155页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
awb #(
.H_SIZE(`IMAGE_WIDTH),
.V_SIZE(`IMAGE_HEIGHT)
) awb (
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
第 156页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
第 157页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
], green_channel[memory_address
]};
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
第 158页
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
endmodule
9.4 仿真及结果
9.4.1 仿真时序图结果
第 159页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
9.4.2 仿真图片结果
可以看见右边的经过白平衡算法验证的图片右边有几列图像出现模糊的现象,而且它是由于错位所导致的现
象,这个是由于算法本身是用了除法器,且中间含有几个数据的延迟,所导致的,在实际上板中,舍去几帧图像即
可达到正常给出图像。
9.5 上板验证
把该 demo 放入上一章 demo 去马赛克的工程中,只需要把它封装成 IP,然后放在去马赛克算法的后面即可。
大致工程如下:
其中关键部分如下图所示:
由于白平衡算法模块的数据位是 96 位的,所以,作者在它的两侧添加了两个转换器,让它能够和前后两个模
块的数据更好的相连。
第 160页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
9.5.1 结果展示
可以看见并未有出现整体绿色的情况了,但是在一些场景中,它的整体还是会偏绿,但是这个白平衡是相对来
说性价比较高的一个算法了,他所占的资源少,整体呈现的效果也不错,如果读者想要更好的效果,可以试试其他
的白平衡算法,或者再单独添加一个绿平衡算法,这样看起来的效果可能会更好。
9.6Python 实现
9.6.1 代码实现
import cv2
import numpy as np
def white_balance(img):
result = img.astype(np.float32)
avg_b = np.mean(result[:, :, 0])
avg_g = np.mean(result[:, :, 1])
avg_r = np.mean(result[:, :, 2])
avg_gray = (avg_b + avg_g + avg_r) / 3
gain_b = avg_gray / avg_b
gain_g = avg_gray / avg_g
gain_r = avg_gray / avg_r
result[:, :, 0] *= gain_b
result[:, :, 1] *= gain_g
第 161页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
result[:, :, 2] *= gain_r
result = np.clip(result, 0, 255)
return result.astype(np.uint8)
img = cv2.imread('002.bmp')
# Apply white balance
balanced_img = white_balance(img)
# Show the result
cv2.imshow('Original', img)
cv2.imshow('White Balanced', balanced_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
9.6.2 结果实现
原图像:
经过白平衡算法后的图像:
第 162页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 163页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
10.FPGA 实现图像去噪处理
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
10.1 图像去噪算法简介
在 FPGA 中实现的 ISP(图像信号处理)去噪算法有多种选择,不同算法在性能、资源占用和去噪效果上各有
不同。以下是一些常见的去噪算法及其在 FPGA 中的性能对比:
1. 均值滤波(Mean Filter)
原理: 使用一个窗口(如 3x3 或 5x5)对图像中的像素进行平均,输出中心像素的值为窗口内所有像素的平均
值。
性能:
优点: 实现简单,计算复杂度低,可并行化实现。
缺点: 去噪效果较差,容易模糊图像细节,无法有效去除高频噪声。
适用场景: 适用于对细节要求不高的应用场景,硬件资源占用少。
2. 中值滤波(Median Filter)
原理: 通过窗口内像素值的排序,取中值作为中心像素的输出,能够有效去除椒盐噪声。
性能:
优点: 对椒盐噪声有良好的去噪效果,保持边缘细节。
缺点: 实现相对复杂,特别是排序过程对硬件资源要求较高。
适用场景: 适用于去除椒盐噪声的场景,但计算资源要求相对较高。
3. 高斯滤波(Gaussian Filter)
原理: 使用高斯权重对窗口内像素进行加权平均,能够平滑图像,同时一定程度上保留边缘信息。
性能:
优点: 去噪效果比均值滤波好,图像模糊程度较低。
缺点: 计算复杂度较高,尤其是实现高斯权重的卷积运算需要较多乘法器和加法器。
适用场景: 适用于对噪声去除和图像平滑有较高要求的场景,但硬件资源要求较高。
4. 双边滤波(Bilateral Filter)
原理: 结合空间距离和像素值差异的双重权重进行加权平均,能够在平滑噪声的同时保留边缘信息。
性能:
优点: 同时去除噪声并保留图像的边缘和细节。
缺点: 计算复杂度非常高,难以在 FPGA 上实现高效的实时处理,硬件资源消耗大。
适用场景: 适用于高质量图像处理的场景,但由于其复杂性,通常在高性能 FPGA 或结合外部处理器使用。
5. 自适应滤波(Adaptive Filter)
原理: 根据图像局部特征动态调整滤波器的权重或窗口大小,能够更好地保留细节和去噪。
性能:
优点: 能够根据图像内容自适应调整,去噪效果较好,且不会过度模糊细节。
缺点: 实现较为复杂,计算量大,特别是需要动态调整滤波参数。
适用场景: 适用于图像质量要求较高的场景,但硬件资源消耗较大。
6. 非局部均值(Non-Local Means, NLM)
原理: 通过计算像素之间的相似性,使用多个相似区域的加权平均值来去噪,而不是仅仅使用邻域窗口。
性能:
优点: 能够有效去除复杂噪声,同时保留细节。
缺点: 计算复杂度极高,难以在实时处理的 FPGA 系统中高效实现。
适用场景: 高质量去噪,但通常需要结合高性能计算平台,FPGA 上实现较为困难。
第 164页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
7. 小波变换去噪(Wavelet Transform Denoising)
原理: 通过小波变换将图像分解到不同的频率分量,并对高频分量进行抑制,从而实现去噪。
性能:
优点: 能够有效去除噪声,同时保留图像的细节。
缺点: 实现复杂,尤其是小波变换和逆变换的计算量大,FPGA 资源消耗较高。
适用场景: 适用于高质量图像去噪,但需要较大的硬件资源。
8. 卷积神经网络(CNN)去噪
原理: 使用深度学习网络训练得到的去噪模型,通过卷积操作对图像进行去噪。
性能:
优点: 能够在复杂场景中提供极好的去噪效果,尤其是在学习到的特征基础上。
缺点: 需要大量的硬件资源和浮点计算能力,FPGA 的实现难度大,通常需要结合高性能 FPGA 或外部加速器。
适用场景: 高端图像处理应用,FPGA 上实现较为困难。
9. Guided Filter(引导滤波)
原理: 基于引导图像的局部线性模型对图像进行平滑处理,能够保留细节并去除噪声。
性能:
优点: 保留边缘细节,且计算复杂度适中。
缺点: 计算量仍然较大,尤其是在大窗口情况下,FPGA 上实现较为复杂。
适用场景: 适用于高质量图像去噪。10.2 图像自动白平衡算法原理
本章选择了高斯滤波进行去噪处理,此法整体计算难度较为简单,也能够让图像达到实时的效果,对于一些简
单的噪声处理是一个不错的选择,由于经过一系列算法(ISP)的图像并未有什么明显噪声出现,所以此模块并未加
入到 ISP 中去进行处理,若有比较大的噪声出现,读者可以试着将此滤波加入,此处主要采用的是 96 位的 RGB 数
据,也就是一个时钟传输四个 RGB,但是这个由于在同一时间对多个像素处理,导致了效果叠加,也就是滤波效果
大大增强,所以作者不建议这样对中值滤波去使用,不过我们可以使用其他的滤波去调试,这里主要提供给读者一个
思路,一般采用去噪的方法,是根据噪声的特点去选择合适的滤波进去去噪处理,在此 demo 中也包含了一个时钟
周期传输一个 RGB 的中值滤波,当然本章主要还是讲述的一个时钟传输四个 RGB 的,这样也是为了适用于更高的
分辨率。
10.2 原理分析
在图像滤波中,常用的方法是线性滤波技术和非线性滤波技术,线性滤波技术以其完美的理论基础,数学处理
简单、易于采用和硬件实现等优点,一直在图像滤波领域中占有重要的地位。线性滤波对加性高斯噪声有较好的平
滑作用,但对脉冲信号和其他形式的高频分量抑制效果较差,且模糊信号边缘。非线性滤波是基于对输入信号序列
的一种非线性投影关系,常把某一特定的噪声近似为零而保留信号的重要特征,在一定程度上克服线性滤波器的不
足,非线性滤波早期运用较多的是中值滤波器,其应用于多维信号处理时,对窄脉冲信号具有良好的抑制能力,但
中值滤波器对中拖尾和短拖尾分布噪声滤波性能较差,且拖尾越短其滤波能力越差。
这里使用的是高斯滤波,首先我们需要根据具体需求选择想要的一个卷积核,这里作者以如下卷积核为例:
141
4 12 4
141
这是一个标准差σ≈1.0 的卷积核,其权重之和为 32,最后归一化除以 32 即可。
此章的关键在在于把 96 位数据形成 3x3 的矩阵,最关键的就是对边界的处理和如何取值去进行算法计算,边界
处理读者可以看第八章的详细讲解,现在重点讲述如何去取值进行算法计算,请看下图:
第 165页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
如图,这个是一个 12x3 的矩阵,我们把四个像素点看成一个整体,那么我们可以发现,这就是一个 3x3 矩阵,
现在我们用的是这样的一个矩阵去进行后续的算法计算,那么我们应该如何去计算呢,是把这个直接看作一个 3x3
矩阵然后去计算吗?当然不是,因为这里的一个数据其实是包含了 4 个像素点的,我们拿四个像素点直接去计算会
导致会非常多的问题出现,比如根本不知道从何下手,特别是对于一些需要把 RGB 三通道都提取出来的算法,更
是不知道如何去进行算法计算了。
所以这里,作者还是根据上面的去马赛克算法的思路来提供了一个合理解决办法,如下图,先取中间的 4x3 的
矩阵,实际也就是一个 1x3 的矩阵,然后再取两边的矩阵的边缘值作为一个扩充,形成一个 3x6 的矩阵(至于为什
么这样选,下文会讲述)。
为了让大家更清晰的看见这个,下图采用了不同颜色的框,如下图所示:
这个就十分明了了,可以看见这个 3x6 的矩阵被分成了 4 个 3x3 的矩阵,这样我们就很容易理解了,我们直
接在下一步的算法中对这 4 个矩阵同时进行算法处理即可,然后再把这 4 个经过算法处理后形成的像素点合并成一
个 96 位的数据,最终输出就可以了,当然这个时候大家有可能不太能分清时序的问题,所以就直接用 valid 信号重
新生成一个规范的 stream 流信号,作者把这个操作称为“画线”,用代码的形式画出想要的形式。
通俗点说,就是把这个四个矩阵的处理看作 4 个面,每个面都是进行一个相同的一个算法操作,然后再整合成
一个包含 4 个像素点的 96 位数据。
接下里我们再讲讲为什么不选择左右两边作为矩阵的位置,这里有两点原因,其一是原本的行缓存和边界复制
操作的选择就是以中间像素点为基准的,若要改变,那么这个行缓存和边界复制操作也需要做一点改变了。其二是
如果选择了像是右边的像素作为基准,那么这个取这个基础像素的左边的列(8、20、32)倒是方便,但是取右边
的列的我们又需要考虑一番,要把下一个矩阵的列(1、13、25)拿过来计算,去做一些额外的操作,这样还可能
导致意料之外的问题出现,所以一般而言,就选择了中间的像素作为基准去计算。
第 166页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
10.3 代码分析
10.3.1IP 分析
去噪 IP
上面 IP 的这些信号用于实现 AXI-Stream 接口协议,适用于高效的数据流传输。
输入信号(Input Signals):
I_clk: 时钟信号,用于同步数据传输。
I_rst_n: 复位信号,低电平有效,用于初始化模块。
I_tlast: 表示数据流中最后一个数据的标志信号。
I_tuser: 用户自定义信号,通常用于携带附加信息。
I_tdata[95:0]: 输入数据总线,宽度为 96 位,是由 4 个像素点组成
I_tvalid: 输入数据有效信号,表示当前数据总线上的数据是有效的。
O_tready: 输出就绪信号,表示下游模块已经准备好接收数据。
输出信号(Output Signals):
I_tready: 输入就绪信号,表示当前模块已经准备好接收数据。
O_tlast: 表示输出数据流中最后一个数据的标志信号。
O_tuser: 输出用户自定义信号。
O_tdata[95:0]: 输出数据总线,宽度为 96 位,是由 4 个像素点组成
O_tvalid: 输出数据有效信号,表示当前输出数据总线上的数据是有效的。
第 167页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
这个选择好所需的分辨率即可。
10.3.2Verilog Design 代码分析
源代码如下,本章采用是第六章所用的行缓存模块,形成 3x3 的矩阵,但是在其基础上又对边界像素进行的处
理,采用了边界复制的方式,补齐了边界像素,方法与前文的去马赛克算法的边界像素处理大同小异,下面给出的
是 line_buffer,也就是行缓存模块,其中最关键的就算把 tuser 信号延续下去了,这样也可让程序更加稳定。
`timescale 1ns / 1ps
module line_buffer_denoise#(
parameter IMG_HEIGHT = 1080,
parameter IMG_WIDTH = 1920
)
(
input
I_clk ,
input
I_rst_n,
input
I_tuser,
input
wire
input
wire
I_valid,
[96:0]
O_valid,
output wire
output wire
I_data ,
[96:0]
O_data
);
第 168页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
wire
rd_en;
reg [10:0]
addra;
reg [10:0]
addrb;
reg [96:0]
data_d0;
reg
valid_d0;
Image processing course advanced(2024)
localparam IMG_WIDTH_4x = (IMG_WIDTH>>2);
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
data_d0
<= 0;
valid_d0 <= 0;
end else begin
data_d0
<= I_data;
valid_d0 <= I_valid;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n || I_tuser) begin
addra <= 0;
end
else if(valid_d0)begin
addra <= (addra == IMG_WIDTH_4x -1) ? 'b0 : addra + 1'b1;
end
end
reg tlast_lock_d0;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n || I_tuser) begin
tlast_lock_d0 <= 'b0;
end
else if((tlast_lock_d0 == 'b0) & (addra == IMG_WIDTH_4x -1))
tlast_lock_d0 <= 'b1;
end
assign rd_en = I_valid&&tlast_lock_d0 ? 1'b1 : 1'b0;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n || I_tuser) begin
addrb <= 0;
end else begin
addrb <= rd_en ?(addrb == IMG_WIDTH_4x - 1)? 'b0 : addrb + 1'b1 : addrb;
end
end
assign O_valid = rd_en;
blk_mem_gen_denoise blk_mem_gen_denoise (
.clka (I_clk
),
// input wire clka
第 169页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
.wea
(valid_d0), // input wire [0 : 0] wea
),
// input wire [10 : 0] addra
.dina (data_d0),
// input wire [97 : 0] dina
.clkb (I_clk
),
// input wire clkb
.addrb(addrb
),
// input wire [10 : 0] addrb
.doutb(O_data )
// output wire [97 : 0] doutb
.addra(addra
);
endmodule
第二个模块,是 image_line_buffer 模块,主要是对图像进行了边界处理。
`timescale 1ns / 1ps
module image_line_buffer_denoise#(
parameter IMG_HEIGHT = 1080,
parameter IMG_WIDTH = 1920
)
(
input
I_clk
,
input
I_rst_n
,
input
I_tuser
,
input
I_tlast
,
input
I_tvalid
,
input
[95:0]
I_tdata
,
output
reg
O_tlast
,
output
reg
O_tuser
,
output
O_tvalid
,
output
[24*6-1:0] last_line_data,
output
[24*6-1:0] cur_line_data ,
output
[24*6-1:0] next_line_data
);
genvar
i;
wire [0:0]
valid_d0 [2:0];
wire [96:0] data_d0
reg [13:0]
h_cnt;
reg [13:0]
v_cnt;
[2:0];
reg ch_valid;
assign valid_d0[0] = I_tvalid;
assign data_d0[0]
= {I_tuser,I_tdata};
parameter IMG_WIDTH_4x = (IMG_WIDTH>>2);
reg [24*4-1:0] last_line_buffer[2:0];
reg [24*4-1:0] cur_line_buffer [2:0];
reg [24*4-1:0] next_line_buffer[2:0];
第 170页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]} <= 'b0;
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<= 'b0;
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]} <= 'b0;
end else if(valid_d0[0]) begin
if(v_cnt == 0) begin
if(h_cnt == 0)begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]} <={{72{1'b0}},
data_d0[0][95:72], data_d0[0][95:0], data_d0[0][95:0]} ;
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<={{72{1'b0}},
data_d0[0][95:72], data_d0[0][95:0], data_d0[0][95:0]} ;
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]} <={{72{1'b0}},
data_d0[0][95:72], data_d0[0][95:0], data_d0[0][95:0]} ;
end
else if(h_cnt == (IMG_WIDTH_4x - 1))begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],next_line_buffer[2][23:0],{72{1'b0}}};
{cur_line_buffer[0] ,cur_line_buffer[1] ,cur_line_buffer[2] }
<={next_line_buffer[1],next_line_buffer[2],next_line_buffer[2][23:0] ,{72{1'b0}}};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],next_line_buffer[2][23:0],{72{1'b0}}};
end
else begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],data_d0[0][95:0]};
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],data_d0[0][95:0]};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],data_d0[0][95:0]};
end
end else if(v_cnt == 1) begin
if(h_cnt == 0)begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]} <={{72{1'b0}},
data_d0[1][95:72], data_d0[1][95:0], data_d0[1][95:0]};
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<={{72{1'b0}},
data_d0[1][95:72], data_d0[1][95:0], data_d0[1][95:0]};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]} <={{72{1'b0}},
data_d0[0][95:72], data_d0[0][95:0], data_d0[0][95:0]};
end
else if(h_cnt == (IMG_WIDTH_4x - 1))begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]}
<={cur_line_buffer [1],cur_line_buffer[2],cur_line_buffer[2][23:0],{72{1'b0}}};
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<={cur_line_buffer [1] ,cur_line_buffer[2],cur_line_buffer[2][23:0] ,{72{1'b0}}};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],next_line_buffer[2][23:0],{72{1'b0}}};
end
else begin
第 171页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]}
<={cur_line_buffer [1],cur_line_buffer [2],data_d0[1][95:0]};
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<={cur_line_buffer [1],cur_line_buffer [2],data_d0[1][95:0]};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],data_d0[0][95:0]};
end
end else begin
if(h_cnt == 0)begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]} <= {{72{1'b0}},
data_d0[2][95:72], data_d0[2][95:0], data_d0[2][95:0]};
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<= {{72{1'b0}},
data_d0[1][95:72], data_d0[1][95:0], data_d0[1][95:0]};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]} <= {{72{1'b0}},
data_d0[0][95:72], data_d0[0][95:0], data_d0[0][95:0]};
end
else if(h_cnt == (IMG_WIDTH_4x - 1))begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]} <=
{last_line_buffer[1],last_line_buffer[2],last_line_buffer[2][23:0],{72{1'b0}}};
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<=
{cur_line_buffer[1] ,cur_line_buffer[2] ,cur_line_buffer[2][23:0] ,{72{1'b0}}};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]} <=
{next_line_buffer[1],next_line_buffer[2],next_line_buffer[2][23:0],{72{1'b0}}};
end
else begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]}
<={last_line_buffer[1],last_line_buffer[2],data_d0[2][95:0]};
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<={cur_line_buffer[1] ,cur_line_buffer[2] ,data_d0[1][95:0]};
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]}
<={next_line_buffer[1],next_line_buffer[2],data_d0[0][95:0]};
end
end
end
else begin
{last_line_buffer[0],last_line_buffer[1],last_line_buffer[2]} <= 'd0;
{cur_line_buffer[0],cur_line_buffer[1],cur_line_buffer[2]}
<= 'd0;
{next_line_buffer[0],next_line_buffer[1],next_line_buffer[2]} <= 'd0;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
ch_valid <= 0;
h_cnt <= 0;
v_cnt <= 0;
O_tuser <= 0;
O_tlast <= 0;
end else begin
ch_valid <= valid_d0[0];
第 172页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
h_cnt
<= valid_d0[0] ? ((h_cnt == IMG_WIDTH_4x - 1) ? 0 : h_cnt + 1) : h_cnt;
v_cnt
<= valid_d0[0]&&(h_cnt == IMG_WIDTH_4x - 1) ? ((v_cnt == IMG_HEIGHT - 1) ? 0 :
v_cnt + 1) : v_cnt;
O_tuser
<= I_tuser;
O_tlast
<= I_tlast;
end
end
assign
last_line_data
=
{last_line_buffer[0][23:0],last_line_buffer[1],last_line_buffer[2][95:72]};
assign
cur_line_data
=
{cur_line_buffer[0][23:0],cur_line_buffer[1],cur_line_buffer[2][95:72]}
assign
next_line_data
;
=
{next_line_buffer[0][23:0],next_line_buffer[1],next_line_buffer[2][95:72]};
assign O_tvalid = ch_valid;
generate for(i=1;i<3;i=i+1)
begin:two_line_buffer
line_buffer_denoise #(
.IMG_HEIGHT (IMG_HEIGHT),
.IMG_WIDTH
(IMG_WIDTH )
)
line_buffer_denoise_r(
.I_clk
( I_clk
),
.I_rst_n
( I_rst_n
),
.I_tuser
( data_d0[i-1][96] & valid_d0[i-1]),
.I_valid
( valid_d0[i-1]),
.I_data
( data_d0[i-1] ),
.O_valid
( valid_d0[i]
),
.O_data
( data_d0[i]
)
);
end
endgenerate
endmodule
第三个模块是高斯滤波模块,其所涉及算法并不难,关键是如何去更好的完成这个模块的代码编写
module denoise_gaussian
#(
parameter [12:0] IMG_WIDTH
= 640,
parameter [12:0] IMG_HEIGHT = 480
)
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
,
第 173页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
input [95:0]
I_tdata
input
I_tvalid ,
output
I_tready ,
output
O_tlast
,
output
O_tuser
,
output [95:0]
O_tdata
,
output
O_tvalid ,
input
O_tready
Image processing course advanced(2024)
,
);
function integer clog2b(
input integer depth
);
begin
for(clog2b=0; depth>0; clog2b=clog2b+1)begin
depth = depth >> 1;
end
end
endfunction
genvar i;
localparam IMG_WIDTH_4x = (IMG_WIDTH>>2);
wire
line_valid;
wire [24*6-1:0]
last_line_buffer;
wire [24*6-1:0]
cur_line_buffer ;
wire [24*6-1:0]
next_line_buffer;
reg [23:0]
matrix03, matrix04, matrix05, matrix06, matrix07, matrix08 ;
reg [23:0]
matrix13, matrix14, matrix15, matrix16, matrix17, matrix18 ;
reg [23:0]
matrix23, matrix24, matrix25, matrix26, matrix27, matrix28 ;
wire
tuser,tlast;
image_line_buffer_denoise#(
.IMG_WIDTH (IMG_WIDTH ) ,
.IMG_HEIGHT(IMG_HEIGHT)
)image_line_buffer_denoise_d(
/*input
*/.I_clk
(I_clk
),
/*input
*/.I_rst_n
(I_rst_n
),
.I_tuser
(I_tuser
),
.I_tlast
(I_tlast
),
/*input wire
*/.I_tvalid
(I_tvalid
),
/*input wire [95:0]
*/.I_tdata
(I_tdata
),
/*output
*/.O_tlast
(tlast
),
.O_tuser
(tuser
),
reg
/*output reg
*/.O_tvalid
(line_valid
),
/*output reg [24*6-1:0] */.last_line_data
(last_line_buffer),
/*output reg [24*6-1:0] */.cur_line_data
(cur_line_buffer ),
/*output reg [24*6-1:0] */.next_line_data
(next_line_buffer)
);
第 174页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
// 重置 c 数组
{matrix03, matrix04, matrix05, matrix06, matrix07, matrix08} <= 0;
{matrix13, matrix14, matrix15, matrix16, matrix17, matrix18} <= 0;
{matrix23, matrix24, matrix25, matrix26, matrix27, matrix28} <= 0;
end
else if(line_valid)begin
{matrix03, matrix04, matrix05, matrix06, matrix07, matrix08} <= last_line_buffer;
{matrix13, matrix14, matrix15, matrix16, matrix17, matrix18} <= cur_line_buffer ;
{matrix23, matrix24, matrix25, matrix26, matrix27, matrix28} <= next_line_buffer;
end
end
reg [3:0]
tlast_d;
reg [3:0]
tuser_d;
reg [3:0]
tvalid_d;
reg [12:0] R_sum1[3:0], G_sum1[3:0], B_sum1[3:0];
reg [12:0] R_sum2[3:0], G_sum2[3:0], B_sum2[3:0];
reg [12:0] R_sum3[3:0], G_sum3[3:0], B_sum3[3:0];
reg [13:0] R_sum[3:0], G_sum[3:0], B_sum[3:0];
reg [7:0]
R_new[3:0], G_new[3:0], B_new[3:0];
wire [7:0] R1[3:0], G1[3:0], B1[3:0];
wire [7:0] R2[3:0], G2[3:0], B2[3:0];
wire [7:0] R3[3:0], G3[3:0], B3[3:0];
wire [7:0] R4[3:0], G4[3:0], B4[3:0];
wire [7:0] R5[3:0], G5[3:0], B5[3:0];
wire [7:0] R6[3:0], G6[3:0], B6[3:0];
wire [7:0] R7[3:0], G7[3:0], B7[3:0];
wire [7:0] R8[3:0], G8[3:0], B8[3:0];
wire [7:0] R9[3:0], G9[3:0], B9[3:0];
assign {R1[0], G1[0], B1[0]} = matrix03;
assign {R2[0], G2[0], B2[0]} = matrix04;
assign {R3[0], G3[0], B3[0]} = matrix05;
assign {R4[0], G4[0], B4[0]} = matrix13;
assign {R5[0], G5[0], B5[0]} = matrix14;
assign {R6[0], G6[0], B6[0]} = matrix15;
assign {R7[0], G7[0], B7[0]} = matrix23;
assign {R8[0], G8[0], B8[0]} = matrix24;
assign {R9[0], G9[0], B9[0]} = matrix25;
assign {R1[1], G1[1], B1[1]} = matrix04;
assign {R2[1], G2[1], B2[1]} = matrix05;
assign {R3[1], G3[1], B3[1]} = matrix06;
assign {R4[1], G4[1], B4[1]} = matrix14;
assign {R5[1], G5[1], B5[1]} = matrix15;
assign {R6[1], G6[1], B6[1]} = matrix16;
第 175页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
assign {R7[1], G7[1], B7[1]} = matrix24;
assign {R8[1], G8[1], B8[1]} = matrix25;
assign {R9[1], G9[1], B9[1]} = matrix26;
assign {R1[2], G1[2], B1[2]} = matrix05;
assign {R2[2], G2[2], B2[2]} = matrix06;
assign {R3[2], G3[2], B3[2]} = matrix07;
assign {R4[2], G4[2], B4[2]} = matrix15;
assign {R5[2], G5[2], B5[2]} = matrix16;
assign {R6[2], G6[2], B6[2]} = matrix17;
assign {R7[2], G7[2], B7[2]} = matrix25;
assign {R8[2], G8[2], B8[2]} = matrix26;
assign {R9[2], G9[2], B9[2]} = matrix27;
assign {R1[3], G1[3], B1[3]} = matrix06;
assign {R2[3], G2[3], B2[3]} = matrix07;
assign {R3[3], G3[3], B3[3]} = matrix08;
assign {R4[3], G4[3], B4[3]} = matrix16;
assign {R5[3], G5[3], B5[3]} = matrix17;
assign {R6[3], G6[3], B6[3]} = matrix18;
assign {R7[3], G7[3], B7[3]} = matrix26;
assign {R8[3], G8[3], B8[3]} = matrix27;
assign {R9[3], G9[3], B9[3]} = matrix28;
/////////////////////////////矩阵计算
//矩阵模板:
//
1 4
1
//
4 12 4
//
1 4
1
//为了防止生成的图像产生过高的延迟,采用多级处理
generate
for(i = 0; i < 4; i = i + 1)
begin: sharpening
//矩阵计算
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R_sum1[i], G_sum1[i], B_sum1[i]} <= 0;
{R_sum2[i], G_sum2[i], B_sum2[i]} <= 0;
{R_sum3[i], G_sum3[i], B_sum3[i]} <= 0;
end
else if(tvalid_d[0])begin
R_sum1[i] <= R1[i] + {R2[i],{2{1'b0}}} + R3[i];
R_sum2[i] <= {R4[i],{2{1'b0}}} + {R5[i],{3{1'b0}}} + {R5[i],{2{1'b0}}} +
{R6[i],{2{1'b0}}};
R_sum3[i] <= R7[i] + {R8[i],{2{1'b0}}} + R9[i];
G_sum1[i] <= G1[i] + {G2[i],{2{1'b0}}} + G3[i];
G_sum2[i] <= {G4[i],{2{1'b0}}} + {G5[i],{3{1'b0}}} + {G5[i],{2{1'b0}}} +
{G6[i],{2{1'b0}}};
第 176页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
G_sum3[i] <= G7[i] + {G8[i],{2{1'b0}}} + G9[i];
B_sum1[i] <= B1[i] + {B2[i],{2{1'b0}}} + B3[i];
B_sum2[i] <= {B4[i],{2{1'b0}}} + {B5[i],{3{1'b0}}} + {B5[i],{2{1'b0}}} +
{B6[i],{2{1'b0}}};
B_sum3[i] <= B7[i] + {B8[i],{2{1'b0}}} + B9[i];
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R_sum[i], G_sum[i], B_sum[i]} <= 0;
end
else if(tvalid_d[1])begin
R_sum[i] <= R_sum1[i] + R_sum2[i] + R_sum3[i];
G_sum[i] <= G_sum1[i] + G_sum2[i] + G_sum3[i];
B_sum[i] <= B_sum1[i] + B_sum2[i] + B_sum3[i];
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R_new[i], G_new[i], B_new[i]} <= 0;
end
else if(tvalid_d[2])begin
R_new[i] <= R_sum[i][13]?255:R_sum[i][12:5];
G_new[i] <= G_sum[i][13]?255:G_sum[i][12:5];
B_new[i] <= B_sum[i][13]?255:B_sum[i][12:5];
end
end
end
endgenerate
// 输出数据
assign O_tdata = {R_new[0],G_new[0],B_new[0],
R_new[1],G_new[1],B_new[1],
R_new[2],G_new[2],B_new[2],
R_new[3],G_new[3],B_new[3]};
//同步信号
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{tlast_d,tuser_d,tvalid_d} <= 0;
else begin
tlast_d <= {tlast_d[2:0],tlast};
tuser_d <= {tuser_d[2:0],tuser};
tvalid_d <= {tvalid_d[2:0],line_valid};
end
end
assign
O_tlast
= tlast_d[3];
assign
O_tuser
= tuser_d[3];
第 177页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
assign
O_tvalid
assign
I_tready = O_tready;
Image processing course advanced(2024)
= tvalid_d[3];
endmodule
10.3.3Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
// Define the image resolution here
// `define RESOLUTION_300_220
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/002.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
第 178页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_300_220
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
`define VERTICAL_BLANKING 40
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_test();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
第 179页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
第 180页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
第 181页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
denoise_gaussian #(
.IMG_WIDTH
(`IMAGE_WIDTH),
.IMG_HEIGHT (`IMAGE_HEIGHT)
)
denoise_gaussian(
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
第 182页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
第 183页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
], green_channel[memory_address
]};
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
第 184页
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
10.4 仿真及结果
10.4.1 仿真时序图结果
第 185页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
10.4.2 仿真图片结果
左边的图是把右边的图加上噪点所得的,这个过程是用 python 去实现,具体实现在 10.5 有提到。
这个是一个时钟周期传输 4 个 RGB 的,可以看见,这个左边的图是原图,右边的图是经过滤波后的图,滤波的效
果还是可以的,但是整个图像是模糊的了,这个是使用了高斯滤波所呈现的模糊效果,一般会在后面加入锐化算法,
进行清晰化,对于锐化算法,在下文也有讲述,也是根据相应的滤波去进行锐化的,当然可使用的卷积核还有很多,
读者可以自己尝试。
10.5 上板结果
此工程也是只加入了 ISP 中的去马赛克算法和白平衡算法,现加入去噪算法,一共三个算法组成,这里用的去
噪算法是一次传输 4 个 RGB 的数据,若读者觉得资源占用太大,可以把一个时钟传输 4 个像素点改成一个时钟传
输 1 个像素点的值,在 demo 里面包含了一个时钟传输一个像素点的 demo,读者可以去试试。
图片细看有些许毛刺,所以一般不是噪点比较明显的图像,都不太建议使用这个去噪,如果对一些要求比较高
的图像可以选择去专门设计一个对应的去噪的算法。
第 186页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见,这个图整体的样子还是可以的,但是看起来有点模糊了,这个就是滤波过度了所造成的。所以一般
是根据噪声的特点去设置合适的滤波进行处理的。
10.6Python 实现
Phthon 实现的大致步骤:
1.读取输入图像,并转换为 RGB 格式。
2.添加盐椒噪声,得到带噪声的图像 noisy_image。
3.将带噪声的图像 noisy_image 保存为 BMP 格式文件 noisy_image.bmp。
4.对带噪声的图像进行中值滤波,得到去噪后的图像 denoised_image。
5.将去噪后的图像 denoised_image 保存为 BMP 格式文件 denoised_image.bmp。
6.使用 matplotlib 显示原始图像、带噪声图像和去噪后的图像。
读者可以自己找一个任意的图片,去给它通过 Python 添加噪点,然后再进行算法处理。
10.6.1Python 代码实现
import cv2
import numpy as np
def add_noise(img):
# 添加随机噪声
row, col, ch = img.shape
mean = 0
sigma = 25
gauss = np.random.normal(mean, sigma, (row, col, ch))
gauss = gauss.reshape(row, col, ch)
noisy = img + gauss
noisy = np.clip(noisy, 0, 255).astype(np.uint8)
return noisy
第 187页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
def gaussian_blur(img):
# 使用高斯滤波去噪
blur = cv2.GaussianBlur(img, (5, 5), 0)
return blur
def main():
# 读取图片
img = cv2.imread('001.bmp')
# 生成噪声图片
noisy_img = add_noise(img)
# 保存噪声图片为 BMP 格式
cv2.imwrite('noisy_image.bmp', noisy_img)
# 去噪
denoised_img = gaussian_blur(noisy_img)
# 保存去噪后的图片为 BMP 格式
cv2.imwrite('denoised_image.bmp', denoised_img)
# 显示图片
cv2.imshow('Original', img)
cv2.imshow('Noisy', noisy_img)
cv2.imshow('Denoised', denoised_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
10.6.2 结果展示
原图像:
第 188页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
加入噪点后的图像:
经过 python 的中值滤波去噪后的图像:
第 189页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
11.FPGA 实现图像自动曝光算法
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
11.1 图像自动曝光算法简介
FPGA 自动曝光算法是一种在 FPGA 上实现的图像处理技术,旨在自动调整摄像头或图像传感器的曝光时间,
以获得最佳图像亮度,它的目标就是是使图像的亮度适中,不出现过曝(图像过亮)或欠曝(图像过暗),从而提高
图像质量。
可以看见下面三个图,左边的图欠曝,中间的图是正常的,右边的图是过曝了,这时候我们就需要用到曝光控
制算法去对它的曝光进行控制,以便达到人眼正常所能接受的程度。
11.2 自动曝光算法原理
正常来说控制曝光算法是在传感器层面进行的,通过对曝光时间的影响,来调整曝光,但是现在是直接用的一
个已经做好的摄像头去进行图像处理,所以就只能采用其他的方法了,此算法是作者综合考虑写出来的一种资源消
耗中等的自动曝光算法,下面讲讲它的具体实现步骤:
首先直把 RGB 转 YUV,把其中的 Y(亮度)单独提取出来,对亮度进行判断并且计算,然后再把它转回 RGB。
RGB 转 YUV 和 YUV 转 RGB 在第二章的时候就已经讲述过了,此处就不在赘述,详细可以观看第二章内容。
现在重点讲述一下如何去对 Y(亮度)进行处理,已到达一个自动曝光的效果,首先求出平均亮度,设置好所
需要的采样帧数,并且对平均亮度进行判断,判断它是否是过曝,不同的场景有不同的应用,读者可以自己试一试
去调试自己想要的范围,这里有一个非常重要的一点,就是在进行采样的时候,如果每次采样帧数达到都把像素点
的值的和和像素点的个数和还原为 0,这个时候就相当于要重新进行累加,也就是重新进行曝光算法,这样会导致
呈现的图片出现非常大的波动,这里作者采用了双通道计算,其中一个在每次采样帧数达到一半的时候赋 0,也就
是说它达到采样帧数的时候,并不为 0,而是进行了一半采样帧数的一个累加值的运算,这个时候把这个值赋给另
外一个正常计算的值,就不会让另外一个值变为 0 了,也就可以达到一个一直的去判断曝光,并且解决曝光的良性
第 190页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
循环。
当然对是否曝光的判断我们还有其他很多方法,比如图像对比度分析、灰度累积分布函数(CDF)分析、感兴
趣区域(ROI)分析等等方法,读者都可以去试试这些方法。
11.3 代码分析
11.3.1IP 解析
下面是 AEC 模块的 IP:
上面 IP 的这些信号用于实现 AXI-Stream 接口协议,适用于高效的数据流传输。
输入信号(Input Signals):
I_clk: 时钟信号,用于同步数据传输。
I_rst_n: 复位信号,低电平有效,用于初始化模块。
I_tlast: 表示数据流中最后一个数据的标志信号。
I_tuser: 用户自定义信号,通常用于携带附加信息。
I_tdata[95:0]: 输入数据总线,宽度为 96 位,是由 4 个像素点组成
I_tvalid: 输入数据有效信号,表示当前数据总线上的数据是有效的。
O_tready: 输出就绪信号,表示下游模块已经准备好接收数据。
输出信号(Output Signals):
I_tready: 输入就绪信号,表示当前模块已经准备好接收数据。
O_tlast: 表示输出数据流中最后一个数据的标志信号。
O_tuser: 输出用户自定义信号。
O_tdata[95:0]: 输出数据总线,宽度为 96 位,是由 4 个像素点组成
O_tvalid: 输出数据有效信号,表示当前输出数据总线上的数据是有效的。
第 191页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
这个是采样帧率的选择,读者尽量选择在所用摄像头帧率以下的采样帧数,不宜过大,这样会导致采样不准确
且计算缓慢。
11.3.2Verilog Design 代码分析
源代码如下:
module AEC #(
parameter [6:0]
FRAME_SAMPLING = 6'd20
// 閲囨牱甯ф暟
)
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
I_tdata
,
input
[95:0]
,
input
I_tvalid ,
output
I_tready ,
output
O_tlast
,
output
O_tuser
,
output [95:0]
O_tdata
,
第 192页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
output
O_tvalid ,
input
O_tready
);
/*****************************************************************
24deta to RGB888
*****************************************************************/
wire [23:0] I_tdata_r1 = I_tdata[23:0] ;
wire [23:0] I_tdata_r2 = I_tdata[47:24];
wire [23:0] I_tdata_r3 = I_tdata[71:48];
wire [23:0] I_tdata_r4 = I_tdata[95:72];
wire [7:0]
rgb888_r[3:0];
wire [7:0]
rgb888_g[3:0];
wire [7:0]
rgb888_b[3:0];
assign
rgb888_r[0] = I_tdata_r1[16+:8];
assign
rgb888_g[0] = I_tdata_r1[8+:8] ;
assign
rgb888_b[0] = I_tdata_r1[0+:8] ;
assign
rgb888_r[1] = I_tdata_r2[16+:8];
assign
rgb888_g[1] = I_tdata_r2[8+:8] ;
assign
rgb888_b[1] = I_tdata_r2[0+:8] ;
assign
rgb888_r[2] = I_tdata_r3[16+:8];
assign
rgb888_g[2] = I_tdata_r3[8+:8] ;
assign
rgb888_b[2] = I_tdata_r3[0+:8] ;
assign
rgb888_r[3] = I_tdata_r4[16+:8];
assign
rgb888_g[3] = I_tdata_r4[8+:8] ;
assign
rgb888_b[3] = I_tdata_r4[0+:8] ;
/*****************************************************************
signals declaration
*****************************************************************/
reg
[8:0]
I_tlast_r
;
reg
[8:0]
I_tuser_r
;
reg
[8:0]
I_tvalid_r
;
localparam
N = 3;
reg
[17:0]
Y_red[N:0]
reg
[17:0]
Y_green[N:0],U_green[N:0],V_green[N:0];
reg
[17:0]
Y_blue[N:0] ,U_blue[N:0] ,V_blue[N:0] ;
reg
[17:0] Y_r0[N:0];
reg
[17:0] U_r0[N:0];
,U_red[N:0]
,V_red[N:0]
第 193页
;
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
reg
[17:0] V_r0[N:0];
reg
[7:0]
Y[N:0];
reg
[9:0]
Y_d0[N:0];
reg
[7:0]
Y_d1[N:0];
reg
[7:0]
U[N:0];
reg
[7:0]
V[N:0];
reg [17:0] Y_m[N:0];
reg [18:0] R_V_m[N:0];
reg [16:0] G_U_m[N:0];
reg [17:0] G_V_m[N:0];
reg [18:0] B_U_m[N:0];
reg [19:0] R_s[N:0];
reg [19:0] G_s[N:0];
reg [19:0] B_s[N:0];
reg [7:0] R[N:0];
reg [7:0] G[N:0];
reg [7:0] B[N:0];
reg [31:0]
pixel_cnt[N:0];
reg [39:0]
Y_count[N:0];
reg [31:0]
pixel_cnt_d1[N:0];
reg [39:0]
Y_count_d1[N:0];
wire [71:0] dout[N:0];
wire [7:0]
Y_avg[N:0];//骞冲潎浜
害
reg [6:0] v_cnt;
parameter d0 = 11'd1436;//1.402*1024;
parameter d1 = 9'd352;//0.344*1024;
parameter d2 = 10'd731;//0.714*1024;
parameter d3 = 11'd1814;//1.772*1024;
parameter R_BASE = 18'd183763;//1.402*128*1024
parameter G_BASE = 18'd138674;//1.058*128*1024
parameter B_BASE = 18'd232260;//1.772*128*1024
parameter C0 = 9'd306;//0.299*1024;
parameter C1 = 10'd601;//0.587*1024;
parameter C2 = 7'd117;//0.114*1024;
第 194页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
parameter C3 = 8'd173;//0.169*1024;
parameter C4 = 9'd339;//0.331*1024;
parameter C5 = 10'd512;//0.5*1024;
parameter C6 = 10'd512;//0.5*1024;
parameter C7 = 9'd429;//0.419*1024;
parameter C8 = 7'd83;//0.081*1024;
parameter BASE = 128*1024;
/*****************************************************************
RGB2YUV
*****************************************************************/
genvar i;
generate for (i = 0;i<4 ;i=i+1 ) begin
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y_red [i] <= 0;
Y_green[i] <= 0;
Y_blue [i] <= 0;
U_red [i] <= 0;
U_green[i] <= 0;
U_blue [i] <= 0;
V_red [i] <= 0;
V_green[i] <= 0;
V_blue [i] <= 0;
end
else if(I_tvalid)begin
Y_red
[i] <= rgb888_r[i] * C0;
Y_green[i] <= rgb888_g[i] * C1;
Y_blue [i] <= rgb888_b[i] * C2;
U_red
[i] <= rgb888_r[i] * C3;
U_green[i] <= rgb888_g[i] * C4;
U_blue [i] <= rgb888_b[i] * C5;
V_red
[i] <= rgb888_r[i] * C6;
V_green[i] <= rgb888_g[i] * C7;
V_blue [i] <= rgb888_b[i] * C8;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y_r0[i]
<= 18'd0 ;
U_r0[i]
<= 18'd0 ;
V_r0[i]
<= 18'd0 ;
第 195页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
end
else if(I_tvalid_r[0])begin
Y_r0[i] <= Y_red[i]
+ Y_green[i] + Y_blue[i] ;
U_r0[i] <= U_blue[i] - U_red[i]
V_r0[i] <= V_red[i]
- U_green[i] + BASE;
- V_green[i] - V_blue[i]
+ BASE;
end
End
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y[i] <= 0;
U[i] <= 0;
V[i] <= 0;
end
else if(I_tvalid_r[1])begin
Y[i] <= Y_r0[i][17:10];
U[i] <= U_r0[i][17:10];
V[i] <= V_r0[i][17:10];
end
end
/*****************************************************************
Calculation description
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
pixel_cnt[i] <= 0;
Y_count
[i] <= 0;
end
else if (v_cnt == FRAME_SAMPLING)begin
pixel_cnt[i] <= pixel_cnt_d1[i];
Y_count
[i] <= Y_count_d1
[i];
end
else if(I_tvalid_r[2])begin
pixel_cnt[i] <= pixel_cnt[i] + 1;
Y_count
[i] <= Y_count[i] + Y[i];
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
pixel_cnt_d1[i] <= 0;
Y_count_d1 [i] <= 0;
end
else if(v_cnt == (FRAME_SAMPLING>>1))begin
pixel_cnt_d1[i] <= 0;
Y_count_d1 [i] <= 0;
end
第 196页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
else if(I_tvalid_r[2])begin
pixel_cnt_d1[i] <= pixel_cnt_d1[i] + 1;
Y_count_d1 [i] <= Y_count_d1[i] + Y[i];
end
end
div_gen_AEC your_instance_name (
// input wire aclk
.aclk(I_clk),
// input wire s_axis_divisor_tvalid
.s_axis_divisor_tvalid(I_tvalid_r[3]),
.s_axis_divisor_tdata(pixel_cnt[i]),
// input wire [31 : 0] s_axis_divisor_tdata
.s_axis_dividend_tvalid(I_tvalid_r[3]),
// input wire s_axis_dividend_tvalid
.s_axis_dividend_tdata(Y_count[i]),
.m_axis_dout_tvalid(),
// input wire [39 : 0] s_axis_dividend_tdata
// output wire m_axis_dout_tvalid
.m_axis_dout_tdata(dout[i])
// output wire [71 : 0] m_axis_dout_tdata
);
assign Y_avg[i] = dout[i][39:32];
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
Y_d0[i] <= 0;
end
else if(I_tvalid_r[4])begin
if(Y_avg[i] < 100 && Y_avg[i] > 80)begin
Y_d0[i] <= Y[i] + 20;
end
else if(Y_avg[i] <= 80 && Y_avg[i] > 60)begin
Y_d0[i] <= Y[i] + 35;
end
else if(Y_avg[i] <= 60 && Y_avg[i] > 30)begin
Y_d0[i] <= Y[i] + 50;
end
else if(Y_avg[i] < 255 && Y_avg[i] >= 220)begin
Y_d0[i] <= Y[i] - 50;
end
else if(Y_avg[i] < 220 && Y_avg[i] >= 200)begin
Y_d0[i] <= Y[i] - 40;
end
else if(Y_avg[i] < 200 && Y_avg[i] >= 180)begin
Y_d0[i] <= Y[i] - 30;
end
else if(Y_avg[i] < 180 && Y_avg[i] >= 160)begin
Y_d0[i] <= Y[i] - 10;
end
else begin
Y_d0[i] <= Y[i];
end
end
end
第 197页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
Y_d1[i] <= 0;
end
else begin
Y_d1[i] <= (Y_d0[i][9]) ? 0:((Y_d0[i][8])?255:Y_d0[i]);
end
end
/*****************************************************************
YUV2RGB
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
Y_m[i]
<= 0;
R_V_m[i] <= 0;
G_U_m[i] <= 0;
G_V_m[i] <= 'b0;
B_U_m[i] <= 'b0;
end else begin
if(I_tvalid_r[5]) begin
Y_m[i]
<= {Y_d1[i],10'b0};
R_V_m[i] <= V[i]*d0;
G_U_m[i] <= U[i]*d1;
G_V_m[i] <= V[i]*d2;
B_U_m[i] <= U[i]*d3;
end
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R_s[i], G_s[i], B_s[i]} <= 0;
end
else if(I_tvalid_r[6]) begin
R_s[i] <= Y_m[i] + R_V_m[i] - R_BASE;
G_s[i] <= Y_m[i] - G_U_m[i] - G_V_m[i] + G_BASE;
B_s[i] <= Y_m[i] + B_U_m[i] - B_BASE;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R[i], G[i], B[i]} <= 0;
end
else if(I_tvalid_r[7]) begin
R[i] <= R_s[i][19] ? 'b0 : R_s[i][18] ? 'd255 : R_s[i][17:10];
G[i] <= G_s[i][19] ? 'b0 : G_s[i][18] ? 'd255 : G_s[i][17:10];
第 198页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
B[i] <= B_s[i][19] ? 'b0 : B_s[i][18] ? 'd255 : B_s[i][17:10];
end
end
end
endgenerate
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
v_cnt <= 0;
end
else if(I_tuser)begin
v_cnt <= v_cnt + 1;
end
else if(v_cnt == FRAME_SAMPLING)
v_cnt <= 0;
end
/*****************************************************************
Signal synchronization
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[7:0],I_tlast};
I_tuser_r <= {I_tuser_r[7:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[7:0],I_tvalid};
end
end
assign
O_tlast
= I_tlast_r[8];
assign
O_tuser
= I_tuser_r[8];
assign
O_tvalid = I_tvalid_r[8];
assign O_tdata = {R[3],G[3],B[3],
R[2],G[2],B[2],
R[1],G[1],B[1],
R[0],G[0],B[0]};
assign I_tready = O_tready;
endmodule
第 199页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
11.3.3Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
// Define the image resolution here
// `define RESOLUTION_300_220
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_300_220
第 200页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
`define VERTICAL_BLANKING 40
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_tb();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
第 201页
Image processing course advanced(2024)
常州米联客信息科技有限公司
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
第 202页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
第 203页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
AEC#(
.FRAME_SAMPLING (20)
) AEC (
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
第 204页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
], green_channel[memory_address
]};
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
第 205页
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
第 206页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
11.4 仿真结果
11.4.1 仿真波形图结果
第 207页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
11.4.2 仿真图结果
左边的图为原图,右边的图为仿真过后的图,可以发现右边的图明显要暗一点,说明去曝成功了,图片中一些
色彩误差和条纹是由于这个图是第一帧数据导致,如果上板,则不会出现这样的现象,可以在后续的帧缓存模块中,
去掉前几帧图像即可。
11.5 上板结果
此工程也是只加入了 ISP 中的去马赛克算法和白平衡算法,现加入 AEC 算法,一共三个算法组成,若读者觉
得资源占用太大,可以把一个时钟传输 4 个像素点改成一个时钟传输 1 个像素点的值,明白了 gamma 的原理,举
一反三即可.
第 208页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见这个整体的曝光算法并不是很好,因为其实大部分自动曝光算法都是对于传感器层面去进行的,所以
像这样强行摄像头外部进行算法优化,是难以做到更好的效果的,当然也不是做不到,只是需要更高级的算法去进
行计算,但是那样所需要的消耗资源就太多了,非常不划算,不过读者可以试试其他方法,比如以灰度代表亮度或
者用直方图统计法去判断亮度,这些都可以让曝光算法更为精细。
11.6Python 实现
11.6.1 代码实现
from PIL import Image, ImageEnhance
import numpy as np
def auto_exposure(input_image_path, output_image_path):
"""
Adjust the brightness of an image automatically and save the output as a BMP file.
:param input_image_path: str, path to the input image
:param output_image_path: str, path to save the output image in BMP format
"""
# Open an image file
with Image.open(input_image_path) as img:
# Convert image to grayscale for analysis
grayscale_img = img.convert("L")
# Convert to numpy array for processing
img_array = np.array(grayscale_img)
# Calculate the mean brightness
mean_brightness = np.mean(img_array)
第 209页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
# Define the target brightness (e.g., 128 for 8-bit images)
target_brightness = 190
# Calculate the brightness factor
brightness_factor = target_brightness / mean_brightness
# Create an ImageEnhance object
enhancer = ImageEnhance.Brightness(img)
# Adjust brightness
img_enhanced = enhancer.enhance(brightness_factor)
# Save the modified image in BMP format
img_enhanced.save(output_image_path, format='BMP')
print(f"Image saved as BMP to {output_image_path}")
# Example usage:
input_path = '002.bmp'
# Replace with your input image path
output_path = 'output.bmp'
# Desired output image path in BMP format
auto_exposure(input_path, output_path)
11.6.2 结果展示
原图像:
经过曝光控制的图像:
第 210页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见这个图像明显暗淡了很多,但是又过于暗淡了,读者可以根据自己想要的亮度去调节。
第 211页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
12.FPGA 实现图像对比度调节
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
12.1 图像对比度调节简介
对比度是图像处理中一个重要的属性,它描述了图像中明暗区域之间的差异程度。高对比度的图像通常具有更
明显的明暗对比,细节更为突出,而低对比度的图像则显得更为平坦和灰暗。调整对比度可以改善图像的视觉效果,
使得图像中的细节更加清晰。
12.2 原理分析
对比度调节的方法也是多种多样,考虑到资源问题,且对比度调节也不是属于 ISP 最核心部分,所以此处采用
了计算量较小的线性调节,就是通过同比例乘 RGB 三通道的值去改变图像的对比度。
12.3 代码分析
12.3.1IP 解析
这个是对比度调节的 IP
上面 IP 的这些信号用于实现 AXI-Stream 接口协议,适用于高效的数据流传输。
输入信号(Input Signals):
I_clk: 时钟信号,用于同步数据传输。
I_rst_n: 复位信号,低电平有效,用于初始化模块。
I_tlast: 表示数据流中最后一个数据的标志信号。
I_tuser: 用户自定义信号,通常用于携带附加信息。
I_tdata[95:0]: 输入数据总线,宽度为 96 位,是由 4 个像素点组成
I_tvalid: 输入数据有效信号,表示当前数据总线上的数据是有效的。
O_tready: 输出就绪信号,表示下游模块已经准备好接收数据。
输出信号(Output Signals):
I_tready: 输入就绪信号,表示当前模块已经准备好接收数据。
O_tlast: 表示输出数据流中最后一个数据的标志信号。
第 212页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
O_tuser: 输出用户自定义信号。
O_tdata[95:0]: 输出数据总线,宽度为 96 位,是由 4 个像素点组成
O_tvalid: 输出数据有效信号,表示当前输出数据总线上的数据是有效的。
这里可以自由调节图像的对比度,范围在 0-255,以 128 为中间值,也就是 1,小于 128,则对比度降低,大于 128,
则对比度加强
12.3.2Verilog Design 代码分析
源代码如下:
module contrast_adj #(
parameter contrast_level
= 160 //对比度调节因子,定点数表示,128 对应 1.0
)
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
I_tdata
,
input
[95:0]
,
input
I_tvalid ,
output
I_tready ,
第 213页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
output
O_tlast
,
output
O_tuser
,
output [95:0]
O_tdata
,
output
O_tvalid ,
input
O_tready
);
/*****************************************************************
24deta to RGB888
*****************************************************************/
reg [2:0]
I_tlast_r ;
reg [2:0]
I_tuser_r ;
reg [2:0]
I_tvalid_r;
wire [23:0] I_tdata_r1 = I_tdata[23:0] ;
wire [23:0] I_tdata_r2 = I_tdata[47:24];
wire [23:0] I_tdata_r3 = I_tdata[71:48];
wire [23:0] I_tdata_r4 = I_tdata[95:72];
wire [7:0]
rgb888_r[3:0];
wire [7:0]
rgb888_g[3:0];
wire [7:0]
rgb888_b[3:0];
reg [9:0]
R_d[3:0];
reg [9:0]
G_d[3:0];
reg [9:0]
B_d[3:0];
wire [7:0]
R[3:0];
wire [7:0]
G[3:0];
wire [7:0]
B[3:0];
reg [15:0] pixel_shifted_R[3:0];
reg [15:0] pixel_shifted_G[3:0];
reg [15:0] pixel_shifted_B[3:0];
reg [15:0] temp_value_R[3:0];
reg [15:0] temp_value_G[3:0];
reg [15:0] temp_value_B[3:0];
assign
rgb888_r[0] = I_tdata_r1[16+:8];
assign
rgb888_g[0] = I_tdata_r1[8+:8] ;
assign
rgb888_b[0] = I_tdata_r1[0+:8] ;
assign
rgb888_r[1] = I_tdata_r2[16+:8];
assign
rgb888_g[1] = I_tdata_r2[8+:8] ;
assign
rgb888_b[1] = I_tdata_r2[0+:8] ;
assign
rgb888_r[2] = I_tdata_r3[16+:8];
第 214页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
assign
rgb888_g[2] = I_tdata_r3[8+:8] ;
assign
rgb888_b[2] = I_tdata_r3[0+:8] ;
assign
rgb888_r[3] = I_tdata_r4[16+:8];
assign
rgb888_g[3] = I_tdata_r4[8+:8] ;
assign
rgb888_b[3] = I_tdata_r4[0+:8] ;
Image processing course advanced(2024)
/*****************************************************************
Calculation description
*****************************************************************/
genvar i ;
generate for (i = 0;i<4 ;i=i+1 ) begin
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
pixel_shifted_R[i] <= 0;
pixel_shifted_G[i] <= 0;
pixel_shifted_B[i] <= 0;
end
else if(I_tvalid)begin
pixel_shifted_R[i] <= {8'd0, rgb888_r[i]} - 16'd128;
pixel_shifted_G[i] <= {8'd0, rgb888_g[i]} - 16'd128;
pixel_shifted_B[i] <= {8'd0, rgb888_b[i]} - 16'd128;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
temp_value_R[i] <= 0;
temp_value_G[i] <= 0;
temp_value_B[i] <= 0;
end
else if(I_tvalid_r[0])begin
temp_value_R[i] <= (pixel_shifted_R[i] * contrast_level)>>7;// 由于 contrast_level 是
定点数(Q0.7 格式),需要右移 7 位
temp_value_G[i] <= (pixel_shifted_G[i] * contrast_level)>>7;
temp_value_B[i] <= (pixel_shifted_B[i] * contrast_level)>>7;
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
R_d[i] <= 0;
G_d[i] <= 0;
B_d[i] <= 0;
end
else if(I_tvalid_r[1])begin
R_d[i] <= temp_value_R[i] + 16'd128;// 由于 contrast_level 是定点数(Q0.7 格式),需要右
第 215页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
移7位
G_d[i] <= temp_value_G[i] + 16'd128;
B_d[i] <= temp_value_B[i] + 16'd128;
end
end
assign
R[i] = (R_d[i][9])?0:(R_d[i][8])?255:R_d[i][7:0];
assign
G[i] = (G_d[i][9])?0:(G_d[i][8])?255:G_d[i][7:0];
assign
B[i] = (B_d[i][9])?0:(B_d[i][8])?255:B_d[i][7:0];
end
endgenerate
/*****************************************************************
Signal synchronization
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[1:0],I_tlast};
I_tuser_r <= {I_tuser_r[1:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[1:0],I_tvalid};
end
end
assign
O_tlast
= I_tlast_r[2];
assign
O_tuser
= I_tuser_r[2];
assign
O_tvalid = I_tvalid_r[2];
assign O_tdata = {R[3],G[3],B[3],
R[2],G[2],B[2],
R[1],G[1],B[1],
R[0],G[0],B[0]};
assign I_tready = O_tready;
endmodule
12.3.3Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
第 216页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
// Define the image resolution here
// `define RESOLUTION_300_220
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_300_220
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
`define VERTICAL_BLANKING 40
`endif
第 217页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_test();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tready;
wire
O_tlast;
第 218页
Image processing course advanced(2024)
常州米联客信息科技有限公司
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
第 219页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
第 220页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
end
// Instantiate the RGB to HSV conversion module
Saturation_adj #(
.contrast_level (160 )
)
Saturation_adj(
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
第 221页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
], green_channel[memory_address
]};
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
第 222页
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
12.4 仿真结果
12.4.1 仿真波形图结果
第 223页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 224页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
12.4.2 仿真图片结果
左边的图为原图,右边的图为对比度加强的图,可以发现,对比度加强之后,人物和景色变得更加鲜活了,
该算法的整体效果还是不错的。
12.5 上板结果
此工程也是只加入了 ISP 中的去马赛克算法和白平衡算法,现加入亮度调节,一共三个算法组成,若读者觉得
资源占用太大,可以把一个时钟传输 4 个像素点改成一个时钟传输 1 个像素点的值,明白了 gamma 的原理,举一
反三即可。
第 225页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见,这个对比度调节的效果非常不错的,作者在此处设置对比度的大小为 160,从比例上来说,是原基
础的 1.25 倍,这个算法呈现的整体效果还是非常不错的。
12.6Python 实现
12.6.1Python 代码
from PIL import Image, ImageEnhance
def adjust_contrast(input_image_path, output_image_path, contrast_factor):
"""
Adjust the contrast of an image and save the output as a BMP file.
:param input_image_path: str, path to the input image
:param output_image_path: str, path to save the output image in BMP format
:param contrast_factor: float, a number where 1 means original contrast,
<1 means lower contrast, and >1 means higher contrast
"""
# Open an image file
with Image.open(input_image_path) as img:
# Create an ImageEnhance object for contrast
enhancer = ImageEnhance.Contrast(img)
# Adjust contrast
img_enhanced = enhancer.enhance(contrast_factor)
# Save the modified image in BMP format
img_enhanced.save(output_image_path, format='BMP')
print(f"Image saved as BMP to {output_image_path}")
第 226页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
# Example usage:
input_path = '001.bmp'
# Replace with your input image path
output_path = 'output.bmp'
# Desired output image path in BMP format
contrast_factor = 1.5 # Adjust this factor to increase or decrease contrast
adjust_contrast(input_path, output_path, contrast_factor)
在 input_path 后面输入想要放入的图片,contrast_factor 是想要调节的对比度的值.
12.6.2 结果显示
左边的图为原图,右边的图为对比度加强的图,可以发现,用 Python 进行对比度加强之后,人物和景色变得更
加鲜活了,该算法的整体效果还是不错的。
第 227页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
13.FPGA 实现图像饱和度调节
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
13.1 图像饱和度调节简介
图像饱和度是指图像中色彩的强度或纯度。高饱和度的图像颜色鲜艳、生动,而低饱和度的图像则显得灰暗、
平淡,甚至接近黑白。调整图像的饱和度可以显著影响图像的视觉效果和情感表达。
饱和度调节的范围为 0 到 1,值越高表示颜色越纯,越低表示颜色越灰。
饱和度为 0 时,颜色是灰色(无色相)。
13.2 算法原理
它的方法有很多,例如 HSV/HSL 的颜色空间调节方法、灰度图混合法、融合 HSL 和 RGB 颜色空间计算方
法,这里所用的是灰度图混合法,计算公式如下:
Y = 0.2989*R + 0.5870*G + 0.1140*B;
R_new = -Y * value + R * (1+value);
G_new = -Y * value + G * (1+value);
B_new = -Y * value + B * (1+value);
value 为调整系数-1~1,当 value 等于 0 时,表示饱和度不做调整,但是为了方便计算和代码实现,我们可以吧
它们扩大到 256,也就是它的范围会在-256 到 256。
13.3 代码分析
13.3.1IP 分析
第 228页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
上面 IP 的这些信号用于实现 AXI-Stream 接口协议,适用于高效的数据流传输。
输入信号(Input Signals):
I_clk: 时钟信号,用于同步数据传输。
I_rst_n: 复位信号,低电平有效,用于初始化模块。
I_tlast: 表示数据流中最后一个数据的标志信号。
I_tuser: 用户自定义信号,通常用于携带附加信息。
I_tdata[95:0]: 输入数据总线,宽度为 96 位,是由 4 个像素点组成
I_tvalid: 输入数据有效信号,表示当前数据总线上的数据是有效的。
O_tready: 输出就绪信号,表示下游模块已经准备好接收数据。
输出信号(Output Signals):
I_tready: 输入就绪信号,表示当前模块已经准备好接收数据。
O_tlast: 表示输出数据流中最后一个数据的标志信号。
O_tuser: 输出用户自定义信号。
O_tdata[95:0]: 输出数据总线,宽度为 96 位,是由 4 个像素点组成
O_tvalid: 输出数据有效信号,表示当前输出数据总线上的数据是有效的。
可以看见,上面我们选择的饱和度是 150,下面会呈现当饱和度为 150 的时候,图像的样貌。
13.3.2Verilog Design 代码分析
源代码如下:
/*****************************************************************
@Description :
第 229页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Y = 0.2989*R + 0.5870*G + 0.1140*B;
R_new = -Y * value + R * (1+value);
G_new = -Y * value + G * (1+value);
B_new = -Y * value + B * (1+value);
value = (-1~1)
*****************************************************************/
`timescale 1ns / 1ps
module Saturation_adj#(
ADJUST_VAL = 128
parameter [8:0]
)
(
input
I_clk
input
I_rst_n,
input
I_tlast ,
input
I_tuser ,
input
[95:0]
,
I_tdata ,
input
I_tvalid,
output
I_tready,
output
O_tlast ,
output
O_tuser ,
output [95:0]
O_tdata ,
output
O_tvalid,
input
O_tready
);
/*****************************************************************
24deta to RGB888
*****************************************************************/
wire [23:0] I_tdata_r1 = I_tdata[23:0] ;
wire [23:0] I_tdata_r2 = I_tdata[47:24];
wire [23:0] I_tdata_r3 = I_tdata[71:48];
wire [23:0] I_tdata_r4 = I_tdata[95:72];
wire [7:0]
rgb888_r[3:0];
wire [7:0]
rgb888_g[3:0];
wire [7:0]
rgb888_b[3:0];
assign
rgb888_r[0] = I_tdata_r1[16+:8];
assign
rgb888_g[0] = I_tdata_r1[8+:8] ;
assign
rgb888_b[0] = I_tdata_r1[0+:8] ;
assign
rgb888_r[1] = I_tdata_r2[16+:8];
assign
rgb888_g[1] = I_tdata_r2[8+:8] ;
assign
rgb888_b[1] = I_tdata_r2[0+:8] ;
assign
rgb888_r[2] = I_tdata_r3[16+:8];
第 230页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
assign
rgb888_g[2] = I_tdata_r3[8+:8] ;
assign
rgb888_b[2] = I_tdata_r3[0+:8] ;
assign
rgb888_r[3] = I_tdata_r4[16+:8];
assign
rgb888_g[3] = I_tdata_r4[8+:8] ;
assign
rgb888_b[3] = I_tdata_r4[0+:8] ;
/*****************************************************************
signals declaration
*****************************************************************/
wire [8:0]
adjust_val[3:0];
assign adjust_val[0] = ADJUST_VAL;
assign adjust_val[1] = ADJUST_VAL;
assign adjust_val[2] = ADJUST_VAL;
assign adjust_val[3] = ADJUST_VAL;
reg [3:0]
I_tlast_r ;
reg [3:0]
I_tuser_r ;
reg [3:0]
I_tvalid_r;
reg [16:0]
Y_R_m[3:0];
reg [17:0]
Y_G_m[3:0];
reg [14:0]
Y_B_m[3:0];
reg [7:0]
rgb888_r_r0[3:0];
reg [7:0]
rgb888_g_r0[3:0];
reg [7:0]
rgb888_b_r0[3:0];
reg [8:0]
RGB_C[3:0];
wire [17:0]
Y_w[3:0];
reg [7:0]
Y[3:0];
reg [7:0]
rgb888_r_r1[3:0];
reg [7:0]
rgb888_g_r1[3:0];
reg [7:0]
rgb888_b_r1[3:0];
reg
Y_C_sign[3:0];
reg [7:0]
Y_C_abs[3:0];
reg [16:0]
Y_m[3:0];
reg [16:0]
rgb888_r_r2[3:0];
reg [16:0]
rgb888_g_r2[3:0];
reg [16:0]
rgb888_b_r2[3:0];
wire [18:0] Y_m_s[3:0];
第 231页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
wire [18:0] Y_R_m_s[3:0];
wire [18:0] Y_G_m_s[3:0];
wire [18:0] Y_B_m_s[3:0];
reg [7:0]
R_new[3:0];
reg [7:0]
G_new[3:0];
reg [7:0]
B_new[3:0];
parameter C0 = 9'd306;//0.299*1024;
parameter C1 = 10'd601;//0.587*1024;
parameter C2 = 7'd117;//0.114*1024;
/*****************************************************************
computing declaration
*****************************************************************/
genvar i;
generate
for(i = 0; i < 4; i = i + 1)
begin: computing
//Y=0.299*R 十 0.587*G+0.114*B
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{Y_R_m[i], Y_G_m[i], Y_B_m[i]} <= 0;
{rgb888_r_r0[i], rgb888_g_r0[i], rgb888_b_r0[i]} <= 0;
RGB_C[i] <= 0;
end
else if(I_tvalid)begin
Y_R_m[i] <= rgb888_r[i]*C0;
Y_G_m[i] <= rgb888_g[i]*C1;
Y_B_m[i] <= rgb888_b[i]*C2;
{rgb888_r_r0[i], rgb888_g_r0[i], rgb888_b_r0[i]} <= {rgb888_r[i], rgb888_g[i],
rgb888_b[i]};
RGB_C[i] <= 255 + adjust_val[i];
end
end
assign Y_w[i] = Y_R_m[i] + Y_G_m[i] + Y_B_m[i];
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y[i] <= 0;
{rgb888_r_r1[i], rgb888_g_r1[i], rgb888_b_r1[i]} <= 0;
{Y_C_sign[i], Y_C_abs[i]} <= 0;
end
else if(I_tvalid_r[0])begin
Y[i] <= Y_w[i][17:10];
{rgb888_r_r1[i], rgb888_g_r1[i], rgb888_b_r1[i]} <= {rgb888_r_r0[i],
rgb888_g_r0[i], rgb888_b_r0[i]};
第 232页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
Y_C_sign[i] <= adjust_val[i][8];
Y_C_abs[i] <= adjust_val[i][8] ? (~adjust_val[i][7:0] + 1) : adjust_val[i];//鍒ゆ
柇姝h礋锛岀劧鍚庡幓璁$畻
end
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
Y_m[i] <= 0;
{rgb888_r_r2[i], rgb888_g_r2[i], rgb888_b_r2[i]} <= 0;
end
else if(I_tvalid_r[1])begin
Y_m[i] <= Y[i]*Y_C_abs[i];
rgb888_r_r2[i] <= rgb888_r_r1[i]*RGB_C[i];
rgb888_g_r2[i] <= rgb888_g_r1[i]*RGB_C[i];
rgb888_b_r2[i] <= rgb888_b_r1[i]*RGB_C[i];
end
end
assign Y_m_s[i] = (~Y_C_sign[i]) ? (~{2'b0, Y_m[i]} + 1) : {2'b0, Y_m[i]};
assign Y_R_m_s[i] = Y_m_s[i] + rgb888_r_r2[i];
assign Y_G_m_s[i] = Y_m_s[i] + rgb888_g_r2[i];
assign Y_B_m_s[i] = Y_m_s[i] + rgb888_b_r2[i];
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{R_new[i], G_new[i], B_new[i]} <= 0;
end
else if(I_tvalid_r[2])begin
R_new[i] <= Y_R_m_s[i][18] ? 0 : Y_R_m_s[i][17:16] > 0 ? 255 : Y_R_m_s[i][15:8];
G_new[i] <= Y_G_m_s[i][18] ? 0 : Y_G_m_s[i][17:16] > 0 ? 255 : Y_G_m_s[i][15:8];
B_new[i] <= Y_B_m_s[i][18] ? 0 : Y_B_m_s[i][17:16] > 0 ? 255 : Y_B_m_s[i][15:8];
end
end
end
endgenerate
/*****************************************************************
synchronization signal
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[2:0],I_tlast};
I_tuser_r <= {I_tuser_r[2:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[2:0],I_tvalid};
第 233页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end
end
assign
O_tlast
= I_tlast_r[3];
assign
O_tuser
= I_tuser_r[3];
assign
O_tvalid = I_tvalid_r[3];
assign
O_tdata = {R_new[3],G_new[3],B_new[3],
R_new[2],G_new[2],B_new[2],
R_new[1],G_new[1],B_new[1],
R_new[0],G_new[0],B_new[0]};
// RGB88 杞琑 GB565
// assign O_st_data = {R_new[7-:5],G_new[7-:6],B_new[7-:5]};
assign
I_tready = O_tready;
endmodule
13.3.3Verilog 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
// Define the image resolution here
// `define RESOLUTION_300_220
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
第 234页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_300_220
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
`define VERTICAL_BLANKING 40
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_test();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
第 235页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
第 236页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
第 237页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
Saturation_adj #(
.ADJUST_VAL (-10 )
)
Saturation_adj(
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
);
// Generate input data and control signals
initial begin
第 238页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
第 239页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
], green_channel[memory_address
]};
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
第 240页
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
13.4 仿真及结果
13.4.1 仿真波形图结果
第 241页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
13.4.2 仿真图片结果
可以看见左边的是原图,右边的是饱和度增强的图,其饱和度有了显著的提高。
13.5 上板结果
此工程也是只加入了 ISP 中的去马赛克算法和白平衡算法,现加入饱和度调节,一共三个算法组成,若读者觉
得资源占用太大,可以把一个时钟传输 4 个像素点改成一个时钟传输 1 个像素点的值,明白了 gamma 的原理,举
一反三即可。
第 242页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见,图像整体都出现色调不准的现象, 是因为作者给这个图像的饱和调到一个非常大的值,导致其他
的算法弊端全部显现出来了,读者可以多多尝试其他的饱和度的值,找到最适配自己算法工程和摄像头的饱和度值。
13.6Python 实现
13.6.1 代码实现
from PIL import Image, ImageEnhance
import os
def adjust_saturation(input_image_path, output_image_path, saturation_factor):
# 打开原始图片
with Image.open(input_image_path) as img:
# 创建增强器对象
enhancer = ImageEnhance.Color(img)
# 调整饱和度
img_enhanced = enhancer.enhance(saturation_factor)
# 将图像保存为 BMP 格式
img_enhanced.save(output_image_path, format='BMP')
def main():
# 输入图片路径
input_image_path = '001.bmp' # 替换为你的图片路径
# 输出图片路径
output_image_path = 'output.bmp'
第 243页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
# 饱和度因子,1.0 表示不变,<1.0 表示减少饱和度,>1.0 表示增加饱和度
saturation_factor = 1.5
# 调整饱和度
adjust_saturation(input_image_path, output_image_path, saturation_factor)
print(f"输出图像已保存为: {output_image_path}")
if __name__ == '__main__':
main()
从 input_image_path 等式后面输入图片, saturation_factor 控制的是饱和度调节的大小。控制这两个变量就可以了。
13.6.2 结果展示
可以看见左边的图是原图,右边的图的颜色明显要更加鲜艳,这个就是饱和度增强的一个效果所在。
第 244页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
14.FPGA 实现图像亮度调节
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
14.1 图像亮度调节简介
图像的亮度调节方法多种多样,总得来说分为线性和非线性,非线性的调节效果更好,更加平滑,不过算法的
难度更大,所消耗资源也更多,后面也会讲述 Gamma 算法调节,也可以用来当作亮度调节,当然 Gamma 算法它不
仅仅是对亮度影响,对其他的也有影响,还有更加用 RGB 转 YUV,来调节 Y,或者用 RGB 转 HSV,来调节 V,
通过这些去调节亮度都可以。
亮度调节在 ISP 中只占极少量的比重,主要用来图像增强所用,为了资源的节省,此章采用了线性调节亮度,
该法所消耗资源较少,也容易理解。
14.2 图像亮度调节原理
该亮度调节的方法很简单,就是去对 RGB 三通道进行同量的增减想要的亮度值即可。
14.3 代码分析
14.3.1IP 解析
下面是亮度调节的 IP:
上面 IP 的这些信号用于实现 AXI-Stream 接口协议,适用于高效的数据流传输。
输入信号(Input Signals):
I_clk: 时钟信号,用于同步数据传输。
I_rst_n: 复位信号,低电平有效,用于初始化模块。
I_tlast: 表示数据流中最后一个数据的标志信号。
I_tuser: 用户自定义信号,通常用于携带附加信息。
I_tdata[95:0]: 输入数据总线,宽度为 96 位,是由 4 个像素点组成
I_tvalid: 输入数据有效信号,表示当前数据总线上的数据是有效的。
O_tready: 输出就绪信号,表示下游模块已经准备好接收数据。
输出信号(Output Signals):
I_tready: 输入就绪信号,表示当前模块已经准备好接收数据。
第 245页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
O_tlast: 表示输出数据流中最后一个数据的标志信号。
O_tuser: 输出用户自定义信号。
O_tdata[95:0]: 输出数据总线,宽度为 96 位,是由 4 个像素点组成
O_tvalid: 输出数据有效信号,表示当前输出数据总线上的数据是有效的。
Brightness Add 表示增加的亮度,Brightness Minus 表示减少的亮度,这个范围尽量保持在 60 以内较好。
14.3.2Verilog Design 代码分析
源代码如下:
module Brightness_adjustment #(
parameter BRIGHTNESS_ADD
= 20,
parameter BRIGHTNESS_MINUS = 0
)
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
I_tdata
,
input
[95:0]
,
input
I_tvalid ,
output
I_tready ,
第 246页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
output
O_tlast
,
output
O_tuser
,
output [95:0]
O_tdata
,
output
O_tvalid ,
input
O_tready
);
/*****************************************************************
24deta to RGB888
*****************************************************************/
reg
I_tlast_r
;
reg
I_tuser_r
;
reg
I_tvalid_r
;
wire [23:0] I_tdata_r1 = I_tdata[23:0] ;
wire [23:0] I_tdata_r2 = I_tdata[47:24];
wire [23:0] I_tdata_r3 = I_tdata[71:48];
wire [23:0] I_tdata_r4 = I_tdata[95:72];
wire [7:0]
rgb888_r[3:0];
wire [7:0]
rgb888_g[3:0];
wire [7:0]
rgb888_b[3:0];
reg [9:0]
R_d[3:0];
reg [9:0]
G_d[3:0];
reg [9:0]
B_d[3:0];
wire [7:0]
R[3:0];
wire [7:0]
G[3:0];
wire [7:0]
B[3:0];
assign
rgb888_r[0] = I_tdata_r1[16+:8];
assign
rgb888_g[0] = I_tdata_r1[8+:8] ;
assign
rgb888_b[0] = I_tdata_r1[0+:8] ;
assign
rgb888_r[1] = I_tdata_r2[16+:8];
assign
rgb888_g[1] = I_tdata_r2[8+:8] ;
assign
rgb888_b[1] = I_tdata_r2[0+:8] ;
assign
rgb888_r[2] = I_tdata_r3[16+:8];
assign
rgb888_g[2] = I_tdata_r3[8+:8] ;
assign
rgb888_b[2] = I_tdata_r3[0+:8] ;
assign
rgb888_r[3] = I_tdata_r4[16+:8];
assign
rgb888_g[3] = I_tdata_r4[8+:8] ;
assign
rgb888_b[3] = I_tdata_r4[0+:8] ;
/*****************************************************************
第 247页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Calculation description
*****************************************************************/
genvar i ;
generate for (i = 0;i<4 ;i=i+1 ) begin
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
{R_d[i],G_d[i],B_d[i]} <= 0;
end
else if(I_tvalid)begin
R_d[i] <= rgb888_r[i] + BRIGHTNESS_ADD - BRIGHTNESS_MINUS;
G_d[i] <= rgb888_g[i] + BRIGHTNESS_ADD - BRIGHTNESS_MINUS;
B_d[i] <= rgb888_b[i] + BRIGHTNESS_ADD - BRIGHTNESS_MINUS;
end
end
assign R[i] = (R_d[i][9])?0:(R_d[i][8])?255:R_d[i][7:0];
assign G[i] = (G_d[i][9])?0:(G_d[i][8])?255:G_d[i][7:0];
assign B[i] = (B_d[i][9])?0:(B_d[i][8])?255:B_d[i][7:0];
end
endgenerate
/*****************************************************************
Signal synchronization
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r,I_tlast};
I_tuser_r <= {I_tuser_r,I_tuser};
I_tvalid_r <= {I_tvalid_r,I_tvalid};
end
end
assign
O_tlast
= I_tlast_r;
assign
O_tuser
= I_tuser_r;
assign
O_tvalid = I_tvalid_r;
assign O_tdata = {R[3],G[3],B[3],
R[2],G[2],B[2],
R[1],G[1],B[1],
R[0],G[0],B[0]};
assign I_tready = O_tready;
endmodule
第 248页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
14.3.3Verilog Simulation 代码分析
`timescale 1ns / 1ps
// Define the image resolution here
// `define RESOLUTION_300_220
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_300_220
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
第 249页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`define VERTICAL_BLANKING 40
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_test();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
第 250页
Image processing course advanced(2024)
常州米联客信息科技有限公司
wire
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
// Close all files
$fclose(output_fd);
第 251页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
第 252页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
Brightness_adjustment #(
.BRIGHTNESS_ADD
(30 ),
.BRIGHTNESS_MINUS(0)
)
Brightness_adjustment(
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
第 253页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
], green_channel[memory_address
]};
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
output_R_d0, output_G_d0, output_B_d0} = line_data;
第 254页
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
14.4 仿真结果
14.4.1 仿真波形图结果
第 255页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
14.4.2 仿真图片结果
原图:
第 256页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
经过亮度调节之后的图:
可以发现这个图的亮度明显比原图亮了很多了,这个也是因为给它
第 257页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
14.5 上板结果
此工程也是只加入了 ISP 中的去马赛克算法和白平衡算法,现加入亮度调节,一共三个算法组成,若读者觉得
资源占用太大,可以把一个时钟传输 4 个像素点改成一个时钟传输 1 个像素点的值,明白了 gamma 的原理,举一
反三即可。
可以看见,这个屏幕整体显示更加白了,但是由于是用的手机拍摄导致了色彩有点偏色了,不过整体来说还是
在原来基础上变亮了些许。
第 258页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
14.6Python 实现
14.6.1Python 代码
from PIL import Image, ImageEnhance
def adjust_brightness(input_image_path, output_image_path, brightness_factor):
"""
Adjust the brightness of an image and save the output as a BMP file.
:param input_image_path: str, path to the input image
:param output_image_path: str, path to save the output image
:param brightness_factor: float, a number > 0 where 1 means original brightness,
<1 means darker, and >1 means brighter
"""
# Open an image file
with Image.open(input_image_path) as img:
# Create an ImageEnhance object
enhancer = ImageEnhance.Brightness(img)
# Adjust brightness
img_enhanced = enhancer.enhance(brightness_factor)
# Save the modified image in BMP format
img_enhanced.save(output_image_path, format='BMP')
print(f"Image saved as BMP to {output_image_path}")
# Example usage:
input_path = '001.bmp'
# Replace with your input image path
output_path = 'output.bmp'
brightness_factor = 2
# Desired output image path in BMP format
# Adjust this factor to increase or decrease brightness
adjust_brightness(input_path, output_path, brightness_factor)
在 input_path 输入图片即可,然后 brightness_factor 控制亮度,这里选择的是 2 倍的亮度。
14.6.2 结果展示
原图像:
第 259页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
亮度增加 2 倍的图像:
可以看见这个亮度增加了 2 倍之后是比较明显的了。
第 260页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
15.FPGA 实现图像 Gamma 校正
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
15.1Gamma 算法简介
什么是 Gamma? 以前在 CRT 和早期 LCD 监视器中的 Gamma 与电压直接相关,是在显示器上准确再现图像
的重要因素。在当前的 LCD 监视器中,Gamma 可以被认为是在观看显示器时,捕获的数据的亮度(输入)与如何
影响人眼对颜色(输出)的总体感知之间的关系的调节器。 从技术意义上讲,它是通过像素值中的颜色阴影平衡
来校正图像颜色的亮度。像素的值介于 0(黑色)到 255(白色)之间,其间具有不同的灰度。我们的正常视觉(不
是过暗或非常明亮的条件)对暗色调的变化更敏感,并且由于图像的捕捉过程,颜色可能被误传,由于我们从原始
图像被捕获时感知亮度和亮度的方式不同。我们的眼睛以不成比例的方式捕捉亮度,例如,如果相机在极亮的环境
中拍摄图像,我们的眼睛会感觉到光线只是亮度的一小部分。如果图像在没有伽马校正的情况下被处理并显示在桌
面上,则用户将其视为褪色或太亮。
Gamma 曲线是一种特殊的色调曲线,当 Gamma 值等于 1 的时候,曲线为与坐标轴成 45°的直线,这个时候表
示输入和输出密度相同。高于 1 的 Gamma 值将会造成输出亮化,低于 1 的 Gamma 值将会造成输出暗化。总之,我
们的要求是输入和输出比率尽可能地接近于 1。在显示器、扫描仪、打印机等输入、输出设备中这是一个相当常见
并且比较重要的概念。在计算机系统中,由于显卡或者显示器的原因会出现实际输出的图像在亮度上有偏差,而
Gamma 曲线矫正就是通过一定的方法来矫正图像的这种偏差的方法。一般情况下,当用于 Gamma 矫正的值大于 1
时,图像的高光部分被压缩而暗调部分被扩展,当 Gamma 矫正的值小于 1 时,图像的高光部分被扩展而暗调部分
被压缩,Gamma 矫正一般用于平滑的扩展暗调的细节。
从图像增强、图像处理的角度来说 gamma,gamma 可以提高或者降低亮/暗处的对比度,下面介绍 5 钟常用的
Gamma 曲线:
Gamma 1.8:
以往是 Mac 电脑的标准,此设置增强了较暗色调之间的色彩渐变,不仅使较暗的场景更清晰,而且还增加了整
体色调亮度。此设置非常适合观看电影,电视或场景或图片太暗的情况。
作用:可以增加整体色调亮度,使较暗的场景更清晰。
应用:比较非常适合观看电影,电视或场景或图片太暗的情况。
Gamma 2.0:
作为另一种选择,这种 Gamma 设置可以提供平衡,同时仍然提供增强的暗色调增强,不仅增强了较暗场景中
的细节,而且还增强了柔和。
Gamma 2.2:
1996 年微软与惠普在特定光照下通过人眼对显示器的感受测试中得出 2.2 是一个较为适合的值,定下了这个标
准;Gamma 2.2 是目前设置的标准,用于平衡真实颜色与显示器,可以产生逼真的色彩。目,前设置的标准,用于
平衡真实颜色与显示器。此设置是完全支持 Windows 和 Mac,由于真彩色输出而采用,可以产生逼真的色彩。
Gamma 2.4:
作为一个额外选择,此 Gamma 设置用于增强对比度。
作用:增强略微过亮的场景中的细节,提供增强的对比度,并提高鲜艳色彩的可视性。
应用:适合高清电视制作,以及 Rec.709(高清电视的国际标准)色彩空间。
Gamma 2.6:
此 Gamma 设置用于突出显示图像和视频中明亮的色调对比度,其中较亮色调的差异难以察觉。这些不同的设
置允许用户灵活选择,根据情况选择哪种设置是理想的。
第 261页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
DCI(数字电影倡议)和电影制作的伽玛标准,这种设置为用户制作电影和电影提供了最真实的色彩。
作用:用于突出显示图像和视频中明亮的色调对比度,其中较亮色调的差异难以察觉。
应用:电影制作。
15.2Gamma 算法原理
算法步骤:
为了方便理解,这边直接用假设法: 假设像素点 A 的值为 100。
1.归一化:
将像素值转换为 0~1 之间的实数。 算法如下: ( i + 0. 5)/256 这里包含 1 个除法和 1 个加法操作。对于像素 A 而
言 ,其对应的归一化值为 0.392578。
2.预补偿:
根据公式 ,求出像素归一化后的 数据以 1/gamma 为指数的对应值。这一步包含一个 求指数运算。若 gamma 值
为 2. 2 , 则 1/gamma 为 0. 454545 ,对归一化后的 A 值进行预补偿的结果就是 0.392578^0. 454545 = 0.650634。
3.反归一化:
将经过预补偿的实数值反变换为 0 ~ 255 之间的整数值。具体算法为: f256 - 0. 5 此步骤包含一个乘法和一个减法
运算。续前 例 ,将 A 的预补偿结果 0.650634 代入上式 ,得到 A 预补偿后对应的像素值,这个像素值就是最后送入
显示器的数据。
可以发现,其中的过程并不复杂,但是如何用代码去复现,这是一个难题,这里我们直接采用了查找表的形式,
事先把所有的值都算出来,然后再根据所输入的值去索引到相应的位置的值,查找表的值也是直接用 Python 去实现
的,详情可以看 15.6。
15.3 代码分析
15.3.1IP 讲解
下面是 gamma 算法的 IP。
上面 IP 的这些信号用于实现 AXI-Stream 接口协议,适用于高效的数据流传输。
输入信号(Input Signals):
I_clk: 时钟信号,用于同步数据传输。
I_rst_n: 复位信号,低电平有效,用于初始化模块。
I_tlast: 表示数据流中最后一个数据的标志信号。
I_tuser: 用户自定义信号,通常用于携带附加信息。
第 262页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
I_tdata[95:0]: 输入数据总线,宽度为 96 位,是由 4 个像素点组成
I_tvalid: 输入数据有效信号,表示当前数据总线上的数据是有效的。
O_tready: 输出就绪信号,表示下游模块已经准备好接收数据。
输出信号(Output Signals):
I_tready: 输入就绪信号,表示当前模块已经准备好接收数据。
O_tlast: 表示输出数据流中最后一个数据的标志信号。
O_tuser: 输出用户自定义信号。
O_tdata[95:0]: 输出数据总线,宽度为 96 位,是由 4 个像素点组成
O_tvalid: 输出数据有效信号,表示当前输出数据总线上的数据是有效的。
这个是 Gamma 数值的更改,范围为 0.8-2.6,且都为 0.2 的倍数,为了更好的选择数值,这些 Gamma 值都在原
基础上乘了 10,读者可以根据自己的需要选择相应的 Gamma 值。
15.3.2Verilog Design 代码分析
这个是 Gamma 算法。
/*****************************************************************
Company : Nanjing Weiku Robot Technology Co., Ltd.
Brand
: VLKUS
Technical forum:www.uisrc.com
@Author
:
XiaoQingquan
@Time
:
2024/08
@Description :
ISP
gamma
第 263页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
*****************************************************************/
module gamma #(
parameter [4:0] GAMMA_10x = 22
)
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
input [95:0]
I_tdata
,
input
I_tvalid
,
output
I_tready
,
output
O_tlast
,
output
O_tuser
,
output [95:0]
O_tdata
,
output
O_tvalid
,
input
O_tready
,
);
/*****************************************************************
24deta to RGB888
*****************************************************************/
wire [23:0] I_tdata_r1 = I_tdata[23:0] ;
wire [23:0] I_tdata_r2 = I_tdata[47:24];
wire [23:0] I_tdata_r3 = I_tdata[71:48];
wire [23:0] I_tdata_r4 = I_tdata[95:72];
wire [7:0]
rgb888_r[3:0];
wire [7:0]
rgb888_g[3:0];
wire [7:0]
rgb888_b[3:0];
assign
rgb888_r[0] = I_tdata_r1[16+:8];
assign
rgb888_g[0] = I_tdata_r1[8+:8] ;
assign
rgb888_b[0] = I_tdata_r1[0+:8] ;
assign
rgb888_r[1] = I_tdata_r2[16+:8];
assign
rgb888_g[1] = I_tdata_r2[8+:8] ;
assign
rgb888_b[1] = I_tdata_r2[0+:8] ;
assign
rgb888_r[2] = I_tdata_r3[16+:8];
assign
rgb888_g[2] = I_tdata_r3[8+:8] ;
assign
rgb888_b[2] = I_tdata_r3[0+:8] ;
assign
rgb888_r[3] = I_tdata_r4[16+:8];
assign
rgb888_g[3] = I_tdata_r4[8+:8] ;
assign
rgb888_b[3] = I_tdata_r4[0+:8] ;
第 264页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
/*****************************************************************
wire signals declaration
*****************************************************************/
wire [11:0] O_LUT_2_6_data_r[3:0];
wire [11:0] O_LUT_2_6_data_g[3:0];
wire [11:0] O_LUT_2_6_data_b[3:0];
wire [11:0] O_LUT_2_4_data_r[3:0];
wire [11:0] O_LUT_2_4_data_g[3:0];
wire [11:0] O_LUT_2_4_data_b[3:0];
wire [11:0] O_LUT_2_2_data_r[3:0];
wire [11:0] O_LUT_2_2_data_g[3:0];
wire [11:0] O_LUT_2_2_data_b[3:0];
wire [11:0] O_LUT_2_0_data_r[3:0];
wire [11:0] O_LUT_2_0_data_g[3:0];
wire [11:0] O_LUT_2_0_data_b[3:0];
wire [11:0] O_LUT_1_8_data_r[3:0];
wire [11:0] O_LUT_1_8_data_g[3:0];
wire [11:0] O_LUT_1_8_data_b[3:0];
wire [11:0] O_LUT_1_6_data_r[3:0];
wire [11:0] O_LUT_1_6_data_g[3:0];
wire [11:0] O_LUT_1_6_data_b[3:0];
wire [11:0] O_LUT_1_4_data_r[3:0];
wire [11:0] O_LUT_1_4_data_g[3:0];
wire [11:0] O_LUT_1_4_data_b[3:0];
wire [11:0] O_LUT_1_2_data_r[3:0];
wire [11:0] O_LUT_1_2_data_g[3:0];
wire [11:0] O_LUT_1_2_data_b[3:0];
wire [11:0] O_LUT_0_8_data_r[3:0];
wire [11:0] O_LUT_0_8_data_g[3:0];
wire [11:0] O_LUT_0_8_data_b[3:0];
wire [7:0]
R_new [3:0];
wire [7:0]
G_new [3:0];
wire [7:0]
B_new [3:0];
/*****************************************************************
reg signals declaration
*****************************************************************/
第 265页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
reg
[11:0]
acc_rgb888_r[3:0];
reg
[11:0]
acc_rgb888_g[3:0];
reg
[11:0]
acc_rgb888_b[3:0];
reg
[3:0]
I_tlast_r ;
reg
[3:0]
I_tuser_r ;
reg
[3:0]
I_tvalid_r;
reg
[20:0] acc_rgb888_r_x0[3:0];
reg
[20:0] acc_rgb888_g_x0[3:0];
reg
[20:0] acc_rgb888_b_x0[3:0];
reg
[20:0] acc_rgb888_r_x1[3:0];
reg
[20:0] acc_rgb888_g_x1[3:0];
reg
[20:0] acc_rgb888_b_x1[3:0];
reg
[7:0]
acc_rgb888_r_x2[3:0];
reg
[7:0]
acc_rgb888_g_x2[3:0];
reg
[7:0]
acc_rgb888_b_x2[3:0];
Image processing course advanced(2024)
/*****************************************************************
Gamma SIZE
*****************************************************************/
genvar i;
generate
for(i = 0; i < 4; i = i + 1)
begin: LUT
lut_2_6 lut_2_6_R(
/*input
/*input
*/
.I_clk
(I_clk
),
(I_rst_n
),
*/
.I_rst_n
[7:0]
*/
.I_LUT_2_6_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_2_6_data(O_LUT_2_6_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_6_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_2_6_data(O_LUT_2_6_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_6_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_2_6_data(O_LUT_2_6_data_b[i])
/*input
),
);
lut_2_6 lut_2_6_G(
/*input
),
);
lut_2_6 lut_2_6_B(
/*input
);
lut_2_4 lut_2_4_R(
第 266页
),
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_4_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_2_4_data(O_LUT_2_4_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_4_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_2_4_data(O_LUT_2_4_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_4_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_2_4_data(O_LUT_2_4_data_b[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_2_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_2_2_data(O_LUT_2_2_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_2_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_2_2_data(O_LUT_2_2_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_2_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_2_2_data(O_LUT_2_2_data_b[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_0_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_2_0_data(O_LUT_2_0_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
/*input
),
);
lut_2_4 lut_2_4_G(
/*input
),
);
lut_2_4 lut_2_4_B(
/*input
),
);
lut_2_2 lut_2_2_R(
/*input
),
);
lut_2_2 lut_2_2_G(
/*input
),
);
lut_2_2 lut_2_2_B(
/*input
),
);
lut_2_0 lut_2_0_R(
/*input
);
lut_2_0 lut_2_0_G(
第 267页
),
常州米联客信息科技有限公司
/*input
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
[7:0]
*/
.I_LUT_2_0_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_2_0_data(O_LUT_2_0_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_2_0_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_2_0_data(O_LUT_2_0_data_b[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_8_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_1_8_data(O_LUT_1_8_data_r[i])
*/
.I_clk
(I_clk
),
(I_rst_n
),
),
);
lut_2_0 lut_2_0_B(
/*input
),
);
lut_1_8 lut_1_8_R(
/*input
),
);
lut_1_8 lut_1_8_G(
/*input
/*input
*/
.I_rst_n
[7:0]
*/
.I_LUT_1_8_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_1_8_data(O_LUT_1_8_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_8_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_1_8_data(O_LUT_1_8_data_b[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_6_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_1_6_data(O_LUT_1_6_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_6_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_1_6_data(O_LUT_1_6_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
/*input
),
);
lut_1_8 lut_1_8_B(
/*input
),
);
lut_1_6 lut_1_6_R(
/*input
),
);
lut_1_6 lut_1_6_G(
/*input
);
lut_1_6 lut_1_6_B(
第 268页
),
常州米联客信息科技有限公司
/*input
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
[7:0]
*/
.I_LUT_1_6_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_1_6_data(O_LUT_1_6_data_b[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_4_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_1_4_data(O_LUT_1_4_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_4_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_1_4_data(O_LUT_1_4_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_4_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_1_4_data(O_LUT_1_4_data_b[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_2_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_1_2_data(O_LUT_1_2_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_2_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_1_2_data(O_LUT_1_2_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_1_2_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_1_2_data(O_LUT_1_2_data_b[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
),
);
lut_1_4 lut_1_4_R(
/*input
),
);
lut_1_4 lut_1_4_G(
/*input
),
);
lut_1_4 lut_1_4_B(
/*input
),
);
lut_1_2 lut_1_2_R(
/*input
),
);
lut_1_2 lut_1_2_G(
/*input
),
);
lut_1_2 lut_1_2_B(
/*input
);
lut_0_8 lut_0_8_R(
第 269页
),
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
/*input
Image processing course advanced(2024)
[7:0]
*/
.I_LUT_0_8_data(rgb888_r[i]
/*output [11:0]
*/
.O_LUT_0_8_data(O_LUT_0_8_data_r[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_0_8_data(rgb888_g[i]
/*output [11:0]
*/
.O_LUT_0_8_data(O_LUT_0_8_data_g[i])
/*input
*/
.I_clk
(I_clk
),
/*input
*/
.I_rst_n
(I_rst_n
),
[7:0]
*/
.I_LUT_0_8_data(rgb888_b[i]
/*output [11:0]
*/
.O_LUT_0_8_data(O_LUT_0_8_data_b[i])
),
);
lut_0_8 lut_0_8_G(
/*input
),
);
lut_0_8 lut_0_8_B(
/*input
),
);
/*****************************************************************
select gamma
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
acc_rgb888_r[i] <= 12'd0;
acc_rgb888_g[i] <= 12'd0;
acc_rgb888_b[i] <= 12'd0;
end
else begin
case (GAMMA_10x)
5'd26:begin
acc_rgb888_r[i] <= O_LUT_2_6_data_r[i];
acc_rgb888_g[i] <= O_LUT_2_6_data_g[i];
acc_rgb888_b[i] <= O_LUT_2_6_data_b[i];
end
5'd24:begin
acc_rgb888_r[i] <= O_LUT_2_4_data_r[i];
acc_rgb888_g[i] <= O_LUT_2_4_data_g[i];
acc_rgb888_b[i] <= O_LUT_2_4_data_b[i];
end
5'd22:begin
acc_rgb888_r[i] <= O_LUT_2_2_data_r[i];
acc_rgb888_g[i] <= O_LUT_2_2_data_g[i];
acc_rgb888_b[i] <= O_LUT_2_2_data_b[i];
end
5'd20:begin
acc_rgb888_r[i] <= O_LUT_2_0_data_r[i];
acc_rgb888_g[i] <= O_LUT_2_0_data_g[i];
acc_rgb888_b[i] <= O_LUT_2_0_data_b[i];
第 270页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
end
5'd18:begin
acc_rgb888_r[i] <= O_LUT_1_8_data_r[i];
acc_rgb888_g[i] <= O_LUT_1_8_data_g[i];
acc_rgb888_b[i] <= O_LUT_1_8_data_b[i];
end
5'd16:begin
acc_rgb888_r[i] <= O_LUT_1_6_data_r[i];
acc_rgb888_g[i] <= O_LUT_1_6_data_g[i];
acc_rgb888_b[i] <= O_LUT_1_6_data_b[i];
end
5'd14:begin
acc_rgb888_r[i] <= O_LUT_1_4_data_r[i];
acc_rgb888_g[i] <= O_LUT_1_4_data_g[i];
acc_rgb888_b[i] <= O_LUT_1_4_data_b[i];
end
5'd12:begin
acc_rgb888_r[i] <= O_LUT_1_2_data_r[i];
acc_rgb888_g[i] <= O_LUT_1_2_data_g[i];
acc_rgb888_b[i] <= O_LUT_1_2_data_b[i];
end
5'd8 :begin
acc_rgb888_r[i] <= O_LUT_0_8_data_r[i];
acc_rgb888_g[i] <= O_LUT_0_8_data_g[i];
acc_rgb888_b[i] <= O_LUT_0_8_data_b[i];
end
default:begin
acc_rgb888_r[i] <= O_LUT_2_2_data_r[i];
acc_rgb888_g[i] <= O_LUT_2_2_data_g[i];
acc_rgb888_b[i] <= O_LUT_2_2_data_b[i];
end
endcase
end
end
/*****************************************************************
Anti normalization
*****************************************************************/
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
acc_rgb888_r_x0[i] <= 0;
acc_rgb888_g_x0[i] <= 0;
acc_rgb888_b_x0[i] <= 0;
end
else if(I_tvalid_r[0])begin
acc_rgb888_r_x0[i] <= acc_rgb888_r[i] << 8;
acc_rgb888_g_x0[i] <= acc_rgb888_g[i] << 8;
acc_rgb888_b_x0[i] <= acc_rgb888_b[i] << 8;
第 271页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
end
else begin
acc_rgb888_r_x0[i] <= acc_rgb888_r_x0[i] ;
acc_rgb888_g_x0[i] <= acc_rgb888_g_x0[i] ;
acc_rgb888_b_x0[i] <= acc_rgb888_b_x0[i] ;
end
end
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
acc_rgb888_r_x1[i] <= 0;
acc_rgb888_g_x1[i] <= 0;
acc_rgb888_b_x1[i] <= 0;
end
else if(I_tvalid_r[1])begin
acc_rgb888_r_x1[i] <= acc_rgb888_r_x0[i] - 2048;
acc_rgb888_g_x1[i] <= acc_rgb888_g_x0[i] - 2048;
acc_rgb888_b_x1[i] <= acc_rgb888_b_x0[i] - 2048;
end
else begin
acc_rgb888_r_x1[i] <= acc_rgb888_r_x1[i];
acc_rgb888_g_x1[i] <= acc_rgb888_g_x1[i];
acc_rgb888_b_x1[i] <= acc_rgb888_b_x1[i];
end
end
// limit
RGB
always @(posedge I_clk or negedge I_rst_n)begin
if(!I_rst_n)begin
acc_rgb888_r_x2[i] <= 0;
acc_rgb888_g_x2[i] <= 0;
acc_rgb888_b_x2[i] <= 0;
end
else if(I_tvalid_r[2])begin
acc_rgb888_r_x2[i] <=
(acc_rgb888_r_x1[i][20])?8'd255:(acc_rgb888_r_x1[i][19:12]);
acc_rgb888_g_x2[i] <=
(acc_rgb888_g_x1[i][20])?8'd255:(acc_rgb888_g_x1[i][19:12]);
acc_rgb888_b_x2[i] <=
(acc_rgb888_b_x1[i][20])?8'd255:(acc_rgb888_b_x1[i][19:12]);
end
else begin
acc_rgb888_r_x2[i] <= acc_rgb888_r_x2[i];
acc_rgb888_g_x2[i] <= acc_rgb888_g_x2[i];
acc_rgb888_b_x2[i] <= acc_rgb888_b_x2[i];
end
end
第 272页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
assign R_new[i] = acc_rgb888_r_x2[i];
assign G_new[i] = acc_rgb888_g_x2[i];
assign B_new[i] = acc_rgb888_b_x2[i];
end
endgenerate
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= {I_tlast_r[2:0],I_tlast};
I_tuser_r <= {I_tuser_r[2:0],I_tuser};
I_tvalid_r <= {I_tvalid_r[2:0],I_tvalid};
end
end
assign
O_tlast
= I_tlast_r[3];
assign
O_tuser
= I_tuser_r[3];
assign
O_tvalid = I_tvalid_r[3];
assign O_tdata = {R_new[3],G_new[3],B_new[3],
R_new[2],G_new[2],B_new[2],
R_new[1],G_new[1],B_new[1],
R_new[0],G_new[0],B_new[0]};
assign
I_tready = O_tready;
endmodule
15.3.3Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
// Define the image resolution here
// `define RESOLUTION_300_220
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/001.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
第 273页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_300_220
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
`define VERTICAL_BLANKING 40
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_tb();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
第 274页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
第 275页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
第 276页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
gamma#(
.GAMMA_10x
(22 )
) gamma (
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
第 277页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
Image processing course advanced(2024)
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
第 278页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
], green_channel[memory_address
]};
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
第 279页
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
15.4 仿真结果
15.4.1 仿真波形图结果
第 280页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
15.4.2 仿真图结果
Gamma 算法主要用于调整图像的亮度,通过应用 Gamma 校正,可以使图像的亮度更加符合人眼的感知特性,
它通过非线性变换来调整像素值,使得图像在不同亮度下的细节更加清晰。虽然 Gamma 校正主要影响亮度,但它
也会间接影响对比度,很明显经过 Gamma 算法的图会比原图亮很多。
15.5 上板结果
此工程也是只加入了 ISP 中的去马赛克算法和白平衡算法,现加入 Gamma 算法,一共三个算法组成,若读者
觉得资源占用太大,可以把一个时钟传输 4 个像素点改成一个时钟传输 1 个像素点的值,明白了 gamma 的原理,
举一反三即可。
第 281页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见,整体图片整体过亮了,此处的 Gamma 值用的是 2.2,读者可以根据自己所需去调整 Gamma 的值,
比如现在这样的 2.2 的值明显过亮了,这个时候可以选择小一点的值,比如 1.8 或者 1.6 等值去进行尝试,当然也可
以选择先用图片去进行调试,这样更加省时省力。
15.6Python 实现
15.6.1Python 代码
这个代码求出来的值为 Gamma 查找表的值,可以代码中 gamma 后面填入相应的值,可以获得增大 4096 倍的
值,这样也节省了大量时间。
results = []
for i in range(256):
normalized_value = (i + 0.5) / 256
gamma = 2.6
transformed_value = normalized_value ** (1/gamma)
final_result = int(transformed_value * 4096)
# 转换为整数
results.append(final_result)
# 打印所有计算结果
for index, value in enumerate(results):
print(f"{index}: {value}")
下面这个代码是 Gamma 算法。
import cv2
import numpy as np
def adjust_gamma(image, gamma=1.0):
# 构建一个查找表,将像素值映射到 gamma 校正后的值
invGamma = 1.0 / gamma
第 282页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
table = np.array([(i / 255.0) ** invGamma * 255 for i in np.arange(0, 256)]).astype("uint8")
# 应用查找表进行 gamma 校正
return cv2.LUT(image, table)
# 读取图像
image = cv2.imread('001.bmp')
# 调整 gamma 值
gamma_corrected = adjust_gamma(image, gamma=2.2)
# 显示原始图像和校正后的图像
cv2.imshow('Original Image', image)
cv2.imshow('Gamma Corrected Image', gamma_corrected)
cv2.waitKey(0)
cv2.destroyAllWindows()
15.6.2 结果展示
可以发现 Python 实现的 Gamma 算法与 FPGA 所实现的算法验证并无差异。
第 283页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
16.FPGA 实现图像黑电平校正
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
16.1 图像黑电平校正简介
黑电平校正(Black Level Correction),有时也称为黑电平补偿(Black Level Compensation),是图像信号处理
(ISP)中的一个关键步骤,它的主要目的是校正图像传感器在捕获图像时由于各种原因(如传感器噪声、暗电流
等)导致的黑电平偏移,从而确保图像的黑色区域在最终输出图像中显示为真正的黑色。
16.2 图像黑电平校正原理
16.2.1 黑电平偏移的来源
传感器噪声:图像传感器在没有光照射时,仍然会产生一定的电信号,这种电信号被称为暗电流(Dark Current),
暗电流会导致捕获的图像中本应为黑色的像素点出现非零值。
读出噪声:在传感器将电信号转换为数字信号的过程中,读出电路也会引入一些噪声。
温度影响:传感器的工作温度会影响暗电流的大小,温度越高,暗电流越大。
16.2.2 黑电平偏移的基本步骤
1.黑电平测量:在图像传感器捕获图像时,通常会有一些专门的像素(称为黑电平参考像素)用于测量黑电平。
这些像素被遮光,不接收任何光信号,因此它们的输出应该仅包含暗电流和读出噪声。
2.计算平均黑电平:对这些黑电平参考像素的值进行平均,得到一个平均黑电平值。
3.校正图像:将捕获图像的每个像素值减去这个平均黑电平值,从而消除黑电平偏移。
在代码中我们需要先用 ILA 去测量黑电平偏移量,如下图,测量方法就是先上板,有专门的暗室的话可以去专
门的暗室,没有暗室就用一块黑布盖住摄像头,然后读取 ILA 值,取一个平均值,读出来加入 BLC 模块就可以了。
第 284页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
16.2.3 黑电平校正的主要 IP 核
下 面 说 说 这 两 个 模 块 的 作 用 , 首 先 BLC_measurement 是 用 来 检 测 出 黑 电 平 偏 移 值 的 , 也 就 是 通 过
black_level_offset_r0、black_level_offset_r1、black_level_offset_r2、black_level_offset_r3 这四个信号去检测黑电平偏
移值,如下图,其中的 Frame Count 是检测的帧数,这里设置为 30,一般来说检测的帧数为 20-60 就可以了,检测
的方法如果没有暗室条件,就用一块黑布去进行检测就可以,用黑布蒙住摄像头,然后用 LIA 去检测它的一个信号
即可,该模块与 MIPI 相连接。
然后我们在来说一下 BLC 模块,当我们用 BLC_measurement 模块检测出来所想要用的黑电平偏移值的时候,
这 个 时 候 我 们 就 可 以 用 BLC 模 块 了 , 如 下 图 所 示 , 假 若 我 们 前 面 用 BLC_measurement 模 块 求 出 来 的
第 285页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
Black_level_offset 是 65,那么我们在 BLC 模块填 65 即可,BLC 检测的原理也就是用输入的 RGB 的值去减去我们
所得出来的偏移值,就可以消去这个偏移值。
16.3 代码分析
16.3.1BLC 模块
源代码如下:
`timescale 1ns / 1ps
module BLC #(
parameter [9:0]
Black_level_offset_r0 = 15,
parameter [9:0]
Black_level_offset_r1 = 15,
parameter [9:0]
Black_level_offset_r2 = 15,
parameter [9:0]
Black_level_offset_r3 = 15
)
(
input
I_clk
input
I_rst_n,
,
第 286页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
input
I_tlast
,
input
I_tuser
,
I_tdata
,
I_tvalid
,
I_tdest
,
output
I_tready
,
output
O_tlast
,
output
O_tuser
,
input
[39:0]
input
input
[9:0]
output [39:0]
O_tdata
,
output
O_tvalid
,
output [9:0]
O_tdest
,
input
O_tready
Image processing course advanced(2024)
);
reg
I_tlast_r
;
reg
I_tuser_r
;
reg
I_tvalid_r
;
wire [9:0]
I_blc_data[3:0];
wire [9:0]
black_level_offset[3:0] ;
assign black_level_offset[0] = Black_level_offset_r0;
assign black_level_offset[1] = Black_level_offset_r1;
assign black_level_offset[2] = Black_level_offset_r2;
assign black_level_offset[3] = Black_level_offset_r3;
reg [9:0]
data_out[3:0];
assign I_blc_data[0] = I_tdata[9:0]
;
assign I_blc_data[1] = I_tdata[19:10];
assign I_blc_data[2] = I_tdata[29:20];
assign I_blc_data[3] = I_tdata[39:30];
genvar i;
generate for(i=0;i<4;i=i+1)
begin:
BLACK_LEVEL_OFFSET
always @(posedge I_clk)begin
if (I_tvalid) begin
// 鎵ц
榛戠數骞崇煫姝o紝闃叉
鍑虹幇璐燂拷??
if (I_blc_data[i] > black_level_offset[i]) begin
data_out[i] <= I_blc_data[i] - black_level_offset[i];
end
else begin
data_out[i] <= 10'd0; // 灏嗙粨鏋滆
end
end
end
第 287页
鍓
负 0 锛岄槻姝㈣礋锟�??
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
end
endgenerate
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{I_tlast_r,I_tuser_r,I_tvalid_r} <= 0;
else begin
I_tlast_r <= I_tlast;
I_tuser_r <= I_tuser;
I_tvalid_r <= I_tvalid;
end
end
assign
O_tlast
= I_tlast_r;
assign
O_tuser
= I_tuser_r;
assign
O_tvalid
= I_tvalid_r;
assign
O_tdata
= {data_out[3],data_out[2],data_out[1],data_out[0]};
// assign O_t_data = {R_new[7-:5],G_new[7-:6],B_new[7-:5]};
assign
I_tready
= O_tready;
endmodule
16.3.2BLC 测量模块
`timescale 1ns / 1ps
module BLC_measurement #(
parameter [13:0] Width
= 1920,
parameter [13:0] Height
= 1080,
parameter [13:0] Width_div4
= 480 ,
parameter [7:0]
FRAME_COUNT = 30
)
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
I_tdata
,
I_tvalid
,
I_tdest
,
output
I_tready
,
output reg [20:0]
pixel_count_r,
output [9:0]
I_blc_data_r0,
output [9:0]
I_blc_data_r1,
output [9:0]
I_blc_data_r2,
output [9:0]
I_blc_data_r3,
input
[39:0]
input
input
[9:0]
,
第 288页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
output [9:0]
black_level_offset_r0,
output [9:0]
black_level_offset_r1,
output [9:0]
black_level_offset_r2,
output [9:0]
black_level_offset_r3
Image processing course advanced(2024)
);
/*****************************************************
锟斤拷锟饺硷拷锟斤拷
*****************************************************/
// calculate the data's bit width
function integer clog2b(
input integer width
);
begin
for(clog2b=0; width>0; clog2b=clog2b+1)begin
width = width >> 1;
end
end
endfunction
/*****************************************************
measurement
*****************************************************/
localparam IMAGE_PIXEL_SUM
= FRAME_COUNT*(Height*Width_div4);//30 锟�??
assign
I_blc_data_r0 = I_tdata[9:0]
assign
I_blc_data_r1 = I_tdata[19:10];
assign
I_blc_data_r2 = I_tdata[29:20];
assign
I_blc_data_r3 = I_tdata[39:30];
reg
[31:0]
pixel_count;
reg
[35:0]
measurement_data[3:0];
// 鍦ㄦ椂閽熶笂鍗囨部鎴栧
;
浣嶄俊鍙锋湁鏁堟椂瑙﹀彂
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
pixel_count <= 'd0;
measurement_data[0] <= 'd0;
measurement_data[1] <= 'd0;
measurement_data[2] <= 'd0;
measurement_data[3] <= 'd0;
pixel_count_r <= 0;
end
else if(I_tuser)
pixel_count_r <= 0;
else if(pixel_count > IMAGE_PIXEL_SUM)begin
pixel_count <= 'd0;
measurement_data[0] <= 'd0;
measurement_data[1] <= 'd0;
measurement_data[2] <= 'd0;
第 289页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
measurement_data[3] <= 'd0;
end
else if(I_tvalid)begin
pixel_count_r <= pixel_count_r + 1;
pixel_count <= pixel_count + 1;
measurement_data[0] <= measurement_data[0] + I_tdata[9:0]
;
measurement_data[1] <= measurement_data[1] + I_tdata[19:10];
measurement_data[2] <= measurement_data[2] + I_tdata[29:20];
measurement_data[3] <= measurement_data[3] + I_tdata[39:30];
end
end
wire
[79:0] avg_data_r0[3:0];
wire
[47:0] avg_data_r1[3:0];
assign
avg_data_r1[0] = avg_data_r0[0][79:32];
assign
avg_data_r1[1] = avg_data_r0[1][79:32];
assign
avg_data_r1[2] = avg_data_r0[2][79:32];
assign
avg_data_r1[3] = avg_data_r0[3][79:32];
assign
black_level_offset_r0 = (avg_data_r1[0][47:22])?10'd1023 : avg_data_r1[0][21:12] ;
assign
black_level_offset_r1 = (avg_data_r1[1][47:22])?10'd1023 : avg_data_r1[1][21:12] ;
assign
black_level_offset_r2 = (avg_data_r1[2][47:22])?10'd1023 : avg_data_r1[2][21:12] ;
assign
black_level_offset_r3 = (avg_data_r1[3][47:22])?10'd1023 : avg_data_r1[3][21:12] ;
genvar i;
generate for(i=0;i<4;i=i+1)
begin:min_avg
div_blc min_avg (
// input wire aclk
.aclk(I_clk),
.s_axis_divisor_tvalid(I_tvalid),
.s_axis_divisor_tdata(pixel_count),
.s_axis_dividend_tvalid(I_tvalid),
// input wire s_axis_divisor_tvalid
// input wire [31 : 0] s_axis_divisor_tdata
// input wire s_axis_dividend_tvalid
.s_axis_dividend_tdata({measurement_data[i],12'd0}),
// input wire [47 : 0]
s_axis_dividend_tdata
.m_axis_dout_tvalid(),
// output wire m_axis_dout_tvalid
.m_axis_dout_tdata(avg_data_r0[i])
// output wire [79 : 0] m_axis_dout_tdata
);
end
endgenerate
endmodule
16.4 上板结果
此工程也是只加入了 ISP 中的去马赛克算法和白平衡算法,现加入 BLC 算法,一共三个算法组成,若读者觉
得资源占用太大,可以把一个时钟传输 4 个像素点改成一个时钟传输 1 个像素点的值,明白了 BLC 的原理,举一
反三即可。
第 290页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
可以看见,这个黑色更黑了,更加浓郁了,这个就是黑电平校正的作用,让黑色更黑,因为很多时候,颜色最
深的点都没有达到真正意义上的黑,也就是 RGB 的像素点都为 0,这个时候我们就需要用黑电平校正去对摄像头进
行调整了。
16.5Python 实现
16.5.1Python 代码
BLC 代码,通过灰度图更加明显直观的看见的 BLC 的影响和作用。
import cv2
import numpy as np
第 291页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
from matplotlib import pyplot as plt
def black_level_correction(image, black_level):
"""
对图像进行黑电平校正。
参数:
image (numpy.ndarray): 输入图像。
black_level (int): 黑电平值,需要从每个像素中减去的值。
返回:
numpy.ndarray: 校正后的图像。
"""
# 将图像转换为浮点型以避免溢出
corrected_image = image.astype(np.float32)
# 减去黑电平值
corrected_image -= black_level
# 将负值剪裁为 0
corrected_image = np.clip(corrected_image, 0, 255)
# 转换回原始数据类型
return corrected_image.astype(image.dtype)
# 加载图像
image = cv2.imread('001.bmp', cv2.IMREAD_GRAYSCALE)
# 定义黑电平
black_level = 15
# 进行黑电平校正
corrected_image = black_level_correction(image, black_level)
# 显示原始图像和校正后的图像
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(image, cmap='gray')
plt.axis('off')
plt.subplot(1, 2, 2)
plt.title('Corrected Image')
plt.imshow(corrected_image, cmap='gray')
plt.axis('off')
plt.show()
第 292页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
16.5.2 结果展示
可以看见右边的图黑色颜色明显更深了,这也就是黑电平校正算法的关键作用。
第 293页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
17.FPGA 实现图像锐化
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
17.1 图像锐化算法简介
图像锐化是图像处理领域的重要技术,旨在增强图像边缘和细节,从而使视觉上更加清晰、锐利,其原理主要通
过强调图像中的高频分量(如边缘信息),从而改善图像中细节部分的对比度,进而使画面看上去更加鲜明和生动,
图像锐化广泛应用于摄影、医学成像、遥感、视频编辑等诸多领域,是提升图像质量重要的步骤之一。
图像锐化的主要目的是提升图像的视觉效果。在许多场景下,原始图像可能会由于各种因素(如传感器噪声、
拍摄条件不佳等)显得模糊不清楚,模糊可能是整体性的,也可能只存在于某些特定区域,它削弱了图像的细节表达
能力,从而影响观众的感知和理解。图像锐化通过增强图像局部对比度,特别是物体轮廓和纹理,可以让图像的细
节更为突出,让视觉质量得到明显提升。
对于一定程度上已经失真的图像,例如被噪点、相机抖动、运动模糊等问题影响的图像,锐化也有助于挽救细
节。虽然强行锐化不能创造原始不存在的细节,但它可以通过增强纹理和边缘的方式弥补部分失真的影响。这尤其
在摄影、监控图像增强和解码质量较差的图像(比如视频通话中的低分辨率帧)中起到显著作用。
17.2 图像锐化算法原理
17.2.1 拉普拉斯公式
拉普拉斯算子是图像的二阶导数,可以用下式表示:
在离散图像中,拉普拉斯算子被近似为一种离散卷积操作,即用一个模板(卷积核)对图像进行卷积。对于 3x3
的拉普拉斯卷积核,常见的模板如下(也称为 8 邻域拉普拉斯算子):
使用该卷积核,可以对图像执行二阶导数操作,检测并增强图像中的边缘。
17.2.2 图像锐化具体步骤
为了提取图像的边缘信息,使用上面的卷积核:
第 294页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
针对图像 ( I(x,y) ),对其每个像素进行卷积操作。卷积的基本步骤如下:
1. 将卷积核的中心对准图像像素 ( I(x,y) ) 的位置。
2. 计算卷积核覆盖区域与图像像素的加权和。对于 3x3 的卷积核,每个中心像素的响应值 ( O(x,y) ) 计算如下:
O(x,y)=(−1)⋅ I(x−1,y−1)+(−1)⋅ I(x,y−1)+(−1)⋅ I(x+1,y−1)+...+8⋅ I(x,y)+...
通俗点说就是把形成的 3x3 矩阵的每个对应值去乘以相对应的数即可,这种卷积操作对于图像上的每个像素都
执行,就可以输出一个边缘增强的图像。
3. 利用拉普拉斯结果锐化图像:
从左往右分别是锐化后的像素点,原像素点,权重系数和拉普拉斯算子计算出的图像增强像素点。
其中最关键的是权重系数的选取,一般权重系数我们都选择为 2 的倍数,权重系数越小,图像增强效果越明显,这
里作者选择的权重系数是 8。
4. 对于超出的值做限制处理
在上述处理过程中,锐化后的图像像素值有可能超出正常的灰度范围(通常 0 到 255)。对于超出范围的像
素,需要进行裁剪,确保最终图像的像素值在有效范围内:
这样处理之后,所有像素值势必都在 0 到 255 的范围内,从而可以正确显示。
5. 输出图像数据即可。
17.3 设计分析
17.3.1IP 分析
上面 IP 的这些信号用于实现 AXI-Stream 接口协议,适用于高效的数据流传输。
输入信号(Input Signals):
第 295页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
I_clk: 时钟信号,用于同步数据传输。
I_rst_n: 复位信号,低电平有效,用于初始化模块。
I_tlast: 表示数据流中最后一个数据的标志信号。
I_tuser: 用户自定义信号,通常用于携带附加信息。
I_tdata[95:0]: 输入数据总线,宽度为 96 位,是由 4 个像素点组成
I_tvalid: 输入数据有效信号,表示当前数据总线上的数据是有效的。
O_tready: 输出就绪信号,表示下游模块已经准备好接收数据。
输出信号(Output Signals):
I_tready: 输入就绪信号,表示当前模块已经准备好接收数据。
O_tlast: 表示输出数据流中最后一个数据的标志信号。
O_tuser: 输出用户自定义信号。
O_tdata[95:0]: 输出数据总线,宽度为 96 位,是由 4 个像素点组成
O_tvalid: 输出数据有效信号,表示当前输出数据总线上的数据是有效的。
选择所需的分辨率即可。
17.3.2Verilog Design 代码分析
此处没有再讲述另外两个模块(line_buffer_sharpening 和 image_line_buffer_sharpening),若要了解详情,可以
看第八章和第十章的内容。
`timescale 1ns / 1ps
module sharpening
#(
parameter [12:0] IMG_WIDTH
= 640,
parameter [12:0] IMG_HEIGHT = 480
)
第 296页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
(
input
I_clk
input
I_rst_n,
input
I_tlast
,
input
I_tuser
,
input [95:0]
I_tdata
,
input
I_tvalid ,
output
I_tready ,
output
O_tlast
,
output
O_tuser
,
output [95:0]
O_tdata
,
output
O_tvalid ,
input
O_tready
,
);
function integer clog2b(
input integer depth
);
begin
for(clog2b=0; depth>0; clog2b=clog2b+1)begin
depth = depth >> 1;
end
end
endfunction
localparam MATRIX_WIDTH = (IMG_WIDTH>>2)-1;
localparam IMG_WIDTH_4x = (IMG_WIDTH>>2);
reg [9:0] R_sum1[3:0], G_sum1[3:0], B_sum1[3:0];
reg [9:0] R_sum2[3:0], G_sum2[3:0], B_sum2[3:0];
reg [9:0] R_sum3[3:0], G_sum3[3:0], B_sum3[3:0];
reg [7:0] R5_d0[3:0], G5_d0[3:0], B5_d0[3:0];
wire [11:0] R_sum_d[3:0], G_sum_d[3:0], B_sum_d[3:0];
wire
line_valid;
wire [24*6-1:0]
last_line_buffer;
wire [24*6-1:0]
cur_line_buffer ;
wire [24*6-1:0]
next_line_buffer;
wire [7:0] R1[3:0], G1[3:0], B1[3:0];
wire [7:0] R2[3:0], G2[3:0], B2[3:0];
wire [7:0] R3[3:0], G3[3:0], B3[3:0];
wire [7:0] R4[3:0], G4[3:0], B4[3:0];
wire [7:0] R5[3:0], G5[3:0], B5[3:0];
wire [7:0] R6[3:0], G6[3:0], B6[3:0];
wire [7:0] R7[3:0], G7[3:0], B7[3:0];
wire [7:0] R8[3:0], G8[3:0], B8[3:0];
第 297页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
wire [7:0] R9[3:0], G9[3:0], B9[3:0];
valid_d0,valid_d1,valid_d2,valid_d3;
reg
reg
[7:0]
R[3:0],G[3:0],B[3:0];
reg
[11:0]
R_sum[3:0], G_sum[3:0], B_sum[3:0];
wire [95:0]
rgb_data;
reg [23:0]
matrix03, matrix04, matrix05, matrix06, matrix07, matrix08 ;
reg [23:0]
matrix13, matrix14, matrix15, matrix16, matrix17, matrix18 ;
reg [23:0]
matrix23, matrix24, matrix25, matrix26, matrix27, matrix28 ;
wire
tuser,tlast;
image_line_buffer_sharpening#(
.IMG_WIDTH (IMG_WIDTH ) ,
.IMG_HEIGHT(IMG_HEIGHT)
)image_line_buffer_sharpening(
/*input
*/.I_clk
(I_clk
),
/*input
*/.I_rst_n
(I_rst_n
),
.I_tuser
(I_tuser
),
.I_tlast
(I_tlast
),
/*input wire
*/.I_tvalid
(I_tvalid
),
/*input wire [95:0]
*/.I_tdata
(I_tdata
),
/*output
*/.O_tlast
(tlast
),
.O_tuser
(tuser
),
reg
/*output reg
*/.O_tvalid
(line_valid
),
/*output reg [24*6-1:0] */.last_line_data
(last_line_buffer),
/*output reg [24*6-1:0] */.cur_line_data
(cur_line_buffer ),
/*output reg [24*6-1:0] */.next_line_data
(next_line_buffer)
);
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{matrix03, matrix04, matrix05, matrix06, matrix07, matrix08} <= 0;
{matrix13, matrix14, matrix15, matrix16, matrix17, matrix18} <= 0;
{matrix23, matrix24, matrix25, matrix26, matrix27, matrix28} <= 0;
end
else if(line_valid)begin
{matrix03, matrix04, matrix05, matrix06, matrix07, matrix08} <= last_line_buffer;
{matrix13, matrix14, matrix15, matrix16, matrix17, matrix18} <= cur_line_buffer ;
{matrix23, matrix24, matrix25, matrix26, matrix27, matrix28} <= next_line_buffer;
end
end
assign {R1[0], G1[0], B1[0]} = matrix03;
assign {R2[0], G2[0], B2[0]} = matrix04;
assign {R3[0], G3[0], B3[0]} = matrix05;
assign {R4[0], G4[0], B4[0]} = matrix13;
assign {R5[0], G5[0], B5[0]} = matrix14;
assign {R6[0], G6[0], B6[0]} = matrix15;
assign {R7[0], G7[0], B7[0]} = matrix23;
assign {R8[0], G8[0], B8[0]} = matrix24;
第 298页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
assign {R9[0], G9[0], B9[0]} = matrix25;
assign {R1[1], G1[1], B1[1]} = matrix04;
assign {R2[1], G2[1], B2[1]} = matrix05;
assign {R3[1], G3[1], B3[1]} = matrix06;
assign {R4[1], G4[1], B4[1]} = matrix14;
assign {R5[1], G5[1], B5[1]} = matrix15;
assign {R6[1], G6[1], B6[1]} = matrix16;
assign {R7[1], G7[1], B7[1]} = matrix24;
assign {R8[1], G8[1], B8[1]} = matrix25;
assign {R9[1], G9[1], B9[1]} = matrix26;
assign {R1[2], G1[2], B1[2]} = matrix05;
assign {R2[2], G2[2], B2[2]} = matrix06;
assign {R3[2], G3[2], B3[2]} = matrix07;
assign {R4[2], G4[2], B4[2]} = matrix15;
assign {R5[2], G5[2], B5[2]} = matrix16;
assign {R6[2], G6[2], B6[2]} = matrix17;
assign {R7[2], G7[2], B7[2]} = matrix25;
assign {R8[2], G8[2], B8[2]} = matrix26;
assign {R9[2], G9[2], B9[2]} = matrix27;
assign {R1[3], G1[3], B1[3]} = matrix06;
assign {R2[3], G2[3], B2[3]} = matrix07;
assign {R3[3], G3[3], B3[3]} = matrix08;
assign {R4[3], G4[3], B4[3]} = matrix16;
assign {R5[3], G5[3], B5[3]} = matrix17;
assign {R6[3], G6[3], B6[3]} = matrix18;
assign {R7[3], G7[3], B7[3]} = matrix26;
assign {R8[3], G8[3], B8[3]} = matrix27;
assign {R9[3], G9[3], B9[3]} = matrix28;
genvar i;
generate
for(i = 0; i < 4; i = i + 1)
begin: sharpening
//矩阵计算
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R_sum1[i], G_sum1[i], B_sum1[i]} <= 0;
{R_sum2[i], G_sum2[i], B_sum2[i]} <= 0;
{R_sum3[i], G_sum3[i], B_sum3[i]} <= 0;
{R5_d0[i], G5_d0[i], B5_d0[i]} <= 0;
end
else if(valid_d0)begin
R_sum1[i] <= R1[i] + R4[i] + R7[i];
R_sum2[i] <= R2[i] + R8[i];
R_sum3[i] <= R3[i] + R6[i] + R9[i];
第 299页
Image processing course advanced(2024)
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
G_sum1[i] <= G1[i] + G4[i] + G7[i];
G_sum2[i] <= G2[i] + G8[i];
G_sum3[i] <= G3[i] + G6[i] + G9[i];
B_sum1[i] <= B1[i] + B4[i] + B7[i];
B_sum2[i] <= B2[i] + B8[i];
B_sum3[i] <= B3[i] + B6[i] + B9[i];
{R5_d0[i], G5_d0[i], B5_d0[i]} <= {R5[i], G5[i], B5[i]};
end
end
assign R_sum_d[i] = {R5_d0[i],3'd0} - (R_sum1[i] + R_sum2[i] + R_sum3[i]);
assign G_sum_d[i] = {G5_d0[i],3'd0} - (G_sum1[i] + G_sum2[i] + G_sum3[i]);
assign B_sum_d[i] = {B5_d0[i],3'd0} - (B_sum1[i] + B_sum2[i] + B_sum3[i]);
//权重系数为 8,所以左移三位
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R_sum[i], G_sum[i], B_sum[i]} <= 0;
end
else if(valid_d1) begin
R_sum[i] <= R5_d0[i] + {{3{R_sum_d[i][11]}}, R_sum_d[i][11:3]};
G_sum[i] <= G5_d0[i] + {{3{G_sum_d[i][11]}}, G_sum_d[i][11:3]};
B_sum[i] <= B5_d0[i] + {{3{B_sum_d[i][11]}}, B_sum_d[i][11:3]};
end
end
//限制处理
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
{R[i], G[i], B[i]} <= 0;
end
else if(valid_d2) begin
R[i] <= (R_sum[i][11]) ? 0 : (R_sum[i][10:8]) ? 255 : R_sum[i][7:0];
G[i] <= (G_sum[i][11]) ? 0 : (G_sum[i][10:8]) ? 255 : G_sum[i][7:0];
B[i] <= (B_sum[i][11]) ? 0 : (B_sum[i][10:8]) ? 255 : B_sum[i][7:0];
end
end
end
endgenerate
assign
rgb_data = {R[0],G[0],B[0],
R[1],G[1],B[1],
R[2],G[2],B[2],
R[3],G[3],B[3]};
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)begin
valid_d0 <= 0;
第 300页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
valid_d1 <= 0;
valid_d2 <= 0;
valid_d3 <= 0;
end
else begin
valid_d0 <= line_valid;
valid_d1 <= valid_d0;
valid_d2 <= valid_d1;
valid_d3 <= valid_d2;
end
end
reg [3:0]
tlast_d;
reg [3:0]
tuser_d;
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
{tlast_d,tuser_d} <= 0;
else begin
tlast_d <= {tlast_d[2:0],tlast};
tuser_d <= {tuser_d[2:0],tuser};
end
end
assign
O_tdata
= rgb_data;
assign
O_tlast
= tlast_d[3];
assign
O_tuser
= tuser_d[3];
assign
O_tvalid = valid_d3;
assign
I_tready = O_tready;
endmodule
17.3.3Verilog Simulation 代码分析
根据自己给的图片的大小选择相应的分辨率,若想要的分辨率在代码中都没有,可自行选择定义所需要的分辨
率,当然也可以自己更改图片的分辨率大小。需要注意所给的图片存放的地址索引的符号,应该是“/”,而不是“\”,
例化的模块,只需要数据和数据有效位即可,其他的可以置空,当然若其他信号会影响源码,则需要另外考虑。
`timescale 1ns / 1ps
/*****************************************************************
Company : MiLianKe Electronic Technology Co., Ltd.
WebSite:https://www.milianke.com
TechWeb:https://www.uisrc.com
tmall-shop:https://milianke.tmall.com
jd-shop:https://milianke.jd.com
taobao-shop: https://milianke.taobao.com
Description:
第 301页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
The reference demo provided by Milianke is only used for learning.
We cannot ensure that the demo itself is free of bugs, so users
should be responsible for the technical problems and consequences
caused by the use of their own products.
@Author
:
XiaoQingquan
@Time
:
2023/10
version:
:
@Description :
*****************************************************************/
// Define the image resolution here
// `define RESOLUTION_300_220
`define RESOLUTION_640x480
//`define RESOLUTION_1280x720
//`define RESOLUTION_1920x1080
// Input and output file paths
`define INPUT_IMAGE "../../../../picture_bmp/in/002.bmp"
`define OUTPUT_IMAGE "../../../../picture_bmp/out/output.bmp"
// BMP file header size
`define BMP_HEADER_SIZE 54
// Data width for each color channel
`define COLOR_DEPTH 8
`define DATA_WIDTH
24
// Seek constants for file operations
`define SEEK_END 2
// Include resolution-specific parameters
`ifdef RESOLUTION_1920x1080
`define IMAGE_WIDTH 1920
`define IMAGE_HEIGHT 1080
`define HORIZONTAL_BLANKING 720
`define VERTICAL_BLANKING 45
`endif
`ifdef RESOLUTION_1280x720
`define IMAGE_WIDTH 1280
`define IMAGE_HEIGHT 720
`define HORIZONTAL_BLANKING 480
`define VERTICAL_BLANKING 30
`endif
`ifdef RESOLUTION_640x480
`define IMAGE_WIDTH 640
`define IMAGE_HEIGHT 480
`define HORIZONTAL_BLANKING 200
`define VERTICAL_BLANKING 30
第 302页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
`endif
`ifdef RESOLUTION_300_220
`define IMAGE_WIDTH 300
`define IMAGE_HEIGHT 220
`define HORIZONTAL_BLANKING 80
`define VERTICAL_BLANKING 40
`endif
// Calculate total image size and other parameters
`define TOTAL_PIXELS (`IMAGE_WIDTH * `IMAGE_HEIGHT)
`define TOTAL_IMAGE_SIZE (`TOTAL_PIXELS * 3)
`define BMP_FILE_SIZE (`TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE)
`define PIXELS_PER_CLK 4
module picture_test();
// Clock period definition
parameter CLOCK_PERIOD = 2;
// File descriptors for input and output files
integer input_fd;
integer output_fd;
// Variables for file operations and counters
integer read_status, i, j, pixel_idx;
integer output_offset, padding_bytes;
// Arrays to store BMP header and image data
reg [`COLOR_DEPTH-1:0] bmp_header[0:`BMP_HEADER_SIZE-1];
reg [`COLOR_DEPTH-1:0] red_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] green_channel[0:`TOTAL_PIXELS-1];
reg [`COLOR_DEPTH-1:0] blue_channel[0:`TOTAL_PIXELS-1];
// Variables to extract image dimensions from BMP header
wire [31:0] bmp_file_size, bmp_image_width, bmp_image_height;
reg initialization_complete;
// Clock and reset signals
reg I_clk = 0;
reg I_rst_n;
// Counters for simulation
reg [31:0] h_counter, v_counter;
reg [31:0] memory_address;
// Signals for data validity and image data
wire data_valid;
wire [`DATA_WIDTH*4-1:0] input_rgb_data;
第 303页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
wire line_data_valid;
wire [`DATA_WIDTH*4-1:0] line_data;
reg
I_tlast;
wire
I_tuser;
reg
I_tready;
wire
O_tready;
wire
O_tlast;
wire
O_tuser;
reg
de_r0;
reg
data_req;
reg
flag_req;
// Output data counters and status flags
reg [31:0] output_pixel_counter;
reg prev_line_valid;
// Individual color components for output data
wire [`COLOR_DEPTH-1:0] output_R_d0, output_G_d0, output_B_d0;
wire [`COLOR_DEPTH-1:0] output_R_d1, output_G_d1, output_B_d1;
wire [`COLOR_DEPTH-1:0] output_R_d2, output_G_d2, output_B_d2;
wire [`COLOR_DEPTH-1:0] output_R_d3, output_G_d3, output_B_d3;
// Clock generation
always begin
#(CLOCK_PERIOD / 2) I_clk = ~I_clk;
end
// Simulation control and file operations
initial begin
I_rst_n = 0;
I_tready = 0;
padding_bytes = 0;
#(CLOCK_PERIOD * 10);
I_rst_n = 1;
I_tready = 1;
// Wait for initialization to complete
wait(initialization_complete);
$display(">> Initialization complete.");
// Wait until all pixels are processed
wait(output_pixel_counter == (`TOTAL_PIXELS - `PIXELS_PER_CLK));
#(CLOCK_PERIOD * 2);
// Adjust file length to be a multiple of 4 bytes (BMP format requirement)
$fseek(output_fd, 0, `SEEK_END);
padding_bytes = $ftell(output_fd)%4;
padding_bytes = 4 - padding_bytes;
第 304页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
for (i = 0; i < padding_bytes; i = i + 1) begin
$fwrite(output_fd, "%c", 0);
end
// Close all files
$fclose(output_fd);
$display(">> Simulation complete.");
$stop;
end
// Extract image dimensions from BMP header
assign bmp_file_size = {bmp_header[5], bmp_header[4], bmp_header[3], bmp_header[2]};
assign bmp_image_width = {bmp_header[21], bmp_header[20], bmp_header[19], bmp_header[18]};
assign bmp_image_height = {bmp_header[25], bmp_header[24], bmp_header[23], bmp_header[22]};
// Read BMP file and initialize image data
initial begin
initialization_complete = 0;
for (i = 0; i < `TOTAL_PIXELS; i = i + 1) begin
red_channel[i] = 0;
green_channel[i] = 0;
blue_channel[i] = 0;
end
// Open input BMP file
input_fd = $fopen(`INPUT_IMAGE, "rb");
if (input_fd) begin
$display(">> Input file opened successfully.");
// Read BMP header
read_status = $fread(bmp_header, input_fd, 0, `BMP_HEADER_SIZE);
// Read image data (stored in reverse order in BMP files)
for (i = `IMAGE_HEIGHT - 1; i >= 0; i = i - 1) begin
for (j = 0; j < `IMAGE_WIDTH; j = j + 1) begin
pixel_idx = i * `IMAGE_WIDTH + j;
blue_channel[pixel_idx] = $fgetc(input_fd);
green_channel[pixel_idx] = $fgetc(input_fd);
red_channel[pixel_idx] = $fgetc(input_fd);
end
end
$display(">> Image data read successfully.");
end else begin
$display(">> Error opening input file.");
$stop;
end
// Open output file for writing
output_fd = $fopen(`OUTPUT_IMAGE, "wb");
第 305页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
// Write BMP header to output file
for (i = 0; i < `BMP_HEADER_SIZE; i = i + 1) begin
$fwrite(output_fd, "%c", bmp_header[i]);
end
// Set file offset to the beginning of the image data
output_offset = `TOTAL_IMAGE_SIZE + `BMP_HEADER_SIZE - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
initialization_complete = 1;
end
// Instantiate the RGB to HSV conversion module
sharpening #(
.IMG_WIDTH
(`IMAGE_WIDTH),
.IMG_HEIGHT (`IMAGE_HEIGHT)
)
sharpening(
.I_clk
( I_clk ),
.I_rst_n
( I_rst_n ),
.I_tlast
( I_tlast ),
.I_tuser
( I_tuser ),
.I_tdata
( input_rgb_data ),
.I_tvalid
( data_valid ),
.I_tready
( O_tready ),
.O_tlast
( O_tlast ),
.O_tuser
( O_tuser ),
.O_tdata
( line_data ),
.O_tvalid
( line_data_valid ),
.O_tready
( I_tready )
);
// Generate input data and control signals
initial begin
data_req = 1'b0;
#(CLOCK_PERIOD*30);
data_req = 1'b1;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
flag_req <= 0;
else
flag_req <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n)
de_r0 <= 1'b0;
第 306页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
else
de_r0 <= data_req;
end
always @(posedge I_clk or negedge I_rst_n) begin
if(!I_rst_n) begin
h_counter <= 'b0;
v_counter <= 'b0;
memory_address <= 'b0;
I_tlast <= 1'b0;
end else begin
if (de_r0) begin
if (h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH + `HORIZONTAL_BLANKING) begin
h_counter <= 'b0;
if (v_counter + 1 >= `IMAGE_HEIGHT + `VERTICAL_BLANKING) begin
v_counter <= 'b0;
end else begin
v_counter <= v_counter + 1;
end
end else begin
h_counter <= h_counter + `PIXELS_PER_CLK;
end
if (memory_address + `PIXELS_PER_CLK >= `TOTAL_PIXELS) begin
memory_address <= 'b0;
end else if(data_valid) begin
memory_address <= memory_address + `PIXELS_PER_CLK;
end
end
// Generate I_tlast (End of Line)
if (data_valid && I_tready && h_counter + `PIXELS_PER_CLK >= `IMAGE_WIDTH) begin
I_tlast <= 1'b1;
end else begin
I_tlast <= 1'b0;
end
end
end
assign I_tuser = (data_valid && I_tready && h_counter == 0 && v_counter == 0) ? 1:0;
assign data_valid = (h_counter < `IMAGE_WIDTH)&&(v_counter < `IMAGE_HEIGHT)&&(flag_req == 1);
assign input_rgb_data = {red_channel[memory_address + 3], green_channel[memory_address + 3],
blue_channel[memory_address + 3],
red_channel[memory_address + 2], green_channel[memory_address + 2],
blue_channel[memory_address + 2],
red_channel[memory_address + 1], green_channel[memory_address + 1],
blue_channel[memory_address + 1],
red_channel[memory_address
blue_channel[memory_address
]};
第 307页
], green_channel[memory_address
],
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
// Extract individual color components from output data
assign {output_R_d3, output_G_d3, output_B_d3,
output_R_d2, output_G_d2, output_B_d2,
output_R_d1, output_G_d1, output_B_d1,
output_R_d0, output_G_d0, output_B_d0} = line_data;
// Write output data to file
always @(posedge I_clk or negedge I_rst_n) begin
if (!I_rst_n) begin
output_pixel_counter <= 0;
prev_line_valid <= 0;
end else begin
prev_line_valid <= line_data_valid;
// If HSV data is valid, write to output file
if (line_data_valid ) begin
$fwrite(output_fd, "%c", output_B_d0);
$fwrite(output_fd, "%c", output_G_d0);
$fwrite(output_fd, "%c", output_R_d0);
$fwrite(output_fd, "%c", output_B_d1);
$fwrite(output_fd, "%c", output_G_d1);
$fwrite(output_fd, "%c", output_R_d1);
$fwrite(output_fd, "%c", output_B_d2);
$fwrite(output_fd, "%c", output_G_d2);
$fwrite(output_fd, "%c", output_R_d2);
$fwrite(output_fd, "%c", output_B_d3);
$fwrite(output_fd, "%c", output_G_d3);
$fwrite(output_fd, "%c", output_R_d3);
output_pixel_counter <= output_pixel_counter + `PIXELS_PER_CLK;
end else if (prev_line_valid) begin
// Move file pointer to the previous line for BMP format
output_offset = output_offset - `IMAGE_WIDTH * 3;
$fseek(output_fd, output_offset, 0);
end
end
end
endmodule
第 308页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
17.4 仿真结果
17.4.1 仿真波形图结果
17.4.2 仿真图片结果
可以看见,左边的图是原图,右边的图是经过锐化处理后的图,这个图明显要更加清晰了,但是整个却显得有
些许僵硬,不过对于本身就模糊的图像来说,这个锐化操作算是利大于弊了。
第 309页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
17.5 上板结果
可以看见,这个图由于锐化的效果,上面的字都是清晰可见的,这里作者用的权重系数为 8,读者也可以试试
其他的值。
17.6Python 实现
17.6.1 代码实现
import cv2
import numpy as np
def laplacian_sharpening(image_path, output_path):
第 310页
米联客(MILIANKE)www.uisrc.com www.milianke.com
常州米联客信息科技有限公司
Image processing course advanced(2024)
# 读取图像
image = cv2.imread(image_path)
if image is None:
raise ValueError("图像读取失败,请检查路径。")
# 定义拉普拉斯核
kernel = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
# 应用拉普拉斯锐化
sharpened_image = cv2.filter2D(image, -1, kernel)
# 保存结果为 BMP 格式
cv2.imwrite(output_path, sharpened_image)
# 使用示例
laplacian_sharpening('003.bmp', 'output.bmp')
在 laplacian_sharpening 后面输入想要锐化的图片即可,没有相应的库需要下载相应的库。
17.6.2 结果显示
可以看见,左边的图为原图,右边的图是经过锐化后面的图,图片由原来的模糊转变为现在的清晰,整体的处理效
果还是很不错的。
第 311页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
18.FPGA 实现 ISP
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
登录“米联客”FPGA 社区-www.uisrc.com 视频课程、答疑解惑!
18.1ISP 简介
图像信号处理器(ISP, Image Signal Processor)是一种特殊的硬件或专用模块,主要用于对摄像头传感器(CMOS
或 CCD)采集的原始图像数据进行处理和优化,最终生成高质量的、可视化的图像供后续的存储或显示使用。ISP 原
理简单来讲,就是通过一系列算法和处理模块,修正和增强图像,确保最终的输出质量达到适合人眼观看的水平。
由于摄像头传感器采集到的是未经过处理的原始数据(也称为未处理数据,如 Bayer 格式),因此这种数据通
常不能被直接用于显示或分析,必须经过一系列的图像处理流程,这就是 ISP 的工作范畴。
18.2 设计分析
这里就是把前文所提到的算法统筹合一,形成 ISP,对于这里就不在赘述每个模块的作用,详细可以看前面章
节的详细分析和介绍。此 ISP 包含了黑电平校正、去马赛克、自动白平衡、伽马校正、饱和度调节、亮度调节和锐
化、去噪等算法,此处就直接上板,直接演示上板后的图像了。所有的模块都制成了 IP 放入的 uisrc 文件下的 ip 文
件中。
18.3 上板结果
这里给的图都是经过压缩后的图,图片画质有所降低,所以可能没有那么清楚,可以看见在图中的画面虽然比
较清晰,但是因为加了锐化算法和滤波算法,导致图片有些许生硬,这里主要是做一个算法的总体演示,读者可以
根据具体的需求去加入算法,有些图像本身就很清晰了的话就不用加入这个算法了,不过这对于原本就不清晰的图
像来说,锐化是一个非常好的算法了,但是如果放在分辨率非常之高的图像中,比如 4K 甚至 8K 中,我们需要酌
情去加入锐化操作,或者调低锐化的效果都是可以的,这里主要是做一个统一的展示,读者可以根据自己的需要去
加入或者删除一些算法。
由于最终的图像出来在最上侧有一些数据问题,所以作者在其中加入了一个图像剪裁的模块,对最上面的数据
进行了一个简单的剪裁,让最终的图像效果更加完好。
第 312页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
第 313页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
19.结语
关于 ISP 的讲解视频,我们会在明年完成,如果有需要的话,在明年还会继续发布关于 FPGA 图像处理的下一
版的内容,里面会包含更多的图像算法以及分享一些关于在图像处理中所获得的经验,并且在后续可能会专门开设
一个关于 FPGA 图像处理的网站以供大家讨论和学习,让大家共同进步。
希望这篇 FPGA 图像处理文档能对大家的有所帮助,谢谢!
第 314页
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
附录一 :软件安装
1.Python 安装教程
1.1 软件获取连接: https://pan.baidu.com/s/1kLQz9_RMugx7KVWGpc6Vkw?pwd=1111
1.2 下载好软件后,双击进行安装
选择自定义安装
点击 NEXT
第 315页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
选择安装路径
等待安装过程
第 316页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
安装完成后选择关闭
第 317页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
2 PyCharm 安装教程
2.1 软件获取连接: https://pan.baidu.com/s/1uyz9_QTAq2ISUZiTBf3brg?pwd=1111
2.2 下载好软件后,双击进行安装
点击下一步
选择安装路径
第 318页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
配置 PyCharm 安装
点击安装
安装完成后需重启电脑
第 319页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
2.3 双击启动 PyCharm
选择继续
第 320页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
选择使用 30 天
选择新建一个项目,选择欢迎脚本,选择 Python 解释器
第 321页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
点击创建
第 322页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
打开工程后可选择在设置中安装汉化包插件
第 323页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
下载安装完成插件,重启 PyCharm 即可生效
2.4 运行文件看环境是否配置成功
第 324页
Image processing course advanced(2024)
常州米联客信息科技有限公司
米联客(MILIANKE)www.uisrc.com www.milianke.com
Image processing course advanced(2024)
附录二 :常见问题链接
1 联系方式
技术交流群网址: https://www.uisrc.com/f-380.html 查看最新可以加入的 QQ 群
技术微信:18951232035
技术电话:18951232035
官方微信公众号(新微信公众号):
2 售后
1、7 天无理由退货(人为原因除外)
2、质保期限:本司产品自快递签收之日起,提供一年质保服务(主芯片,比如 FPGA 或者 CPU 等除外)。
3、维修换货,需提供淘宝订单编号或合同编号,联系销售/技术支持安排退回事宜。
售后维修请登录工单系统:https://www.uisrc.com/plugin.php?id=x7ree_service
4、以下情形不属于质保范畴。
A:由于用户使用不当造成板子的损坏:比如电压过高造成的开发板短路,自行焊接造成的焊盘脱落、铜线起皮 等
B:用户日常维护不当造成板子的损坏:比如放置不当导致线路板腐蚀、基板出现裂纹等
5、质保范畴外(上方第 4 条)及质保期限以外的产品,本司提供有偿维修服务。维修仅收取器件材料成本,往返
运 费全部由客户承担。
6、寄回地址,登录网页获取最新的售后地址:https://www.uisrc.com/t-1982.html
3 销售
天猫米联客旗舰店:https://milianke.tmall.com
京东米联客旗舰店:https://milianke.jd.com/
FPGA|SOC 生态店:https://milianke.taobao.com
销售电话:18921033576
常州溧阳总部:常州溧阳市中关村吴潭渡路雅创高科制造谷 10-1 幢楼
4 在线视频
https://www.uisrc.com/video.html
5 资源下载
https://www.uisrc.com/download.html
6 软件或其他下载
https://www.uisrc.com/f-download.html
第 325页
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )