完成训练后,就是在开发板上实现自己的项目了。将脚本生成的项目导入到eclipse里边。
这个生成的项目中已经完成了CNN神经网络推理的实现。现在就是需要额外将摄像头采集到的数据喂给CNN网络即可。参考例程ImgCapture。通过DMA来读取摄像头。
// rps-demo // Created using ./ai8xize.py --verbose --log --test-dir pytorch --prefix rps-demo --checkpoint-file trained/ai85-rps82-chw.pth.tar --config-file networks/rps-chw.yaml --softmax --embedded-code --device MAX78000 --compact-data --mexpress --timer 0 --display-checkpoint --fifo #include <stdlib.h> #include <stdint.h> #include <string.h> #include <stdio.h> #include "mxc_device.h" #include "mxc_sys.h" #include "bbfc_regs.h" #include "fcr_regs.h" #include "icc.h" #include "dma.h" #include "led.h" #include "tmr.h" #include "pb.h" #include "cnn.h" #include "weights.h" #include "sampledata.h" #include "mxc_delay.h" #include "camera.h" #define TFT_ENABLE #define IMAGE_SIZE_X (64) #define IMAGE_SIZE_Y (64) #define CAMERA_FREQ (10 * 1000 * 1000) #define CNN_NUM_OUTPUTS 4 // number of classes const char classes[CNN_NUM_OUTPUTS][10] = {"Paper", "Rock", "Scissors", "Empty"}; volatile uint32_t cnn_time; // Stopwatch uint32_t input_0_camera[1024]; uint32_t input_1_camera[1024]; uint32_t input_2_camera[1024]; void fail(void) { printf("\n*** FAIL ***\n\n"); while (1) ; } void load_input(void) { int i; const uint32_t* in0 = input_0_camera; const uint32_t* in1 = input_1_camera; const uint32_t* in2 = input_2_camera; for (i = 0; i < 1024; i++) { while (((*((volatile uint32_t*)0x50000004) & 1)) != 0) ; // Wait for FIFO 0 *((volatile uint32_t*)0x50000008) = *in0++; // Write FIFO 0 while (((*((volatile uint32_t*)0x50000004) & 2)) != 0) ; // Wait for FIFO 1 *((volatile uint32_t*)0x5000000c) = *in1++; // Write FIFO 1 while (((*((volatile uint32_t*)0x50000004) & 4)) != 0) ; // Wait for FIFO 2 *((volatile uint32_t*)0x50000010) = *in2++; // Write FIFO 2 } } // Expected output of layer 6 for rps-demo given the sample input int check_output(void) { if ((*((volatile uint32_t*)0x50401000)) != 0x00079c32) return CNN_FAIL; // 0,0,0 if ((*((volatile uint32_t*)0x50401004)) != 0xfffae676) return CNN_FAIL; // 0,0,1 if ((*((volatile uint32_t*)0x50401008)) != 0xfff657b6) return CNN_FAIL; // 0,0,2 return CNN_OK; } // Classification layer: static int32_t ml_data[CNN_NUM_OUTPUTS]; static q15_t ml_softmax[CNN_NUM_OUTPUTS]; void softmax_layer(void) { cnn_unload((uint32_t*)ml_data); softmax_q17p14_q15((const q31_t*)ml_data, CNN_NUM_OUTPUTS, ml_softmax); } /* **************************************************************************** */ static uint8_t signed_to_unsigned(int8_t val) { uint8_t value; if (val < 0) { value = ~val + 1; return (128 - value); } return val + 128; } /* **************************************************************************** */ int8_t unsigned_to_signed(uint8_t val) { return val - 128; } /* **************************************************************************** */ void process_camera_img(uint32_t* data0, uint32_t* data1, uint32_t* data2) { uint8_t* frame_buffer; uint32_t imgLen; uint32_t w, h, x, y; uint8_t* ptr0; uint8_t* ptr1; uint8_t* ptr2; uint8_t* buffer; camera_get_image(&frame_buffer, &imgLen, &w, &h); ptr0 = (uint8_t*)data0; ptr1 = (uint8_t*)data1; ptr2 = (uint8_t*)data2; buffer = frame_buffer; for (y = 0; y < h; y++) { for (x = 0; x < w; x++, ptr0++, ptr1++, ptr2++) { *ptr0 = (*buffer); buffer++; *ptr1 = (*buffer); buffer++; *ptr2 = (*buffer); buffer++; buffer++; //MSB is zero } } } /* **************************************************************************** */ void capture_camera_img(void) { camera_start_capture_image(); while (1) { if (camera_is_image_rcv()) { return; } } } /* **************************************************************************** */ void convert_img_unsigned_to_signed(uint32_t* data0, uint32_t* data1, uint32_t* data2) { uint8_t* ptr0; uint8_t* ptr1; uint8_t* ptr2; ptr0 = (uint8_t*)data0; ptr1 = (uint8_t*)data1; ptr2 = (uint8_t*)data2; for (int i = 0; i < 4096; i++) { *ptr0 = unsigned_to_signed(*ptr0); ptr0++; *ptr1 = unsigned_to_signed(*ptr1); ptr1++; *ptr2 = unsigned_to_signed(*ptr2); ptr2++; } } /* **************************************************************************** */ void convert_img_signed_to_unsigned(uint32_t* data0, uint32_t* data1, uint32_t* data2) { uint8_t* ptr0; uint8_t* ptr1; uint8_t* ptr2; ptr0 = (uint8_t*)data0; ptr1 = (uint8_t*)data1; ptr2 = (uint8_t*)data2; for (int i = 0; i < 4096; i++) { *ptr0 = signed_to_unsigned(*ptr0); ptr0++; *ptr1 = signed_to_unsigned(*ptr1); ptr1++; *ptr2 = signed_to_unsigned(*ptr2); ptr2++; } } /* **************************************************************************** */ void cnn_wait(void) { while ((*((volatile uint32_t*)0x50100000) & (1 << 12)) != 1 << 12) ; CNN_COMPLETE; // Signal that processing is complete cnn_time = MXC_TMR_SW_Stop(MXC_TMR0); } /* **************************************************************************** */ int main(void) { int i, dma_channel; int digs, tens; int ret = 0; int result[CNN_NUM_OUTPUTS] = {0}; // Wait for PMIC 1.8V to become available, about 180ms after power up. MXC_Delay(200000); /* Enable camera power */ Camera_Power(POWER_ON); printf("\n\nRPS Feather Demo\n"); MXC_ICC_Enable(MXC_ICC0); // Enable cache // Switch to 100 MHz clock MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO); SystemCoreClockUpdate(); printf("Waiting...\n"); // DO NOT DELETE THIS LINE: MXC_Delay(SEC(2)); // Let debugger interrupt if needed // Enable peripheral, enable CNN interrupt, turn on CNN clock // CNN clock: 50 MHz div 1 cnn_enable(MXC_S_GCR_PCLKDIV_CNNCLKSEL_PCLK, MXC_S_GCR_PCLKDIV_CNNCLKDIV_DIV1); // Configure P2.5, turn on the CNN Boost mxc_gpio_cfg_t gpio_out; gpio_out.port = MXC_GPIO2; gpio_out.mask = MXC_GPIO_PIN_5; gpio_out.pad = MXC_GPIO_PAD_NONE; gpio_out.func = MXC_GPIO_FUNC_OUT; MXC_GPIO_Config(&gpio_out); MXC_GPIO_OutSet(gpio_out.port, gpio_out.mask); MXC_Delay(1000000); // Initialize DMA for camera interface MXC_DMA_Init(); dma_channel = MXC_DMA_AcquireChannel(); // Initialize camera. printf("Init Camera.\n"); camera_init(CAMERA_FREQ); ret = camera_setup(IMAGE_SIZE_X, IMAGE_SIZE_Y, PIXFORMAT_RGB888, FIFO_THREE_BYTE, USE_DMA, dma_channel); if (ret != STATUS_OK) { printf("Error returned from setting up camera. Error %d\n", ret); return -1; } int frame = 0; while (1) { // Capture a single camera frame. printf("\nCapture a camera frame %d\n", ++frame); capture_camera_img(); // Copy the image data to the CNN input arrays. // printf("Copy camera frame to CNN input buffers.\n"); process_camera_img(input_0_camera, input_1_camera, input_2_camera); convert_img_unsigned_to_signed(input_0_camera, input_1_camera, input_2_camera); cnn_init(); // Bring state machine into consistent state cnn_load_weights(); // Load kernels cnn_load_bias(); cnn_configure(); // Configure state machine cnn_start(); // Start CNN processing load_input(); // Load data input via FIFO MXC_TMR_SW_Start(MXC_TMR0); while (cnn_time == 0) __WFI(); // Wait for CNN softmax_layer(); printf("Time for CNN: %d us\n\n", cnn_time); printf("Classification results:\n"); for (i = 0; i < CNN_NUM_OUTPUTS; i++) { digs = (1000 * ml_softmax[i] + 0x4000) >> 15; tens = digs % 10; digs = digs / 10; result[i] = digs; printf("[%7d] -> Class %d %16s: %d.%d%%\r\n", ml_data[i], i, classes[i], digs, tens); } printf("\n"); MXC_Delay(SEC(2)); } return 0; }
将摄像头获得到的数据,喂给CNN网络后,会得出不同手势的概率值。
不过实际测试发现,剪刀、石头识别率还行,到了布总是识别错误。
最后附上视频:https://www.bilibili.com/video/BV1PatjzCEq1/