基于FPGA的图像灰度处理

        对于图像的灰度处理,原理与基于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实机中,以更快的时钟速度运行,并且不需要运行仿真文件,直接读取通过存储器传来的数据,速度将可以获得大更大的提高。

        需要工程源码的友友可以在下方评论。

        

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值