问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 34 人浏览分享

开启左侧

FPGA图像处理-视频水印效果处理

[复制链接]
34 0
安路-FPGA课程
安路课程: 图像算法 » 图像新手入门实验
安路系列: EG4
本帖最后由 UT发布 于 2025-4-3 09:24 编辑

软件版本:Anlogic -TD5.6.1-64bit
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
登录米联客”FPGA社区-www.uisrc.com视频课程、答疑解惑!
1概述

本文简述了视频水印效果的算法,讲解如何进行Verilog的算法实现,并进行上板实验。

2算法原理简介

视频水印效果就是在实时的视频流中添加特定的图片,就是图片叠加在视频流里。先划定一块区域用于填充水印,把水印图片存储在固定的ROM块中,每来一帧图像便刷新一次水印进去。如图所示,需要在显示时计算出蓝色方块出现的位置即显示的位置坐标,等到行列刷新到时这个位置时从ROM中取出水印的图像。

image.jpg

3算法仿真
3.1Verilog算法仿真
3.1.1Modelsim仿真
3.1.1.1仿真执行

在件夹Algorithm_simulation下进行算法的仿真,分为simsrctb三个子文件夹。在sim文件夹下有win系统的快捷执行文件sim.bat,可以一键进行仿真,src文件下放的是Verilog的核心图像算法及其顶层与输入图像激励,tb文件下放的是测试激励文件及输出图像的保存。

双击执行sim文件夹下sim.bat,自动打开Modelsim仿真,自动添加仿真波形,执行完成后自动保存图像,仿真波形如图所示:

image.jpg
3.1.1.2仿真关键部分代码解析

Sim.do执行仿真代码,文件内容如下:

  1. #
  2. # Create work library
  3. #
  4. vlib work
  5. #
  6. # Compile sources
  7. #
  8. vlog "../src/*.v"
  9. vlog "../tb/*.v"
  10. #
  11. # Call vsim to invoke simulator
  12. #
  13. vsim -voptargs=+acc work.top_tb
  14. #
  15. # Add waves
  16. #
  17. do wave.do
  18. #
  19. # Run simulation
  20. #
  21. run -all
  22. #
  23. # End
复制代码

图像输入代码部分:

  1. reg                 en;
  2. reg [12:0]         h_syn_cnt = 'd0;
  3. reg [12:0]         v_syn_cnt = 'd0;
  4. reg [23:0]         image [0 : H_ACTIVE*V_ACTIVE-1];
  5. reg [31:0]         image_cnt = 'd0;
  6. //读取txt文件到image数组中
  7. initial begin
  8.         $readmemh("../matlab_src/image_720_1280_3.txt", image);
  9. end
  10. // 行扫描计数器
  11. always@(posedge i_clk)
  12. begin
  13.         if(h_syn_cnt == H_TOTAL_TIME-1)
  14.         h_syn_cnt <= 0;
  15.     else
  16.         h_syn_cnt <= h_syn_cnt + 1;
  17. end
  18. // 列扫描计数器
  19. always@(posedge i_clk)
  20. begin
  21.         if(h_syn_cnt == H_TOTAL_TIME-1)
  22.         begin
  23.         if(v_syn_cnt == V_TOTAL_TIME-1)
  24.             v_syn_cnt <= 0;
  25.         else
  26.             v_syn_cnt <= v_syn_cnt + 1;
  27.         end
  28. end
  29. // 行同步控制
  30. always@(posedge i_clk)
  31. begin
  32.     if(h_syn_cnt < H_SYNC_TIME)
  33.         o_hsyn <= 0;
  34.     else
  35.         o_hsyn <= 1;
  36. end
  37. // 场同步控制
  38. always@(posedge i_clk)
  39. begin
  40.     if(v_syn_cnt < V_SYNC_TIME)
  41.         o_vsyn <= 0;
  42.     else
  43.         o_vsyn <= 1;
  44. end
  45. // 坐标使能.
  46. always@(posedge i_clk)
  47. begin
  48.     if(v_syn_cnt >= V_SYNC_TIME + V_BACK_PORCH && v_syn_cnt < V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE)
  49.     begin
  50.         if(h_syn_cnt >= H_SYNC_TIME + H_BACK_PORCH && h_syn_cnt < H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE)
  51.             en <= 1;
  52.         else
  53.             en <= 0;
  54.     end
  55.     else
  56.         en <= 0;
  57. end
  58. always@(posedge i_clk)
  59. begin
  60.     if(en)
  61.         begin
  62.                 o_r                 <= image[image_cnt][23:16];
  63.                 o_g                 <= image[image_cnt][15:8];
  64.                 o_b                 <= image[image_cnt][7:0];
  65.             image_cnt         <= image_cnt + 1;
  66.         end
  67.         else if(image_cnt == H_ACTIVE*V_ACTIVE)
  68.         begin
  69.                 o_r                 <= 8'h00;
  70.                 o_g                 <= 8'h00;
  71.                 o_b                 <= 8'h00;
  72.             image_cnt         <= 'd0;
  73.         end        
  74.     else
  75.         begin
  76.                 o_r                 <= 8'h00;
  77.                 o_g                 <= 8'h00;
  78.                 o_b                 <= 8'h00;
  79.             image_cnt         <= image_cnt;
  80.         end        
  81. end
  82. always@(posedge i_clk)
  83. begin
  84.         // if(image_cnt >= H_ACTIVE*V_ACTIVE)
  85.                 // o_en <= 0;
  86.         // else
  87.                 o_en <= en;
  88. end
复制代码

图像输出保存代码部分:

  1. reg             clk;
  2. reg             rst_n;
  3. integer                 image_txt;
  4. reg [31:0]                 pixel_cnt;
  5. wire[23:0]          data;
  6. wire            de;
  7. top u_top
  8. (
  9.     .i_clk                              (clk                ),
  10.     .i_rst_n                      (rst_n              ),
  11.     .o_gray_data             (data               ),
  12.     .o_gray_de               (de                 )
  13. );
  14. always #(1) clk = ~clk;
  15. initial
  16. begin
  17.         clk   = 1;
  18.     rst_n = 0;         
  19.         #100
  20.     rst_n = 1;
  21.         
  22. end
  23. glbl glbl();
  24. initial
  25. begin
  26.     image_txt = $fopen("../matlab_src/image_720_1280_3_out.txt");
  27. end
  28. always@(posedge clk or negedge rst_n)
  29. begin
  30.     if(!rst_n)
  31.         begin
  32.         pixel_cnt <= 0;
  33.     end
  34.     else if(de)
  35.         begin
  36.         pixel_cnt = pixel_cnt + 1;
  37.         $fwrite(image_txt,"%h\n",data);
  38.     end
  39. end
  40. always@(posedge clk )
  41. begin
  42.         if(pixel_cnt == 720*1280)
  43.         begin
  44.                 $display("*******************************************************************************");               
  45.                 $display("*** Success:image_720_1280_3_out.txt is output complete! %t", $realtime, "ps***");
  46.                 $display("*******************************************************************************");
  47.                         $fclose(image_txt);
  48.                 $stop;
  49.         end        
  50. end
复制代码
3.1.2Modelsim实验结果

matlab查看输入输出的图像代码部分:

  1. clear;clear all;clc;
  2. row = 720;  
  3. col = 1280;  
  4. n   = 3;   
  5. image_sim_pass = uint8(zeros(row,col,n));
  6. fid = fopen('image_720_1280_3_out.txt','r');
  7. for x = 1:row
  8.     for y = 1:col
  9.         RGB = fscanf(fid,'%s',1);
  10.         image_sim_pass(x,y,1) = uint8(hex2dec(RGB(1:2)));
  11.         image_sim_pass(x,y,2) = uint8(hex2dec(RGB(3:4)));
  12.         image_sim_pass(x,y,3) = uint8(hex2dec(RGB(5:6)));              
  13.     end
  14. end
  15. fclose(fid);
  16. image_1 = imread('lena_1280x720.jpg');
  17. subplot(121);
  18. imshow(image_1), title('The original image');
  19. subplot(122);
  20. imshow(image_sim_pass),title('After processing images');
  21. imwrite(image_sim_pass,'lena_720x128_sim_pass.jpg');   
复制代码
image.jpg
4工程实现
4.1Verilog代码分析
定义水印的大小和坐标。
  1. parameter  H_ACTIVE                 = 128; //水印区域宽度                              
  2. parameter  V_ACTIVE                 = 36;  //水印区域高度
  3. parameter  BEGIN_X          = 891; //水印起始坐标
  4. parameter  BEGIN_Y          = 5; //水印起始坐标
  5. 变量声明。
  6. reg  [10:0]             h_cnt;
  7. reg  [10:0]             v_cnt;
  8. reg  [10:0]             x_pos;
  9. reg  [10:0]             y_pos;
  10. reg  [12:0]                 rd_addr;
  11. reg                                        o_de;
  12. reg                                        o_de1;
  13. reg                                 hsyn_d0;
  14. reg                                        vsyn_d0;
  15. reg                                        en_pos_d0;
  16. reg                                 hsyn_d1;
  17. reg                                        vsyn_d1;
  18. reg                                        en_pos_d1;
  19. reg  [7:0]                  r_d;
  20. reg  [7:0]                  g_d;
  21. reg  [7:0]                  b_d;
  22. reg  [7:0]                  r_d1;
  23. reg  [7:0]                  g_d1;
  24. reg  [7:0]                  b_d1;
  25. wire [7:0]                  r_d0;
  26. wire [7:0]                  g_d0;
  27. wire [7:0]                  b_d0;
  28. wire                                   de_d0;//显示区域使能信号
复制代码
输出信号赋值。
  1. assign o_r   = o_de1 ? r_d0 : r_d1;
  2. assign o_g   = o_de1 ? g_d0 : g_d1;
  3. assign o_b   = o_de1 ? b_d0 : b_d1;
  4. assign o_hs  = hsyn_d1;
  5. assign o_vs  = vsyn_d1;
  6. assign o_en  = en_pos_d1;
复制代码
水印区域使能计算。
  1. assign de_d0 = i_en_pos && (x_pos >= BEGIN_X)&&(x_pos < BEGIN_X + H_ACTIVE)&&
  2.                            (y_pos >= BEGIN_Y)&&(y_pos < BEGIN_Y + V_ACTIVE) ? 1'b1:1'b0;
  3. //同步输出使能信号
  4. always@(posedge i_clk )
  5. begin        
  6.         hsyn_d0                <= i_hsyn;
  7.         vsyn_d0                <= i_vsyn;
  8.         en_pos_d0        <= i_en_pos;
  9.         hsyn_d1                <= hsyn_d0;        
  10.         vsyn_d1                <= vsyn_d0;        
  11.         en_pos_d1        <= en_pos_d0;        
  12.         r_d                        <= i_r;
  13.         g_d                        <= i_g;
  14.         b_d                        <= i_b;
  15.         r_d1                <= r_d;
  16.         g_d1                <= g_d;
  17.         b_d1                <= b_d;        
  18. end
  19. //x计数
  20. always@(posedge i_clk or negedge i_rst_n)
  21. begin
  22.     if(!i_rst_n)
  23.         begin
  24.         x_pos <= 11'd0;
  25.     end
  26.     else if(i_en_pos)
  27.         begin
  28.                 if(x_pos == 1024 - 1'b1)
  29.                         x_pos <= 11'd0;
  30.                 else
  31.                         x_pos <= x_pos + 11'd1;
  32.     end
  33. end
  34. //y计数
  35. always@(posedge i_clk or negedge i_rst_n)
  36. begin
  37.     if(!i_rst_n)
  38.         begin
  39.         y_pos <= 11'd0;
  40.     end
  41.     // else if(x_pos == 1280 - 1'b1)
  42.     else if(!i_en_pos && en_pos_d0)        
  43.         begin
  44.                 if(y_pos == 600 - 1'b1)
  45.                         y_pos <= 11'd0;
  46.                 else
  47.                         y_pos <= y_pos + 11'd1;
  48.     end
  49. end
  50. //显示区域行计数
  51. always@(posedge i_clk or negedge i_rst_n)
  52. begin
  53.     if(!i_rst_n)
  54.         begin
  55.         h_cnt <= 11'd0;
  56.     end
  57.     else if(de_d0)
  58.         begin
  59.                 if(h_cnt == H_ACTIVE - 1'b1)
  60.                         h_cnt <= 11'd0;
  61.                 else
  62.                         h_cnt <= h_cnt + 11'd1;
  63.     end
  64. end
  65. //显示区域场计数
  66. always@(posedge i_clk or negedge i_rst_n)
  67. begin
  68.     if(!i_rst_n)
  69.         begin
  70.         v_cnt <= 11'd0;
  71.     end
  72.     else if(h_cnt == H_ACTIVE - 1'b1)
  73.         begin
  74.                 if(v_cnt == V_ACTIVE - 1'b1)
  75.                         v_cnt <= 11'd0;
  76.                 else
  77.                         v_cnt <= v_cnt + 11'd1;
  78.     end
  79. end
  80. //水印显示区域存储ROM
  81. image_36_128_rom u_image_buffer(
  82.         .doa        ({r_d0,g_d0,b_d0}),
  83.         .addra        (rd_addr                 ),
  84.         .clka        (i_clk                         ),
  85.         .rsta        (1'b0                         )
  86. );
  87. //读取地址更新
  88. always@(posedge i_clk or negedge i_rst_n)
  89. begin
  90.     if(!i_rst_n)
  91.         begin
  92.         rd_addr <= 'd0;
  93.     end
  94.     else if(de_d0)
  95.         begin
  96.                 rd_addr <= v_cnt * H_ACTIVE + h_cnt;
  97.     end
  98. end
  99. //同步输出使能信号
  100. always@(posedge i_clk )
  101. begin
  102.         o_de         <= de_d0;
  103.         o_de1         <= o_de;        
  104. end
复制代码
4.2工程结构
工程结构如图所示:
image.jpg

图像数据通过摄像头采集进来,先缓存在fifo中,然后通过写状态机,将图像数据送进DDR进行缓存,缓存后的图像数据从DDR中取出,通过读状态机送出到fifo中,然后算法处理模块在fifo中取出数据,完成数据处理后送到LCD进行显示输出。

5上板实验
image.jpg

点击下载后,可以看到正常的输出如下所示,摄像头的分辨率为640x480水印叠加在整个视频上,如图所示:

image.jpg
image.jpg



































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

本版积分规则

0

关注

0

粉丝

272

主题
精彩推荐
热门资讯
网友晒图
图文推荐

  • 微信公众平台

  • 扫描访问手机版