对于图像的灰度处理,原理与基于FPGA的图像反转相同,但算法不同。相交于基于FPGA的图像反转,基于FPGA的图像灰度处理操作时间由于FPGA的并行性,其处理时间与前者相同。虽然工作量大了4倍左右,但处理时间基本相同,在仿真中,仍在5.2ms完成了处理。凸显出FPGA图像处理的优势特点。下文将对FPGA图像灰度处理各部分进行讲解。
- 处理效果
先上处理效果,以下为对我妹妹的脸部进行灰度处理效果。
512*512 处理前
512*512 处理后
- 处理过程
通过python使用PILLOW,获得输入bmp图片的RGB值,并将R/G/B三个分量分别以16进制写入三个txt文件中。再通过vivado仿真FPGA处理,读取三个txt文件数据分别到三个寄存器中。再从寄存器中读取数据,以verilog语言进行RGB转YCbCr格式处理。在格式转换过程中,同时以两个always模块处理乘、加和一个assig取高8位进行运算。得到YCbCr的Y分量之后,将Y分量输出到一个txt文件中,即为灰度转换的512*512图片的结果。通过python使用OpenCV将txt文件读取,分配到512*512个像素中,即可得到灰度处理后的bmp图像。
2.1读取lzy.bmp图像,通过配置miniconda环境中的PILLOW库,读取图片RGB数据,分离输出RGB的值到red、green、blue.txt文件。
- from PIL import Image
-
- # 打开图像文件
- image = Image.open('lzy.bmp') # 图像文件路径
-
- # 获得图像的 RGB 数据
- rgb_values = list(image.getdata())
-
- # 分离 R、G、B 值
- r_values = [rgb[0] for rgb in rgb_values]
- g_values = [rgb[1] for rgb in rgb_values]
- b_values = [rgb[2] for rgb in rgb_values]
-
- # 将 R、G、B 值写入文本文件
- with open('red.txt', 'w') as file:
- for value in r_values:
- file.write(format(value, '02X') + '\n')
-
- with open('green.txt', 'w') as file:
- for value in g_values:
- file.write(format(value, '02X') + '\n')
-
- with open('blue.txt', 'w') as file:
- for value in b_values:
- file.write(format(value, '02X') + '\n')
-
- # 关闭图像文件
- image.close()
2.2在vivado中用Verilog语言编写RGB转YCbCr源文件、并编写testbench文件读取数据进行仿真。在源文件中,对于YCbCr格式由于在Verilog语言中,对浮点运算处理较为复杂,所以乘100转为整数数据处理,简化运算。通过Y =(77 *R + 150*G + 29 *B)>>8,进行计算,先进行乘法运算,再进行加法运算,最后取高8位,得到应输出的Y值。
Source:
- module rgb_to_ycbcr
- (
- input clock,
- input rst,
- input [7:0] input_red_data,
- input [7:0] input_green_data,
- input [7:0] input_blue_data,
-
- output [7:0] output_gray_data
- );
-
- reg [15:0] img_red_r0;
- reg [15:0] img_green_r0;
- reg [15:0] img_blue_r0;
-
- always@(posedge clock or negedge rst)
- begin
- if(rst)
- begin
- img_red_r0 <= 0;
- img_green_r0 <= 0;
- img_blue_r0 <= 0;
- end
- else
- begin
- img_red_r0 <= input_red_data * 8'd77;
- img_green_r0 <= input_green_data * 8'd150;
- img_blue_r0 <= input_blue_data * 8'd29;
- end
- end
- reg [15:0] img_Y_r0;
- always@(posedge clock or negedge rst)
- begin
- if(rst)
- begin
- img_Y_r0 <= 0;
- end
- else
- begin
- img_Y_r0 <= img_red_r0 + img_green_r0 + img_blue_r0;
- end
- end
- assign output_gray_data = img_Y_r0[15:8];
- endmodule
在testbench仿真文件中,通过分别读取先前输出的red/green/blue.txt文件到,red/green/blue_data寄存器中,设置基本仿真条件,从寄存器输入数据到input_red/green/blue_data中。创建gray.txt文件,将输出结果output_gray_data输入到gray.txt文件中,即可得到灰度处理后的灰度值。
Simulation:
- `timescale 1ns/1ps
- module rgb_to_ycbcr_tb;
- reg clock;
- reg rst;
-
- reg [7:0] red_data [(512*512-1):0];
- reg [7:0] green_data [(512*512-1):0];
- reg [7:0] blue_data [(512*512-1):0];
-
- reg[18:0] cnt;
-
- integer file_id;
-
- wire[7:0] input_red_data;
- wire[7:0] input_green_data;
- wire[7:0] input_blue_data;
-
- wire[7:0] output_gray_data;
-
- initial begin
-
- clock = 1'b0;
- forever #10 clock = ~clock;
- end
- initial begin
- cnt = 19'b0;
- $readmemh("./red.txt", red_data);
- $readmemh("./green.txt",green_data);
- $readmemh("./blue.txt",blue_data);
- file_id = $fopen("./gray.txt", "w");
- end
-
- initial begin
- rst = 1'b1;
- #195 rst = 1'b0;
- #20000000 $stop;
- $fclose(file_id);
- end
-
- assign input_red_data = red_data[cnt[17:0]];
- assign input_green_data = green_data[cnt[17:0]];
- assign input_blue_data = blue_data[cnt[17:0]];
-
- always @(posedge clock or posedge rst)
- if (rst) begin /
- cnt <= 19'b0; /
- end /
- else if(cnt[18] == 1'b0) /
- begin /
- $fwrite(file_id, "0x%x\n", output_gray_data); /
- cnt <= cnt + 1'b1; /
- end /
- rgb_to_ycbcr u_rgb_to_ycbcr(
- .clock(clock),
- .rst(rst),
-
- .input_red_data(input_red_data),
- .input_green_data(input_green_data),
- .input_blue_data(input_green_data),
-
- .output_gray_data(output_gray_data)
- );
-
- endmodule
vivado仿真结果如下图:
仿真总图
仿真开始阶段图
仿真中间部分截取图
将在python转换得到的三个txt文件,放在工程文件的xsim文件夹里,仿真的结果都输出在了xsim文件夹里的gray.txt。
blue.txt
red.txt
green.txt
gray.txt
可以看到red/green/blue.txt数据数量均为262136个,输出到gray.txt文件中,数据量也为262136个十六进制数,所有数据都完成了运算,表明仿真成功。
2.3在OpenCV中将输出的txt文件转为bmp图像进行输出。
- import cv2
- import numpy as np
-
- '''
- main entry
- '''
-
-
- def main():
- picture = cv2.imread('./lzy.bmp')
- for i in range(512):
- for j in range(512):
- picture[i, j] = 255
-
- f = open("./gray.txt", 'r')
- for i in range(512 * 512):
- line = f.readline()
- picture[int(i / 512), int(i % 512)] = int(line, 16)
- f.close()
-
- cv2.imwrite('./new_lzy.bmp', picture)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
-
-
- if __name__ == '__main__':
- main()
至此,可以看到在vivado仿真中,与FPGA图像反转处理进行对比,在处理的数据量增加的情况下,处理时间并没有改变,在图像处理中,我们可以广泛应用FPGA的并行特性,实现硬件加速。在仿真中,以20ns一个周期的虚拟时钟进行仿真,处理速度就可以达到5.26ms,如果在FPGA实机中,以更快的时钟速度运行,并且不需要运行仿真文件,直接读取通过存储器传来的数据,速度将可以获得大更大的提高。
需要工程源码的友友可以在下方评论。
评论记录:
回复评论: