add KPU and mobilenet demo, fix LCD bug

This commit is contained in:
Neucrack
2019-04-01 18:41:25 +08:00
parent eb16336cae
commit c19cb56c1a
17 changed files with 1535 additions and 10 deletions

View File

@@ -36,7 +36,7 @@ static const int resolution[][2] = {
{1600, 1200}, /* UXGA */
};
Camera::Camera(framesize_t frameSize = FRAMESIZE_QVGA, pixformat_t pixFormat = PIXFORMAT_RGB565)
Camera::Camera(framesize_t frameSize, pixformat_t pixFormat)
{
_frameSize = frameSize;
_pixFormat = pixFormat;
@@ -44,6 +44,14 @@ Camera::Camera(framesize_t frameSize = FRAMESIZE_QVGA, pixformat_t pixFormat = P
_height = resolution[frameSize][1];
}
Camera::Camera(int16_t width, uint16_t height, pixformat_t pixFormat)
{
_frameSize = FRAMESIZE_CUSTOM;
_pixFormat = pixFormat;
_width = width;
_height = height;
}
Camera::~Camera()
{

View File

@@ -44,6 +44,7 @@ typedef enum {
FRAMESIZE_SVGA, // 800x600
FRAMESIZE_SXGA, // 1280x1024
FRAMESIZE_UXGA, // 1600x1200
FRAMESIZE_CUSTOM,
} framesize_t;
@@ -51,6 +52,7 @@ class Camera{
public:
Camera(framesize_t frameSize, pixformat_t pixFormat);
Camera(int16_t width, uint16_t height, pixformat_t pixFormat);
~Camera();
virtual bool begin( ) = 0;
virtual void end() = 0;
@@ -64,8 +66,16 @@ public:
* If pixels format is RGB565: return RGB565 pixels with every uint16_t one pixel, e.g. RED: 0xF800
*/
virtual uint8_t* snapshot() = 0;
virtual uint8_t* getRGB565(){ return 0; };
virtual uint8_t* getRGB888(){ return 0; };
/**
* @return pixels with RGB565 format, every uint16_t one pixel, e.g. RED: 0xF800, so two pixels: {0xF800, 0xF800}
*/
virtual uint16_t* getRGB565(){ return nullptr; };
/**
*
* @return pixels with RGB888 format, for n pixels: {{R0,R1,...,Rn-1,},{G0,G1,...,Gn-1},{B0,B1,...,Bn-1}}
* e.g. two RED pixel: {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}
*/
virtual uint8_t* getRGB888(){ return nullptr; };
virtual void setRotaion(uint8_t rotation) = 0;
virtual void setInvert(bool invert) = 0;

View File

@@ -0,0 +1,208 @@
/**
* @file MBNet_1000.cpp
* @brief Detect object type
* @author Neucrack@sipeed.com
*/
#include "MBNet_1000.h"
#include "names.h"
#include "stdlib.h"
MBNet_1000::MBNet_1000(KPUClass& kpu, Sipeed_ST7789& lcd, Sipeed_OV2640& camera)
:_kpu(kpu),_lcd(lcd), _camera(camera),
_count(0), _result(nullptr)
{
_names = mbnet_label_name;
memset(_statistics, 0, sizeof(_statistics));
}
MBNet_1000::~MBNet_1000()
{
}
int MBNet_1000::begin(const char* kmodel_name)
{
File myFile;
if(!_camera.begin())
return -1;
if(!_lcd.begin(15000000, COLOR_RED))
return -2;
_camera.run(true);
if (!SD.begin())
return -3;
myFile = SD.open(kmodel_name);
if (!myFile)
return -4;
uint32_t fSize = myFile.size();
_lcd.setTextSize(2);
_lcd.setTextColor(COLOR_WHITE);
_lcd.setCursor(100,100);
_lcd.print("Loading ... ");
long ret = myFile.read(_model, fSize);
myFile.close();
if(ret != fSize)
return -5;
if(_kpu.begin(_model) != 0)
return -6;
return 0;
}
int MBNet_1000::detect()
{
uint8_t* img;
uint8_t* img888;
img = _camera.snapshot();
if(img == nullptr || img==0)
return -1;
img888 = _camera.getRGB888();
if(_kpu.forward(img888) != 0)
{
return -2;
}
while( !_kpu.isForwardOk() );
if( _kpu.getResult((uint8_t**)&_result, &_count) != 0)
{
return -3;
}
return 0;
}
void MBNet_1000::show()
{
float prob;
const char* name;
uint8_t i, j;
uint16_t* img;
_count /= sizeof(float);
label_init();
label_sort();
for(j=0; j<STATISTICS_NUM; ++j)
_statistics[j].updated = false;
for ( i = 0; i < 5; i++)
{
label_get(i, &prob, &name);
for(j=0; j<STATISTICS_NUM; ++j)
{
if(_statistics[j].name == NULL)
{
_statistics[j].name = name;
_statistics[j].sum = prob;
_statistics[j].updated = true;
break;
}
else if( _statistics[j].name == name )
{
_statistics[j].sum += prob;
_statistics[j].updated = true;
break;
}
else
{
}
}
if( j == STATISTICS_NUM)
{
float min = _statistics[0].sum;
j = 0;
for(i=1; i<STATISTICS_NUM; ++i)
{
if(_statistics[i].name)
{
if(_statistics[i].sum <= min)
{
min = _statistics[i].sum;
j = i;
}
}
}
_statistics[j].name = name;
_statistics[j].sum = prob;
_statistics[j].updated = true;
}
}
float max = _statistics[0].sum;
float second = 0;
uint8_t index1=0, index2 = 0;
for(i=0; i<STATISTICS_NUM; ++i)
{
if(_statistics[i].name)
{
if(_statistics[i].sum > max)
{
max = _statistics[i].sum;
index1 = i;
}
else if(_statistics[i].sum > second && _statistics[i].sum<max)
{
index2 = i;
}
}
if( !_statistics[i].updated )
{
float tmp = _statistics[i].sum - _statistics[i].sum*2/5;
if( tmp < 0)
tmp = 0;
_statistics[i].sum = tmp;
}
}
img = _camera.getRGB565();
_lcd.fillRect(224,0, _lcd.width()-224, _lcd.height(), COLOR_RED);
_lcd.drawImage(0, 0, _camera.width(), _camera.height(), img);
_lcd.setTextSize(2);
_lcd.setTextColor(COLOR_WHITE);
_lcd.setCursor(0,0);
_lcd.println(_statistics[index1].name);
_lcd.println("-----");
_lcd.println(_statistics[index2].name);
// _lcd.println("=======");
// _lcd.println(_names[_index[0]]);
// _lcd.println(_names[_index[1]]);
// _lcd.println(_names[_index[2]]);
// _lcd.println(_names[_index[3]]);
// _lcd.println(_names[_index[4]]);
}
void MBNet_1000::label_init( )
{
int i;
for(i = 0; i < _count; i++)
_index[i] = i;
}
void MBNet_1000::label_sort(void)
{
int i,j;
float tmp_prob;
uint16_t tmp_index;
for(j=0; j<_count; j++)
for(i=0; i<_count-1-j; i++)
if(_result[i]<_result[i+1])
{
tmp_prob=_result[i];
_result[i]=_result[i+1];
_result[i+1]=tmp_prob;
tmp_index=_index[i];
_index[i]=_index[i+1];
_index[i+1]=tmp_index;
}
}
void MBNet_1000::label_get(uint16_t index, float* prob, const char** name)
{
*prob = _result[index];
*name = _names[_index[index]];
}

View File

@@ -0,0 +1,53 @@
/**
* @file MBNet_1000.h
* @brief Detect object type
* @author Neucrack@sipeed.com
*/
#ifndef __MBNET_1000_H
#define __MBNET_1000_H
#include "Sipeed_OV2640.h"
#include "Sipeed_ST7789.h"
#include <SD.h>
#include <KPU.h>
#define KMODEL_SIZE (4220 * 1024)
#define STATISTICS_NUM 5
typedef struct{
const char* name;
float sum;
bool updated;
} statistics_t;
class MBNet_1000{
public:
MBNet_1000(KPUClass& kpu, Sipeed_ST7789& lcd, Sipeed_OV2640& camera);
~MBNet_1000();
int begin(const char* kmodel_name);
int detect();
void show();
const char** _names;
private:
KPUClass& _kpu;
Sipeed_ST7789& _lcd;
Sipeed_OV2640& _camera;
uint8_t _model[KMODEL_SIZE] __attribute__((aligned(128)));
size_t _count;
statistics_t _statistics[STATISTICS_NUM];
float* _result;
uint16_t _index[1000];
void label_init();
void label_get(uint16_t index, float* prob, const char** name);
void label_sort(void);
};
#endif

View File

@@ -0,0 +1,54 @@
/**
*
*
* Download model here:
* http://dl.sipeed.com/MAIX/MaixPy/model/mobilenet_0x300000.kfpkg
* Unpack it(zip format), get m.kmodel, change name to a short name "m" for example,
* put it in SD card at root path
*
*
*
*/
#include <Sipeed_OV2640.h>
#include <Sipeed_ST7789.h>
#include "MBNet_1000.h"
SPIClass spi_(SPI0); // MUST be SPI0 for Maix series on board LCD
Sipeed_ST7789 lcd(320, 240, spi_);
Sipeed_OV2640 camera(224, 224, PIXFORMAT_RGB565);
KPUClass KPU;
MBNet_1000 mbnet(KPU, lcd, camera);
const char* kmodel_name = "m";
void setup()
{
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("init mobile net, load kmodel from SD card, it may takes a long time");
if( mbnet.begin(kmodel_name) != 0)
{
Serial.println("mobile net init fail");
while(1);
}
}
void loop()
{
if(mbnet.detect() != 0)
{
Serial.println("detect object fail");
return;
}
mbnet.show();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
#ifndef __MBNET_NAMES_H
#define __MBNET_NAMES_H
extern const char* mbnet_label_name[];
#endif

View File

@@ -0,0 +1,26 @@
#######################################
# Syntax Coloring Map SD
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
KPUClass KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
forward KEYWORD2
isForwardOk KEYWORD2
getResult KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
KPU_ERROR_BUSY LITERAL1
KPU_ERROR_BAD_MODEL LITERAL1
KPU_ERROR_MODEL_VERSION LITERAL1
KPU_ERROR_NONE LITERAL1

View File

@@ -0,0 +1,9 @@
name=KPU
version=1.0.0
author= Neucrack Sipeed
maintainer=Sipeed <support@sipeed.com>
sentence=KPU API of k210
paragraph=KPU API of k210
category=Other
url=
architectures=k210

74
libraries/KPU/src/KPU.cpp Normal file
View File

@@ -0,0 +1,74 @@
#include "KPU.h"
#include "sysctl.h"
#define AI_STATUS_IDLE 0
#define AI_STATUS_BUSY 1
#define AI_STATUS_OK 2
static volatile uint32_t g_ai_done_flag = AI_STATUS_IDLE;
KPUClass::KPUClass()
:_flagGotResult(true)
{
}
KPUClass::~KPUClass()
{
end();
}
int KPUClass::begin(uint8_t* model)
{
sysctl_clock_enable(SYSCTL_CLOCK_AI);
if (kpu_load_kmodel(&_task, model) != 0)
return KPU_ERROR_BAD_MODEL;
return KPU_ERROR_NONE;
}
void KPUClass::end()
{
sysctl_clock_disable(SYSCTL_CLOCK_AI);
}
extern "C" {
static void ai_done(void* userdata)
{
bool* user_used = (bool*)userdata;
g_ai_done_flag = AI_STATUS_OK;
*user_used = false;
}
}
int KPUClass::forward(uint8_t* imgSrc, uint8_t dmaCh)
{
if(g_ai_done_flag == AI_STATUS_BUSY)
return KPU_ERROR_BUSY;
g_ai_done_flag = AI_STATUS_BUSY;
if (kpu_run_kmodel(&_task, imgSrc, (dmac_channel_number_t)dmaCh, ai_done, (void*)&_flagGotResult) != 0)
{
g_ai_done_flag = AI_STATUS_IDLE;
return KPU_ERROR_BAD_MODEL;
}
return KPU_ERROR_NONE;
}
bool KPUClass::isForwardOk()
{
return g_ai_done_flag==AI_STATUS_OK;
}
int KPUClass::getResult(uint8_t**data, size_t* count, uint32_t startIndex )
{
_flagGotResult = true;
kpu_get_output(&_task, startIndex, data, count);
return KPU_ERROR_NONE;
}

42
libraries/KPU/src/KPU.h Normal file
View File

@@ -0,0 +1,42 @@
#ifndef __MOBILENET_V1_H
#define __MOBILENET_V1_H
extern "C" {
#include "kpu.h"
}
typedef enum{
KPU_ERROR_BUSY = -3,
KPU_ERROR_BAD_MODEL = -2,
KPU_ERROR_MODEL_VERSION = -1,
KPU_ERROR_NONE = 0,
} KPU_Error_t;
class KPUClass{
public:
KPUClass();
~KPUClass();
int begin(uint8_t* model);
void end();
/**
* @param imgSrc RGB888 image source
* @param dmaCh [0,5)
*/
int forward(uint8_t* imgSrc, uint8_t dmaCh=0);
bool isForwardOk();
int getResult(uint8_t**data, size_t* count, uint32_t startIndex = 0);
private:
kpu_model_context_t _task;
bool _flagGotResult;
};
#endif

View File

@@ -95,6 +95,22 @@ int File::read(void *buf, uint16_t nbyte) {
return 0;
}
long File::read(void *buf, uint32_t nbyte) {
if (!_file)
return 0;
uint32_t bytesToRead = nbyte;
uint16_t ret, readBytesOnece;
while(bytesToRead)
{
readBytesOnece = (bytesToRead>65000) ? 65000 : bytesToRead;
ret = (uint16_t)_file->read(buf+(nbyte-bytesToRead), readBytesOnece);
if(ret == 0xffff)
return -1;
bytesToRead -= ret;
}
return nbyte;
}
int File::available() {
if (! _file) return 0;

View File

@@ -40,6 +40,7 @@ public:
virtual int available();
virtual void flush();
int read(void *buf, uint16_t nbyte);
long read(void *buf, uint32_t nbyte);
boolean seek(uint32_t pos);
uint32_t position();
uint32_t size();

View File

@@ -606,6 +606,19 @@ _id(0)
configASSERT(pixFormat == PIXFORMAT_RGB565 || pixFormat==PIXFORMAT_YUV422);
}
Sipeed_OV2640::Sipeed_OV2640(uint16_t width, uint16_t height, pixformat_t pixFormat)
:Camera(width, height, pixFormat),
_dataBuffer(NULL), _aiBuffer(NULL),
_resetPoliraty(ACTIVE_HIGH), _pwdnPoliraty(ACTIVE_HIGH),
_slaveAddr(0x00),
_id(0)
{
configASSERT(pixFormat == PIXFORMAT_RGB565 || pixFormat==PIXFORMAT_YUV422);
}
Sipeed_OV2640::~Sipeed_OV2640()
{
end();

View File

@@ -37,6 +37,7 @@ class Sipeed_OV2640 : public Camera{
public:
Sipeed_OV2640(framesize_t frameSize = FRAMESIZE_QVGA, pixformat_t pixFormat = PIXFORMAT_RGB565);
Sipeed_OV2640(uint16_t width, uint16_t height, pixformat_t pixFormat = PIXFORMAT_RGB565);
~Sipeed_OV2640();
virtual bool begin();
@@ -51,6 +52,8 @@ public:
* If pixels format is RGB565: return RGB565 pixels with every uint16_t one pixel, e.g. RED: 0xF800
*/
virtual uint8_t* snapshot();
virtual uint16_t* getRGB565(){ return (uint16_t*)_dataBuffer; };
virtual uint8_t* getRGB888(){ return _aiBuffer; };
virtual void setRotaion(uint8_t rotation);
virtual void setInvert(bool invert);

View File

@@ -174,7 +174,7 @@ void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
lcd_set_area(x, y, x, y);
tft_write_byte((uint8_t*)&color, 2);
tft_write_half(&color, 1);
}
void lcd_clear(uint16_t color)
@@ -204,13 +204,13 @@ void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint
*p++ = data;
lcd_set_area(x1, y1, x2, y1 + width - 1);
tft_write_byte((uint8_t*)data_buf, ((x2 - x1 + 1) * width + 1) * 2);
tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2);
lcd_set_area(x1, y2 - width + 1, x2, y2);
tft_write_byte((uint8_t*)data_buf, ((x2 - x1 + 1) * width + 1) * 2);
tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2);
lcd_set_area(x1, y1, x1 + width - 1, y2);
tft_write_byte((uint8_t*)data_buf, ((y2 - y1 + 1) * width + 1) * 2);
tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2);
lcd_set_area(x2 - width + 1, y1, x2, y2);
tft_write_byte((uint8_t*)data_buf, ((y2 - y1 + 1) * width + 1) * 2);
tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2);
}
#define SWAP_16(x) ((x >> 8 & 0xff) | (x << 8))

View File

@@ -73,7 +73,7 @@ void tft_write_byte(uint8_t *data_buf, uint32_t length)
{
set_dcx_data();
spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
spi_init_non_standard(g_spi_num, 0 /*instrction length*/, 8 /*address length*/, 0 /*wait cycles*/,
spi_init_non_standard(g_spi_num, 8 /*instrction length*/, 0 /*address length*/, 0 /*wait cycles*/,
SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, data_buf, length, SPI_TRANS_CHAR);
}
@@ -82,7 +82,7 @@ void tft_write_half(uint16_t *data_buf, uint32_t length)
{
set_dcx_data();
spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 16, 0);
spi_init_non_standard(g_spi_num, 0 /*instrction length*/, 16 /*address length*/, 0 /*wait cycles*/,
spi_init_non_standard(g_spi_num, 16 /*instrction length*/, 0 /*address length*/, 0 /*wait cycles*/,
SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, data_buf, length, SPI_TRANS_SHORT);
}