Vivado HLS implements MNIST handwritten digit recognition (2)

The previous section introduced how to use the built convolution and pooling modules to recognize the images of handwritten digits stored in the SD card. This section will introduce how to recognize handwritten digits on the image data collected by the camera.

1. HLS image processing part

The input of the convolution and pooling modules is a 28*28 single-channel grayscale image, while the ov5640 camera collects a 1024*768 three-channel color image. Here, the picture collected by the camera is first cropped. Taking into account the position of the actual handwritten digits in the collected image, a picture of 112*112 size located in the center of the image is intercepted. Then the image is grayscaled and binarized, so that the data The format is consistent with the training input; then the image size is scaled, and the grayscale image of 112*112 size is scaled to 28*28 size.

void doKernel(AXI_STREAM & inStream,AXI_STREAM & outStream,unsigned char result[],int num)
{
#pragma HLS INTERFACE m_axi depth=4294967295 port=result offset=slave
#pragma HLS INTERFACE s_axilite port=return bundle=CTRL_BUS
#pragma HLS INTERFACE axis register both port=outStream
#pragma HLS INTERFACE axis register both port=inStream
#pragma HLS INTERFACE s_axilite port=num

unsigned char tmp,cnt;
unsigned char pix;
unsigned char valOut_m=255;
unsigned char valOut_z=0;
RGB_image image1(4*MINST_WIDTH,4*MINST_WIDTH);
Resize_image image2(MINST_WIDTH,MINST_WIDTH);
Gray_image gray(MINST_WIDTH,MINST_WIDTH);

uint_side_channel dataOutChannel;
uint_side_channel currentChannel;


for(int i = 0; i < (IMG_HEIGHT); i + + )
{
for(int j = 0; j < (IMG_WIDTH); j + + )
{
#pragma HLSPIPELINE
currentChannel = inStream.read();
hls::Scalar<3, unsigned char> pixel_val;
if((i==(IMG_HEIGHT/2-2*MINST_WIDTH-1) || i==(IMG_HEIGHT/2 + 2*MINST_WIDTH)) & amp; & amp; (j>=(IMG_WIDTH/2-2*MINST_WIDTH -1) & amp; & amp; j<=(IMG_WIDTH/2 + 2*MINST_WIDTH)))
{
dataOutChannel.data = (valOut_m << 16) | (valOut_z << 8) | valOut_z;
}
else if((i>=(IMG_HEIGHT/2-2*MINST_WIDTH-1) & amp; & amp; i<=(IMG_HEIGHT/2 + 2*MINST_WIDTH)) & amp; & amp; (j==(IMG_WIDTH/ 2-2*MINST_WIDTH-1) || j==(IMG_WIDTH/2 + 2*MINST_WIDTH)))
{
dataOutChannel.data = (valOut_m << 16) | (valOut_z << 8) | valOut_z;
}
else
{
dataOutChannel.data = currentChannel.data;
}
if((i>=(IMG_HEIGHT/2-2*MINST_WIDTH) & amp; & amp; i<=(IMG_HEIGHT/2 + 2*MINST_WIDTH-1)) & amp; & amp; (j>=(IMG_WIDTH/2 -2*MINST_WIDTH) & amp; & amp; j<=(IMG_WIDTH/2 + 2*MINST_WIDTH-1)))
{
unsigned char R = currentChannel.data & 0xFF;
unsigned char G = (currentChannel.data >> 8) & amp; 0xFF;
unsigned char B = (currentChannel.data >> 16) & amp; 0xFF;
pix = (R*76 + G*150 + B*30) >> 8;
if(pix<16)
pix=0;
else if(pix<128)
pix=pix>>3;
else
pix=255;
dataOutChannel.data = (pix << 16) | (pix << 8) | pix;
pixel_val.val[0] = pix;
pixel_val.val[1] = pix;
pixel_val.val[2] = pix;
image1.write(pixel_val);
}
if(num<10){
tmp = number[num][i][j/8];
if(i<128 & amp; & amp; (j-959)>0){
if(tmp!=0){
for(cnt=0;cnt<j%8;cnt + + )
tmp = tmp/2;
if(tmp%2==1){
dataOutChannel.data = (valOut_m << 16) | (valOut_z << 8) | valOut_z;
}
}
}
}

dataOutChannel.dest = currentChannel.dest;
dataOutChannel.id = currentChannel.id;
dataOutChannel.keep = currentChannel.keep;
dataOutChannel.strb = currentChannel.strb;
dataOutChannel.user = currentChannel.user;
dataOutChannel.last = currentChannel.last;
outStream.write(dataOutChannel);
}
}
#pragma HLS dataflow
hls::Resize(image1,image2,1);
hls::CvtColor<HLS_BGR2GRAY>(image2,gray);
hls::Mat2Array<MINST_WIDTH>(gray,result);
}

In addition to image processing, the recognized numbers are displayed on the screen. At the same time, in order to extract the result of image processing, the result array is configured as m_axi type.

2. Vivado system construction

Here, the input of the image processing module is connected to the output of the camera module, and the output of the image processing module is connected to the input of the HDMI display.

3. Visit SDK design

The design of the SDK first starts the initialization camera, image processing module and convolution pooling module, then initializes the SD card, reads the weight parameters of the convolution pooling layer, and finally inputs the image acquisition results to the convolution pooling module to output the results. .

#include <stdio.h>
#include "platform.h"
#include <stdlib.h>
#include <string.h>
#include "xil_types.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xaxivdma.h"
#include "xaxivdma_i.h"
#include "vdma_api/vdma_api.h"
#include "emio_sccb_cfg/emio_sccb_cfg.h"
#include "ov5640/ov5640_init.h"
#include "xdokernel.h"
#include "xil_printf.h"
#include "xil_cache.h"
#include "Convolution.h"
#include "Pool.h"
#include "sd.h"

#define HLS_VDMA_DEV_ID XPAR_AXI_VDMA_0_DEVICE_ID
#define DISP_VDMA_DEV_ID XPAR_AXI_VDMA_1_DEVICE_ID
#define DOKERNEL_DEV_ID XPAR_DOKERNEL_0_DEVICE_ID

#define HLS_BASE_ADDR 0x08000000
#define DISP_BASE_ADDR 0x03000000
#define SCREEN_X 1024
#define SCREEN_Y 768

static XAxiVdma vdma;
static XDokernel dokernel;
static XDokernel_Config *dokernel_Cfg;

//Weight of Conv1
unsigned char oral_pic[28][28];
float image[28][28][1];
float W_conv1[3][3][1][12];
float b_conv1[12];
float h_conv1[28][28][12];
float h_pool1[14][14][12];

//Weight of Conv2
float W_conv2[3][3][12][24];
float b_conv2[24];
float h_conv2[14][14][24];
float h_pool2[7][7][24];

//Weight of FC1
float W_fc1[7*7*24][96];
float b_fc1[96];
float h_fc1[96];

//Weight of FC2
float W_fc2[96][10];
float b_fc2[10];
float h_fc2[10];

int main()
{
    init_platform();
    Xil_DCacheDisable();

    int i,j;

u32 status;

u16 cmos_h_pixel;
u16 cmos_v_pixel;
u16 total_h_pixel;
u16 total_v_pixel;

cmos_h_pixel = 1024;
cmos_v_pixel = 768;
total_h_pixel = 2570;
total_v_pixel = 980;

emio_init();

status = ov5640_init( cmos_h_pixel,
cmos_v_pixel,
total_h_pixel,
total_v_pixel);
if(status == 0)
xil_printf("OV5640 detected successful!\r\
");
else
xil_printf("OV5640 detected failed!\r\
");

dokernel_Cfg = XDokernel_LookupConfig(DOKERNEL_DEV_ID);
status = XDokernel_CfgInitialize( & amp;dokernel,dokernel_Cfg);
if(status != XST_SUCCESS){
printf("dokernel initialize failed! \
");
}

    XConv xconv;
    if(XConv_Initialize( & amp;xconv,XPAR_CONV_0_DEVICE_ID)!=XST_SUCCESS)
    xil_printf("XConv device not found\r\
");

    XPool xpool;
    if(XPool_Initialize( & amp;xpool,XPAR_POOL_0_DEVICE_ID)!=XST_SUCCESS)
    xil_printf("XPool device not found\r\
");
    //Initialize SD card
    SD_Init();
    print("Hello World\r\
");

    LoadWeight("W_conv1.bin",3*3*1*12,W_conv1[0][0][0]);
    LoadWeight("b_conv1.bin",12,b_conv1);

    LoadWeight("W_conv2.bin",3*3*12*24,W_conv2[0][0][0]);
    LoadWeight("b_conv2.bin",24,b_conv2);

    LoadWeight("W_fc1.bin",7*7*24*96,W_fc1[0]);
    LoadWeight("b_fc1.bin",96,b_fc1);

    LoadWeight("W_fc2.bin",96*10,W_fc2[0]);
    LoadWeight("b_fc2.bin",10,b_fc2);

run_vdma_frame_buffer( & amp;vdma, DISP_VDMA_DEV_ID, SCREEN_X, SCREEN_Y,
DISP_BASE_ADDR,0,0,BOTH);
run_vdma_frame_buffer( & amp;vdma, HLS_VDMA_DEV_ID, SCREEN_X, SCREEN_Y,
HLS_BASE_ADDR,0,0,BOTH);

    while(1)
    {
    XDokernel_Set_result( & amp;dokernel,(unsigned int)orional_pic);
    XDokernel_Start( & amp;dokernel);
    while(!XDokernel_IsDone( & amp;dokernel));
    for(i=0;i<28;i + + ){
    for(j=0;j<28;j + + ){
    image[i][j][0] = 1-orional_pic[i][j]/255.0;
    }
    }

//Conv1
RunConv( &xconv,1,28,28,12,//CHin,Hin,Win,CHout
3,3,1,1,1,1,//Kx,Ky,Sx,Sy,mode,relu_en
image[0][0],W_conv1[0][0][0],b_conv1,h_conv1[0][0]);//feature_in,W,bias,feature_out
RunPool( &xpool,12,28,28,//CHin,Hin,Win
2,2,2,//Kx,Ky,mode
h_conv1[0][0],h_pool1[0][0]);//feature_in,feature_out

//Conv2
RunConv( &xconv,12,14,14,24,//CHin,Hin,Win,CHout
3,3,1,1,1,1,//Kx,Ky,Sx,Sy,mode,relu_en
h_pool1[0][0],W_conv2[0][0][0],b_conv2,h_conv2[0][0]);//feature_in,W,bias,feature_out
RunPool( &xpool,24,14,14,//CHin,Hin,Win
2,2,2,//Kx,Ky,mode
h_conv2[0][0],h_pool2[0][0]);//feature_in,feature_out

//FC1
RunConv( &xconv,24,7,7,96,//CHin,Hin,Win,CHout
7,7,1,1,0,1,//Kx,Ky,Sx,Sy,mode,relu_en
h_pool2[0][0],W_fc1[0],b_fc1,h_fc1);//feature_in,W,bias,feature_out

//FC2
RunConv( &xconv,96,1,1,10,//CHin,Hin,Win,CHout
1,1,1,1,0,1,//Kx,Ky,Sx,Sy,mode,relu_en
h_fc1,W_fc2[0],b_fc2,h_fc2);//feature_in,W,bias,feature_out
//Equivalent to softmax effect
float max=-10000;int num=0;
for(int m=0;m<10;m + + )
{
if(h_fc2[m]>max)
{
max=h_fc2[m];
num=m;
}
}
xil_printf("predicted=%d \r\
",num);
    }

    cleanup_platform();
    return 0;
}

Demonstration effect: station b

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. OpenCV skill treeDeep learning in OpenCVImage classification 23663 people are learning the system