最近想完成FPGA图像处理,由于没有开发板,就像通过仿真完成,之前像的是通过python 将图像转化为txt文本,最后利用verilog 读取txt文件导入,对像素点进行处理,然后将处理后像素数据写入txt,最后通过python转化为bmp位图,后来发现verilog可以直接读取bmp文件,并且将数据写入bmp文件。方便了很多。
位图说明
BMP文件存储格式
bmp文件的存储格式是Windows系统中广泛使用的图像文件格式,对图像不做任何程度的压缩处理,主要分为位图头文件,位图信息头,调色板信息,像素数据四大部分,由于通常是处理RBG图像,因此仅讨论RGB的情况
位图头文件 :文件的格式、大小等信息,前14Byte;主要关心的是图像尺寸,像素数据开始位置。
位图信息头: 提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息,前40Byte;主要关心的是图像宽度,图像高度。
调色板信息: 字,不关心
像素数据 : 像素数据,8bit一个像素数据,即1Byte。
位图
我使用的是上面这个128*128
24位位图: 又名RGB真彩色图,又名RGB真彩色图,含2^24=16 777 216=16M色,没有彩色表。每个像素点由3个字节(十六进制码6位)表示,每个字节负责控制一种颜色,分别为蓝(Blue)、绿(Green)、红(Red)。
一幅256×256的24位位图大小计算方法:
位图文件头(14字节)+位图信息头(40字节)+实际像素点占内存(256×256×3字节)=196 662字节(Byte)
注意:
Windows有“补零”的习惯!即要求位图的每一行像素所占字节数必须被4整除。若不能倍4整除,则在该位图每一行的十六进制码末尾“补”1至3个字节的“00”。
例如:一幅宽253×高256的24位位图,微软在生成该图为实际文件时,计算每一行像素所占字节=宽253×3字节=759字节,检验其被4除余1,则在每行的十六进制码末尾加1个字节,补“00”,变为760字节。因此我们计算该图大小时应先判断是否“补零”,再得出算法:
该图大小=位图文件头(14字节)+位图信息头(40字节)+实际像素点占内存(高256×每行760字节)=194614字节(Byte)。
“补零”只针对位图的宽进行检验,一幅宽256×高253的24位位图,
其大小=位图文件头(14字节)+位图信息头(40字节)+实际像素点占内存(高253×每行768字节)=194358字节(Byte)< 196 662字节(Byte)。
只是把此图像的宽和高颠倒,图像所占内存竟然变小了。
Verilog代码实现
/*******************************************************************************
* *
* (c) Copyright 1995-2017 TAIHO ELE Co,Ltd. *
* All rights reserved. *
* *
********************************************************************************
*
* FileName : top_tb.v
* Abstract : This module is an example for coding.
* Author : Mouhongbing
* Version : 1.1
* Release : 2022.9.29
* Revision :
* Version Date Author Modification description
* 1.0 Mouhongbing 2022.9.29
*
******************************************************************************/
`timescale 1ns / 1ns
module top_tb;
//图像属性:图像宽度 图像高度 图像尺寸 图像像素点起始位
integer bmp_width;
integer bmp_high;
integer bmp_size;
integer start_index;
//bmp file id
integer bmp_file_id;
integer bmp_dout_id;
integer dout_txt_id;
//文件句柄
integer h;
//文件bmp文件数据
reg [7:0] rd_data [0:49300];//根据自己图片大小
//写操作
reg [23:0] wr_data;
integer i = 0;
integer index;
initial
begin
clk=1'b1;
//打开原始图像
bmp_file_id = $fopen("D:\\python\\pic\\lena.bmp","rb");
//打开输出图像
bmp_dout_id = $fopen("D:\\python\\pic\\output_file.bmp","wb");
//打开输出数据
dout_txt_id = $fopen("D:\\python\\pic\\output_file.txt","w+");
//读取bmp文件
h = $fread(rd_data,bmp_file_id);
// 图像宽度
bmp_width = {rd_data[21], rd_data[20], rd_data[19], rd_data[18]};
// 图像宽度
bmp_high = {rd_data[25], rd_data[24], rd_data[23], rd_data[22]};
// 像素起始位置
start_index = {rd_data[13], rd_data[12], rd_data[11], rd_data[10]};
// 图像尺寸
bmp_size = {rd_data[5], rd_data[4], rd_data[3], rd_data[2]};
$fclose(bmp_file_id);
//输出BMP
for(i = 0; i < bmp_size; i = i + 1)begin
$fwrite(bmp_dout_id, "%c", rd_data[i]);//注意参数%c
end
$fclose(bmp_dout_id);
//输出txt,只存像素点
for(index = start_index; index < bmp_size-2; index = index + 3)begin
wr_data = {rd_data[index + 2], rd_data[index + 1], rd_data[index]};
$fwrite(dout_txt_id, "%d,", wr_data[7:0]);
$fwrite(dout_txt_id, "%d,", wr_data[15:8]);
$fwrite(dout_txt_id, "%d\n", wr_data[23:16]);
end
$fclose(dout_txt_id);
end
endmodule
python处理代码(附)
图像转txt
import cv2 # h, w, c
import numpy
import matplotlib.pyplot as plt
img = cv2.imread("./pic/th.bmp" , 1)
print("图像的形状,返回一个图像的(行数,列数,通道数):", img.shape)
print("图像的像素数目:", img.size)
print("图像的数据类型:", img.dtype)
#img = cv2.resize(img,(280,280)) 可以改变图片的大小
fname = open("./pic/th.txt",'w')
# fname.write("图像的形状,返回一个图像的(行数,列数,通道数):"+str(img.shape)+'\n')
# fname.write("图像的像素数目:"+str(img.size)+'\n')
# fname.write("图像的数据类型:"+str(img.dtype)+'\n')
Ylenth = img.shape[1] # 图片列数
Xlenth = img.shape[0] # 图片行数
for i in range(Xlenth):
for j in range(Ylenth):
fname.write(str(img[i][j][0])+','+str(img[i][j][1])+','+str(img[i][j][2])+'\n')
# fname.write('\n')
fname.close()
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
txt转bmp
# -*- coding:utf8 -
from PIL import Image
x = 128 #x坐标 通过对txt里的行数进行整数分解
y = 128 #y坐标 x*y=行数 13500行,150和900也可以
im = Image.new("RGB", (x,y))
file = open('./pic/output_file.txt')
for i in range(0,x):
for j in range(0,y):
#line = file.readline().replace('[','').replace(']','') #获取一行rgb值,并且把()都替换为空
line=file.readline()
rgb = line.split(",") #逗号分割
im.putpixel((i, j), (int(rgb[2]), int(rgb[1]), int(rgb[0]))) #(i,j)为坐标,后面的是像素点
file.close()
im.save("./pic/output_file.bmp")