当前位置:   article > 正文

基于FPGA的Sobel算法实现_sobelfpga的实现

sobelfpga的实现

基于FPGA的Sobel算法实现

第一次写这种技术博客,发现整理清楚思路,把想法清楚的表达出来还是挺困难的。在努力表达清楚的过程中,发现觉得逻辑不太清晰的原因可能是自己的理解根本就没有深入。这篇博文是自己2019年的第一个Flag,自己要立好了!


在基于FPGA的图像处理算法中,对于算法实现的验证有两种方法:

  • 使用显示器
  • 使用matlab

仿真图象生成

Python图像处理方案

找一张图,使用Python进行数据处理

  1. RGB转灰度图像;
  2. 对图像进行裁剪,得到640*512分辨率的图像;
  3. 把图像数据写入txt文件中;
# -*- coding:UTF-8-*-
from cv2 import cv2
import numpy as np
import struct
from matplotlib import pyplot as plt

width               = 640
hidth               = 512
pix_bit             = 16#每个像素点有8位
IMG_ORIGINAL        = './../data/lena.jpg'
IMG_GRAY            = './../data/lena_gray.jpg'
IMG_GRAY_640x512    = './../data/lena_gray_640x512.jpg'
IMG_RESULT          = './../data/lena_result.jpg'
IMG_RESULT_REVERSE  = './../data/lena_result_reverse.jpg'
sim_file            = './../data/lena.txt'
post_file           = './../sim/post_108.txt'

def read_img(img_file):
    img1 = cv2.imread(img_file)
    return img1

def rgb2gray(img_file):
    img1 = cv2.cvtColor(img_file,cv2.COLOR_RGB2GRAY)
    return img1

def show_img(image):
    cv2.imshow('image',image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def plt_show_img(image):
    plt.imshow(image)
    plt.xticks([])
    plt.yticks([])
    plt.show()


# 图像缩放函数
def img_resize(image,post_x,post_y):
    fx=1.6
    fy=1.2
    # post_image = cv2.resize(image,(0,0),fx=fx,fy=fy,interpolation=cv2.INTER_CUBIC)
    post_image = cv2.resize(image,(post_x,post_y))
    return post_image

def raw2Txt(image):
    np.savetxt(sim_file, image, fmt='%d', delimiter='\n')


def loadTxt(filename,nx,ny):
    a = np.loadtxt(filename,dtype=np.float64,usecols=(0), unpack=True).reshape((nx,ny))
    post_image_8bit = np.rint(a).astype(dtype='uint8')
    cv2.imwrite(IMG_RESULT,post_image_8bit)
    cv2.imwrite(IMG_RESULT_REVERSE,255-post_image_8bit)
    return post_image_8bit

def main():
    img = read_img(IMG_ORIGINAL)#原始图像读入
    img2 = rgb2gray(img)#RGB转灰度图像
    cv2.imwrite(IMG_GRAY,img2)#保存灰度图像

    img3 = img_resize(img2,640,512)#分辨率剪裁
    cv2.imwrite(IMG_GRAY_640x512,img3)
    show_img(img3)

    raw2Txt(img3)#生成测试数据

    # img4 = loadTxt(post_file,hidth,width)#加载Modelsim中产生的进行Sobel处理的图片
    # show_img(img4)

    # show_img(255-img4)#极性做反向

if __name__ == "__main__":
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

Matlab图像处理平台搭建

这个小标题起的有点大,其实跟图像算法没有什么关系,不过是利用MATLAB生成图像数据、使用verilog读入数据提供源数据、再使用MATLAB读入modelsim中产生的输出数据,最后显示。

基本思路是:

把一副图片转换为320x256分辨率的灰度图片,然后利用fprintf函数把图像矩阵写入txt文件。

这个m文件涉及到的函数都很简单,写的时候一遍看help,一遍运行着看结果对不对。MATLAB源码如下:

% /*-----------------------------------------------------------------------
% CONFIDENTIAL IN CONFIDENCE
% This confidential and proprietary software may be only used as authorized
% by a licensing agreement from zjl ().
% In the event of publication, the following notice is applicable:
% Copyright (C) 2013-20xx zjl Corporation
% The entire notice above must be reproduced on all authorized copies.
% Author				:		zjl
% Technology blogs 	:       
% Email Address 		: 		i540113104@gmail.com
% Filename			:		.m
% Data				:		2018-12-30
% Description			:		1.可以输入任意尺寸的图片,输出图片分辨率为320x256
%                               2.输出rgb、灰度图像
%                               3.生成txt文件,在modelsim仿真时使用
%                               4.生成mif文件,在例化IP核时使用
% Modification History	:
% Data			By			Version			Change Description
% =========================================================================
% 30/12/18		zjl			  1.0				Original
% -----------------------------------------------------------------------*/

clc
clear all
close all

img_ori = imread('lena.jpg');%加载图像
img_320x256 = imresize(img_ori,[256,320]);% 把图片转换为320x256分辨率
img_320x256_gray = rgb2gray(img_320x256);%图像转换为灰度图像

imwrite(img_320x256_gray,'lena_gray_320x256.jpg');

% ---------------------------------------------------------------------------
figure(1)
subplot(1,3,1),imshow(img_ori);
subplot(1,3,2),imshow(img_320x256);
subplot(1,3,3),imshow(img_320x256_gray);
% ---------------------------------------------------------------------------
%320*256大小的灰度图像生成TXT文档
fid = fopen('./lena.txt','wt');%打开空文件
for i = 1 : size(img_320x256_gray, 1)%行循环
    for j = 1 : size(img_320x256_gray, 2)%列循环
        fprintf(fid, '%d ', img_320x256_gray(i, j));%每个数据之间用空格分开%
    end
    fprintf(fid, '\n');%文件末尾加一个换行
end
fid = fclose(fid);%关闭文件
I_data = load('./lena.txt');%加载txt文件到matlab工作区-可不要

% ---------------------------------------------------------------------------
%生成mif文件
[m,n] = size( img_320x256_gray );% m行 n列
N = m*n;                               %%数据的长度,即存储器深度。
word_len = 8;                          %%每个单元的占据的位数,需自己设定
data = reshape(img_320x256_gray', 1, N);% 把矩阵转换为1行N列
 
fid=fopen('gray_image.mif', 'w');       %打开文件
fprintf(fid, 'DEPTH=%d;\n', N);         %存储器深度
fprintf(fid, 'WIDTH=%d;\n', word_len);  %存储器位宽
fprintf(fid, 'ADDRESS_RADIX = UNS;\n'); %% 指定address为十进制
fprintf(fid, 'DATA_RADIX = HEX;\n');    %% 指定data为十六进制
fprintf(fid, 'CONTENT\t');
fprintf(fid, 'BEGIN\n');
for i = 0 : N-1
    fprintf(fid, '\t%d\t:\t%x;\n',i, data(i+1));
end
fprintf(fid, 'END;\n');                 %%输出结尾
fclose(fid);                            %%关闭文件
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

Modelsim仿真

  1. 使用$readmemh把txt文件中的图像数据导入数组中,并在tb文件中产生行场信号;
//***********************************************
//Project Name               :Sobel
//File Name                  :tb_x2.v
//Author                     :ZJL
//Date of Creation           :20190920
//Functional Description     :图像数据仿真
//              
//Revision History           :
//Change Log                 :
//***********************************************
`timescale 1ns/1ns
module tb_x2;
//------------------------------------------
// `define 1280_1024_30


// `ifdef 1280_1024_30
// 	parameter FRAME_RATE 		= 30;								//帧频
// 	parameter RES_WIDTH 		= 1280;								//分辨率:宽度
// 	parameter RES_HEIGHT 		= 1024;								//分辨率:高度
// `endif

// `else//def 320_256_50
// 	parameter FRAME_RATE 		= 50;								//帧频
// 	parameter RES_WIDTH 		= 320;								//分辨率:宽度
// 	parameter RES_HEIGHT 		= 256;								//分辨率:高度
// `endif


parameter FRAME_RATE 		= 50	;							//帧频
parameter RES_WIDTH 		= 640	;							//分辨率:宽度
// parameter RES_HEIGHT 		= 512	;							//分辨率:高度
parameter RES_HEIGHT 		= 514	;							//分辨率:高度
parameter PERIOD_50MHZ	 	= 20	;							//50MHz
parameter LINE_BLANK 		= 100	;							//消隐期周期数
parameter EXTRA_LINES 		= 10	;							//多输出的行数
parameter FRAME_PERIOD 		= 1_000_000_000/FRAME_RATE;			//帧周期-‭16,666,666.66666667‬ns
parameter TOTAL_PIXEL 		= (RES_WIDTH + LINE_BLANK);			//多输出的行数-1330
parameter TOTAL_LINES 		= (RES_HEIGHT + EXTRA_LINES);		//多输出的行数-1040
parameter TEMP1 			= FRAME_PERIOD/20;					//多输出的行数-1040
parameter TEMP2 			= TOTAL_PIXEL * TOTAL_LINES;		//多输出的行数-1040
parameter TEMP3 			= TEMP1 - TEMP2;					//多输出的行数-1040
parameter CNT_WAIT_TIME 	= (FRAME_PERIOD/20 - (TOTAL_PIXEL * TOTAL_LINES))/2;//多输出的行数
//信号列表
reg	 				clk;		//clock
reg 				rst_n;		//reset @high voltage

reg					in_pulse;	//input signal
reg					i_start;	//to streamscale
wire 	[15:0]		o_data;		//data after scale
wire 				o_dvalid;	//data valid after scale
wire 	[15:0]		data_tmp;
wire 	[15:0]		data_tmp2;
integer 			i;			//counter for random task
reg 	[15:0]		rand_data1;	//random data out
reg 	[15:0]		rand_data2;	//random data out
integer 			N = 512;		//random seed
reg 	[15:0] 		reg_mem[0:RES_WIDTH*RES_HEIGHT-1];//={0};	//! memory
integer 			addr;				//memory address

reg 	[1-1:0] 		field_rst;
wire 	[1-1:0] 		wait_done;
reg 	[1-1:0] 		flag_image;

wire        [1-1:0]         	wait_time_add		;
reg        	[1-1:0]         	en_cnt_wait_time	;
reg        	[32-1:0]        	cnt_wait_time		;
reg 		[12-1:0] 			hcnt				;
reg 		[12-1:0] 			vcnt				;
wire 		[1-1:0] 			h_valid				;
wire 		[1-1:0] 			v_valid				;
//------------------------------------------

//系统时钟
initial
begin
	clk = 0;
	forever	#(PERIOD_50MHZ/2)
	clk = ~clk;
end

//------------------任务------------------------
//*任务:系统初始化
task task_sysinit;
begin
	in_pulse = 0;
	i_start = 0;
	field_rst = 0;
end
endtask

//*任务:Generate global reset
task task_reset;
begin
	rst_n = 0;
	repeat(2) @(negedge clk);
	rst_n = 1;
end
endtask

//产生帧复位信号
task task_field_rst;
begin
	@(posedge clk);
		field_rst = 1;
	@(posedge clk);
		field_rst = 0;
	#(FRAME_PERIOD);
	@(posedge clk);
		field_rst = 1;
	@(posedge clk);
		field_rst = 0;
end
endtask




//task of generate random bit signal
//*任务:产生随机数
task task_rand_bit;
begin
	begin
		for( i = 0; i < 255; i=i+1 )begin
			@( posedge clk );
				rand_data1 = { $random } % N;//随机数取值范围[0,N-1]
				rand_data2 = { $random } % N;//随机数取值范围[0,N-1]
		end
	end
end
endtask

//*任务:读取文件到内存
task load_data2mem;
begin
	$readmemh("./../data/lena.txt",reg_mem);
end
endtask
//-----------------存储器地址------------------------
//生成存储器地址
always @ (posedge clk)begin
	if(!rst_n) begin
		addr <= 0;
	end
	else if( h_valid )begin
		addr <= addr +1;
	end
end
assign data_tmp = h_valid?(reg_mem[addr]):0;//从内存中读出数据
assign data_tmp2 = { data_tmp[7:0],data_tmp[15:8] };//从内存中读出数据
//------------------行计数-----------------------
assign     wait_time_add = field_rst;
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		cnt_wait_time        <=        'd0;
	end
	else if( en_cnt_wait_time )begin//只有在有效才计数
		cnt_wait_time        <=        cnt_wait_time + 'd1;
	end
	else begin
		cnt_wait_time        <=        'd0;
	end
end
		
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		en_cnt_wait_time        <=        'd0;
	end
	else if( cnt_wait_time == CNT_WAIT_TIME - 1)begin//结束计数条件
		en_cnt_wait_time        <=        'd0;
	end
	else if( wait_time_add )begin        //开始计数条件
		en_cnt_wait_time        <=        'd1;
	end
	else begin
		en_cnt_wait_time        <=        en_cnt_wait_time;
	end
end
assign wait_done = ( cnt_wait_time == CNT_WAIT_TIME - 1);

always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		flag_image        <=        'd0;
	end
	else if( vcnt == RES_HEIGHT-1 && hcnt == RES_WIDTH-1 )begin//结束计数条件
		flag_image        <=        'd0;
	end
	else if( wait_done )begin        //开始计数条件
		flag_image        <=        'd1;
	end
	else begin
		flag_image        <=        flag_image;
	end
end
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		hcnt        <=        'd0;
	end
	else if( flag_image )begin//结束计数条件
		if( hcnt ==  TOTAL_PIXEL-1)
			hcnt        <=        'd0;
		else
			hcnt        <=        hcnt + 'd1;
	end
	else begin
		hcnt        <=        'd0;
	end
end
assign h_valid = ( flag_image && hcnt<RES_WIDTH );
assign v_valid = ( flag_image && vcnt<RES_HEIGHT );
always @ ( posedge clk ) begin
	if( ~rst_n ) begin
		vcnt        <=        'd0;
	end
	else if( flag_image )begin//结束计数条件
		if( hcnt ==  TOTAL_PIXEL-1)
			vcnt        <=        vcnt + 'd1;
		else
			vcnt        <=        vcnt;
	end
	else begin
		vcnt        <=        'd0;
	end
end



//----------------------系统初始化------------------------
initial
begin
	task_sysinit;
	task_reset;
	load_data2mem;
	#5000 i_start = 1;
	#(PERIOD_50MHZ*2)
	i_start = 0;
	// generate_frame;
	#100
	@ ( posedge clk )
		in_pulse = 1;
	@ ( posedge clk )
		in_pulse = 0;
	task_field_rst;
end

//----------------------模块例化------------------------
wire[15:0]		data00;
wire[15:0]		data01;
wire[15:0]		data02;
wire[15:0]		data10;
wire[15:0]		data11;
wire[15:0]		data12;
wire[15:0]		data20;
wire[15:0]		data21;
wire[15:0]		data22;
wire		  	data_valid;
window_3x3 #(
	.PIX_PER_LINE( 640	),
	.PIX_DOUBLE_LINE( 1280	)
	)inst_window_3x3(
		.clock			( clk			),
		.frame_reset	( field_rst		),
		.datain			( data_tmp		),
		.datain_en		( h_valid		),
		.data00			( data00		),
		.data01			( data01		),
		.data02			( data02		),
		.data10			( data10		),
		.data11			( data11		),
		.data12			( data12		),
		.data20			( data20		),
		.data21			( data21		),
		.data22			( data22		),
		.data_valid		( data_valid	)
						);
   
wire        [1-1:0]          Dvld			;           
wire        [16-1:0]         Data       ;
sobel inst_sobel(
    .i_Clk            ( clk ),
    .i_Rst_n          ( field_rst ),      
    .i_Frame_rst      ( field_rst ),        
    .i_Data_valid     ( data_valid ),        
    .i_Line0_0        ( data00 ),    //previous line
    .i_Line0_1        ( data01 ),        
    .i_Line0_2        ( data02 ),        
    .i_Line1_0        ( data10 ),	//current line
    .i_Line1_1        ( data11 ),        
    .i_Line1_2        ( data12 ),        
    .i_Line2_0        ( data20 ),    //next line    
    .i_Line2_1        ( data21 ),        
    .i_Line2_2        ( data22 ),     
    .o_Dvld			( Dvld ),                  
    .o_Data			( Data )                  
);

//----------------------------------------------
wire [9:0] start_h;
wire [9:0] start_v;
wire [9:0] end_h;
wire [9:0] end_v;

//----------------------系统函数------------------------
//将仿真数据o_data写入外部文件中
integer file_df;
initial begin
	//文件放置在"工程目录\simulation\modelsim"路径下
	file_df = $fopen("post_108.txt");
	if(!file_df)begin
		$display("could not open file!");
		$finish;
	end
end
always @(posedge clk) begin
	if( Dvld )//一帧图像数据
		$fdisplay(file_df,"%d",Data);
end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  1. 行缓冲器-window_3x3
  2. Sobel运算模块
  3. 运算后数据写入文件

仿真波形如下图所示:

在这里插入图片描述

在这里插入图片描述

注意:因为是在testbench中产生数据的,所以可以使用延时语句让行有效信号严格对齐数据,这样更容易实现。

数据写入文件,在matlab中进行显示

verilog操作文本的函数比较多,$display就够用了。

//----------------------系统函数------------------------
//将仿真数据o_data写入外部TXT文件中(x1.txt)
integer file_df;
initial begin
	//文件放置在"工程目录\simulation\modelsim"路径下
	file_df = $fopen("x1.txt");
	if(!file_df)begin
		$display("could not open file!");
		$finish;
	end
end
always @(posedge clk) begin
	if( data_valid )//一帧图像数据
		$fdisplay(file_df,"%d",out);
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最后一步是MATLAB读入仿真数据,显示图片

% /*-----------------------------------------------------------------------
% CONFIDENTIAL IN CONFIDENCE
% This confidential and proprietary software may be only used as authorized
% by a licensing agreement from zjl ().
% In the event of publication, the following notice is applicable:
% Copyright (C) 2013-20xx zjl Corporation
% The entire notice above must be reproduced on all authorized copies.
% Author				:		zjl
% Technology blogs 	:       
% Email Address 		: 		i540113104@gmail.com
% Filename			:		.m
% Data				:		2018-12-30
% Description			:		1.读入tb文件中生成的txt文件;
%                               2.txt文件中的数据可以是十进制、也可以是十六进制,在tb中设置;
%                               3.使用imshow函数显示仿真数据的时候有个坑,数据导入matlab后,查看数据范围是0~255,但是数据类型与imshow函数使用的不同,直接使用imshow(img)的时候,imshow会多余的处理数据,处理结果就是:大于0的像素认为该点灰度为1,否则为零,直观的观察就是窗口像是图像为纯白色;
% Modification History	:
% Data			By			Version			Change Description
% =========================================================================
% 30/12/18		zjl			  1.0				Original
% -----------------------------------------------------------------------*/


% fid = fopen('./x1.txt','rt');
fid = fopen('./lena.txt','rt');
img_tmp=fscanf(fid,'%x',inf);%以十进制数据读入数据到matlab工作区
% img_tmp2 = reshape(img_tmp, 254,320);% 1行N列
% img_tmp3 = imresize(img_tmp2,[256,320]);
% img_tmp4 = round(img_tmp3);
% img_320x256=uint8(img_tmp3);
p=1;
for i = 1 : 254			%行数,取决于生成的txt文件像素数目
	for j = 1 : 320		%列数,设置为固定吧
        img_tmp2(i,j) = img_tmp(p);
		p=p+1;
    end
end
fclose(fid);
figure(1)
imshow(img_tmp2,[]);	%! 注意:加上[]配置函数自动处理数据类型
% imwrite(uint8(img_320x256),'file_out.tif')
% imshow(img_320x256);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

显示图片有个比较坑的地方是,最后使用imshow函数显示图片的时候,要使用imshow(mat,[])来把数据调整到合适的灰度值范围内,否则直接现实的话会出现整帧图像全是白色的诡异图像(诡异的地方是matlab工作区的变量显示的取值范围就是0~255,我猜测是imshow函数在处理数据的时候把所有的数据判断为255,但是原因是什么还不清楚)。

下面两个图是verilog输入输出数据的图像显示。

在这里插入图片描述

在这里插入图片描述

行缓冲器的verilog实现

盗用一下altera-ip-shift-register-usermanual中的一个图。

在这里插入图片描述
使用三个FIFO-Core实现行缓冲器。
缓冲器的关键点在于读出条件信号的控制。

module window_3x3#(
	parameter PIX_PER_LINE = 320,
	parameter PIX_DOUBLE_LINE = 640
)(
						input 			  clock,
						input 			  frame_reset,
						input[15:0] 	  datain,
						input 			  datain_en,
						output reg[15:0] data00,
						output reg[15:0] data01,
						output reg[15:0] data02,
						
						output reg[15:0] data10,
						output reg[15:0] data11,
						output reg[15:0] data12,
						
						output reg[15:0] data20,
						output reg[15:0] data21,
						output reg[15:0] data22,
						
						output reg		  data_valid
						);
						
	
	reg 		  	line_buf_rden;
	reg 		  	line_buf_rden_d1;
	wire[15:0] 		line_buf_dout;
	wire[15:0] 		line_dout00;
	wire[15:0] 		line_dout01;
	wire[9:0]  		line_buf_data_count;
	wire[9:0]  		line_data_count00;
	wire[9:0]  		line_data_count01;
	wire		  	line_rden0;
	wire		  	line_rden1;
	reg[9:0]   		line_buf_rd_cnt;
	reg[10:0]  		line_rden_cnt;
	reg		  		line_data_valid;
	reg		  		line_data_valid_d1,line_data_valid_d2;
	
	reg [9:0] hcnt;
	reg [9:0] vcnt;
	// assign line_rden0 = (line_data_count00 >= PIX_PER_LINE - 1) ? line_buf_rden : 1'b0;
	// assign line_rden1 = (line_data_count01 >= PIX_PER_LINE - 1) ? line_buf_rden : 1'b0;
	assign line_rden0 = (line_data_count00 >= PIX_PER_LINE ) ? line_buf_rden : 1'b0;
	assign line_rden1 = (line_data_count01 >= PIX_PER_LINE ) ? line_buf_rden : 1'b0;
	
	always @(posedge clock)
	begin
		if(frame_reset)
			line_buf_rden <= 1'b0;
		else if(line_buf_data_count >= PIX_PER_LINE)
			line_buf_rden <= 1'b1;
		else if(line_buf_rd_cnt == PIX_PER_LINE - 1)
			line_buf_rden <= 1'b0;
	end
	
	always @(posedge clock)
	begin
		if(frame_reset)
			line_buf_rd_cnt <= 10'd0;
		else if(line_buf_rden)
			line_buf_rd_cnt <= line_buf_rd_cnt + 1'b1;
		else
			line_buf_rd_cnt <= 10'd0;
	end
	
	always @(posedge clock)
	begin
		line_buf_rden_d1 <= line_buf_rden;
	end
	
	always @(posedge clock)
	begin
		if(frame_reset)
			line_rden_cnt <= 11'd0;
		else if(line_buf_rden) begin
			if(line_rden_cnt < PIX_DOUBLE_LINE)
				line_rden_cnt <= line_rden_cnt + 1'b1;
			else
				line_rden_cnt <= line_rden_cnt;
		end
		else
			line_rden_cnt <= line_rden_cnt;
	end
	
	always @(posedge clock)
	begin
		if(frame_reset)
			line_data_valid <= 1'b0;
		else if(line_rden_cnt == PIX_DOUBLE_LINE)
			line_data_valid <= line_buf_rden;
		else
			line_data_valid <= 1'b0;
	end
	
	always @(posedge clock)
	begin
		if(frame_reset) begin
			data00 <= 16'h0;
			data01 <= 16'h0;
			data02 <= 16'h0;
			
			data10 <= 16'h0;
			data11 <= 16'h0;
			data12 <= 16'h0;
			
			data20 <= 16'h0;
			data21 <= 16'h0;
			data22 <= 16'h0;
			
			line_data_valid_d1 <= 1'b0;
			line_data_valid_d2 <= 1'b0;
		end
		else begin
			// data22 <= (vcnt<510) ? line_buf_dout : line_dout01;
			data22 <= line_buf_dout;
			data21 <= data22;
			data20 <= data21;
			
			data12 <= line_dout00;
			// data12 <= (vcnt<511) ? line_dout00 : line_dout01;
			data11 <= data12;
			data10 <= data11;
			
			data02 <= line_dout01;
			// data02 <= (vcnt<512) ? line_dout01 : 0;
			data01 <= data02;
			data00 <= data01;
			
			line_data_valid_d1 <= line_data_valid;
			line_data_valid_d2 <= line_data_valid_d1;
			// data_valid			 <= line_data_valid_d2;
			data_valid			 <= line_data_valid_d1;
			// data_valid			 <= line_data_valid;
		end
	end	
	fifo #(.DATA_W(16),.DEPT_W(2048) )inst_board_sync1(
                   .aclr    ( frame_reset			),
                   .wrclk   ( clock					),
                   .wrreq   ( datain_en				),
                   .data    ( datain				),
                   .rdclk   ( clock					),//24mhz from test-board pll
                   .rdreq   ( line_buf_rden			),
                   .q       ( line_buf_dout			),
                   .wrusedw ( line_buf_data_count	)
);  
	// enfifo1024x16 line_buf(
	// 	.aclr		(frame_reset),
	// 	.clock		(clock),
	// 	.data		(datain),
	// 	.rdreq		(line_buf_rden),
	// 	.wrreq		(datain_en),
	// 	.q			(line_buf_dout),
	// 	.usedw		(line_buf_data_count)
	// 	);
		
	fifo #(.DATA_W(16),.DEPT_W(2048) )inst_board_sync2(
                   .aclr    ( frame_reset			),
                   .wrclk   ( clock					),
                //    .wrreq   ( line_buf_rden_d1				),
                   .wrreq   ( line_buf_rden				),
                   .data    ( line_buf_dout				),
                   .rdclk   ( clock					),//24mhz from test-board pll
                   .rdreq   ( line_rden0			),
                   .q       ( line_dout00			),
                   .wrusedw ( line_data_count00	)
);  
	// enfifo1024x16 line_00(
	// 	.aclr		(frame_reset),
	// 	.clock		(clock),
	// 	.data		(line_buf_dout),
	// 	.rdreq		(line_rden0),
	// 	.wrreq		(line_buf_rden_d1),
	// 	.q			(line_dout00),
	// 	.usedw		(line_data_count00)
	// 	);
	
	fifo #(.DATA_W(16),.DEPT_W(2048) )inst_board_sync3(
                   .aclr    ( frame_reset		),
                   .wrclk   ( clock				),
                //    .wrreq   ( line_buf_rden_d1	),
                   .wrreq   ( line_rden0	),
                   .data    ( line_dout00		),
                   .rdclk   ( clock				),//24mhz from test-board pll
                   .rdreq   ( line_rden1		),
                   .q       ( line_dout01		),
                   .wrusedw ( line_data_count01	)
);  
	// enfifo1024x16 line_01(
	// 	.aclr		(frame_reset),
	// 	.clock		(clock),
	// 	.data		(line_dout00),
	// 	.rdreq		(line_rden1),
	// 	.wrreq		(line_buf_rden_d1),
	// 	.q			(line_dout01),
	// 	.usedw		(line_data_count01)
	// 	);


reg 	  data_valid_r1;
always @ ( posedge clock ) begin
	if( frame_reset ) begin
		data_valid_r1 <= 1'd0;
	end
	else begin
		data_valid_r1 <= data_valid;
	end
end
always @ ( posedge clock ) begin
	if( frame_reset ) begin
		hcnt        <=        'd0;
	end
	else if( data_valid)begin
		hcnt        <=        hcnt + 'd1;
	end
	else begin
		hcnt        <=        'd0;
	end
end
always @ ( posedge clock ) begin
	if( frame_reset ) begin
		vcnt        <=        'd0;
	end
	else if( data_valid_r1 && (~data_valid) )begin
		vcnt        <=        vcnt + 'd1;
	end
	else begin
		vcnt        <=        vcnt;
	end
end

endmodule 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232

未完待续……

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/547811
推荐阅读
相关标签
  

闽ICP备14008679号