[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_图像入门连载-6FPGA 实现图像 Gamma 伽马变换

文档创建者:FPGA课程
浏览次数:80
最后更新:2024-10-17
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 8-FPGA图像入门
本帖最后由 FPGA课程 于 2024-10-17 13:24 编辑

​软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1 图像伽马变换算法简介
伽马变换主要用于图像的校正,将灰度过高或者灰度过低的图片进行修正,增强对比度,简单的说就是让图像 从曝光强度的线性响应变得更接近人眼感受的响应。变换公式就是对原图像上每一个像素值做乘积运算:
g= c* rY
其中 c 为常数系数,r 为图像像素值,取值范围 0~255,Y为伽马变换因子,Y值以 1 为分界,值越小,对图像 低灰度部分的扩展作用就越强,值越大,对图像高灰度部分的扩展作用就越强,通过不同的Y值,就可以达到增强 低灰度或高灰度部分细节的作用。伽马变换对于图像对比度偏低,并且整体亮度值偏高(对于相机过曝)情况下的 图像增强效果明显。
伽马变换对图像的修正作用其实就是通过增强低灰度或高灰度的细节实现的,从伽马曲线可以直观理解:
ebf97ad754c84eba873da0487656beb5.jpg
我们之所以对图像进行 gamma 变换是因为人眼对外界光源的感光值与输入光强不是呈线性关系的,而是呈指 数型关系的。在低照度下,人眼更容易分辨出亮度的变化,随着照度的增加,人眼不易分辨出亮度的变化。而摄像 机感光与输入光强呈线性关系。为能更有效的保存图像亮度信息,需进行 Gamma 变换。未经 Gamma 变换和经过 Gamma 变换保存图像信息如下图:可以观察到,未经 Gamma 变换的情况下,低灰度时,有较大范围的灰度值被保 存成同一个值,造成信息丢失;同时高灰度值时,很多比较接近的灰度值却被保存成不同的值,造成空间浪费。经 过 Gamma 变换后,改善了存储的有效性和效率。
下图中第一幅图为原图,第二幅图系数为 0.75,第三幅图系数为 1.5。由图中显示的信息可得第二幅比第一幅 图明显增亮,第三幅图则比第一幅图更暗淡。

7630c4b96d854e869ca688c1918527d6.jpg
2 设计分析
2.1Matlab代码分析
  1. [row,col,n] = size(image_in);
  2. image_out =imadjust(image_in,[],[],0.75); %imadjust 对图像灰度进行调整并调高亮度,第一个[]为原图中要变换 的灰度范围,第二个[]为变换后的灰度范围
  3. image_out1=imadjust(image_in,[],[],1.5);

  4. figure
  5. subplot(131);
  6. imshow(image_in), title('the original image'); subplot(132);
  7. imshow(image_out), title('the translated image '); subplot(133);
  8. imshow(image_out1), title('the translated image 1');

  9. //使用matlab 生成伽马变换后系数的代码如下: clear;clear all;clc;

  10. num = 256;

  11. r = [0:1:255];

  12. c =16;

  13. g = c*sqrt(r);

  14. %==========================写.coe 文件========================== fid = fopen('gamma_sqrt_para_256.coe','w');

  15. fprintf(fid,'memory_initialization_radix = 10;\n'); fprintf(fid,'memory_initialization_vector =\n');
  16. for n = 1:num
  17. gamma(n) = round(g(n)); end

  18. for n = 1: num - 1
  19. fprintf(fid,'%d, \n',gamma(n)); end

  20. fprintf(fid,'%d;',gamma(256)); fclose(fid);

  21. %============================写 rom 存储器=============================== fid1 = fopen('../src/image_rom_gamma_sqrt_para.v','w');
  22. fprintf(fid1,'module image_rom_gamma_sqrt_para\n'); fprintf(fid1,'(\n');
  23. fprintf(fid1,'    input                                clka,\n');
  24. fprintf(fid1,'    input                [7:0]addra,\n');
  25. fprintf(fid1,'    input                                ena,\n');
  26. fprintf(fid1,'    output              [7:0]douta\n');
  27. fprintf(fid1,');\n');
  28. fprintf(fid1,'reg [7:0] DATA;\n');
  29. fprintf(fid1,'assign  douta = DATA;\n'); fprintf(fid1,'always@(*)\n');
  30. fprintf(fid1,'begin\n');
  31. fprintf(fid1,'    case(addra)\n');

  32. for n = 1:num
  33. gamma(n) = round(g(n)); end

  34. for n = 1: num
  35. fprintf(fid1,'%d : DATA <= %d; \n',n-1,gamma(n)); end
  36. fprintf(fid1,'      default:      DATA<= 0;\n');
  37. fprintf(fid1,'    endcase\n'); fprintf(fid1,'end\n');
  38. fprintf(fid1,'endmodule\n'); fclose(fid1);
  39. %=================================================================





  40. g1 = (r.^2)/255; %系数为 1
  41. %================================================================= fid = fopen('gamma_square_para_256.coe','w');
  42. fprintf(fid,'memory_initialization_radix = 10;\n'); fprintf(fid,'memory_initialization_vector =\n');

  43. for n = 1:num
  44. gamma(n) = round(g1(n)); end

  45. for n = 1: num - 1
  46. fprintf(fid,'%d, \n',gamma(n)); end

  47. fprintf(fid,'%d;',gamma(256)); fclose(fid);

  48. %================================================================= fid1 = fopen('../src/image_rom_gamma_square_para.v','w');

  49. fprintf(fid1,'module image_rom_gamma_square_para\n'); fprintf(fid1,'(\n');
  50. fprintf(fid1,'    input                                clka,\n');
  51. fprintf(fid1,'    input                [7:0]addra,\n');
  52. fprintf(fid1,'    input                                ena,\n');
  53. fprintf(fid1,'    output              [7:0]douta\n');
  54. fprintf(fid1,');\n');
  55. fprintf(fid1,'reg [7:0] DATA;\n');
  56. fprintf(fid1,'assign  douta = DATA;\n'); fprintf(fid1,'always@(*)\n');
  57. fprintf(fid1,'begin\n');
  58. fprintf(fid1,'    case(addra)\n');

  59. for n = 1:num
  60. gamma(n) = round(g1(n)); end

  61. for n = 1: num
  62. fprintf(fid1,'%d : DATA <= %d; \n',n-1,gamma(n)); end
  63. fprintf(fid1,'      default:      DATA<= 0;\n');
  64. fprintf(fid1,'    endcase\n'); fprintf(fid1,'end\n');
  65. fprintf(fid1,'endmodule\n'); fclose(fid1);
  66. %================================================================

  67. hold on
  68. plot(r);   
  69. plot(g);   
  70. plot(g1);
  71. legend('f','gamma g','gamma g1');
  72. hold off
复制代码

2.2Verilog代码分析
由于提前使用 matlab 计算好了伽马变换后的值,这里代码很简单直接查表就行。
  1. assign o_hs = i_hsyn; assign o_vs = i_vsyn; assign o_en = i_en;
  2. generate
  3. if (GAMMA_ALGORITHM == "GAMMA_SQUARE") begin
  4. image_rom_gamma_square_para u  i  r (
  5. .clka(i_clk              ),
  6. .addra      (i_r          ),
  7. .ena (1'b1                ),
  8. .douta      (o_r         )
  9. );

  10. image_rom_gamma_square_para u_i_g (
  11. .clka(i_clk              ),
  12. .addra      (i_g         ),
  13. .ena (1'b1                ),
  14. .douta      (o_g        )
  15. );

  16. image_rom_gamma_square_para u  i  b (
  17. .clka(i_clk              ),
  18. .addra      (i_g         ),
  19. .ena (1'b1                ),
  20. .douta      (o_b        )
  21. ); end
  22. elseif(GAMMA_ALGORITHM == "GAMMA_SQRT") begin
  23. image_rom_gamma_sqrt_para u  i  r (
  24. .clka(i_clk              ),
  25. .addra      (i_r          ),
  26. .ena (1'b1                ),
  27. .douta      (o_r         )
  28. );

  29. image_rom_gamma_sqrt_para u_i_g (
  30. .clka(i_clk              ),
  31. .addra      (i_g         ),
  32. .ena (1'b1                ),
  33. .douta      (o_g        )
  34. );

  35. image_rom_gamma_sqrt_para u  i  b (
  36. .clka(i_clk              ),
  37. .addra      (i_g         ),
  38. .ena (1'b1                ),
  39. .douta      (o_b        )
  40. ); end
  41. endgenerate
复制代码

3 工程结构分析
我们将图像 GAMMA 变换的模块做成 IP 后,在vivado 中进行工程的搭建,工程结构如图所示:
1e57c40733234998acb8ad0e996a6252.jpg
4 仿真及结果
4.1Matlab实验结果

2ab98597c3a541e4a8d0a8859dc05eb7.jpg
4.2Modelsim实验结果

73e66094824546a2969fe6355eaf6bf6.jpg
5 搭建 Vitis-sdk 工程
创建 soc_base  sdk  platform  和 APP  工程的过程不再重复,可以阅读 3-3-01_sdk_base_app。以下给出创建好 soc_base sdk platform 的截图和对应工程 APP 的截图。
5.1 创建 SDKPlatform工程
25dc827527cb409fa537af7d1fb6c184.jpg
5.2SDKAPP工程

133d2f6381044faba51e0f7348ae1032.jpg

6 硬件连接
硬件连接如图所示:
6940bcc5960743558f92d3329acb054a.jpg
7 上板实验结果
实验结果如图所示:
4fdcc4ddc77346d4963e9acebe4599b4.jpg

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则