その2 人検出後に写真をSDに保存する
概要
この特設では、HVC-P2で人を検出した後に画像をマイクロSDに保存するサンプルを紹介します。
準備
以下の接続写真を参考に、GR-PEACH、HVC-P2のほかにUSBケーブル(マイクロBタイプ)を2本、USB(タイプA)変換アダプタを準備してください。
それから写真を保存するためにマイクロSDをGR-PEACHの裏面にあるソケットに差し込んでください。
また、GR-PEACHの中央部にあるジャンパー(JP3)をショートしてください。これによってUSBホストとして接続する際にVBUSに電源が供給されるようになります。
検出写真をSDに保存するサンプル
以下のサンプルをWebコンパイラでビルドし、実行してみてください。ソース上でダブルクリックすると全選択されます。
//* GR-PEACH Sketch Template for using HVC-P2
* based on library version V1.06
*/
// GR-PEACH API
#include <arduino.h>
#include <SD.h>
#include <RTC.h>
#include <USBHostSerial.h>
#include <JPEG_Converter.h>
// HVC-P2 API
#include "HVCApi.h" // Omron sample
#include "HVCDef.h" // Omron sample
#include "HVCExtraUartFunc.h" // Omron sample
#define USB_SETTING_TIMEOUT 1000
#define USB_EXECUTE_TIMEOUT 7000
#define ALL_DETECTION
#define SENSOR_ROLL_ANGLE_DEFAULT 0 /* Camera angle setting (0°) */
#define BODY_THRESHOLD_DEFAULT 500 /* Threshold for Human Body Detection */
#define FACE_THRESHOLD_DEFAULT 500 /* Threshold for Face Detection */
#define HAND_THRESHOLD_DEFAULT 500 /* Threshold for Hand Detection */
#define REC_THRESHOLD_DEFAULT 500 /* Threshold for Face Recognition */
#define BODY_SIZE_RANGE_MIN_DEFAULT 30 /* Human Body Detection minimum detection size */
#define BODY_SIZE_RANGE_MAX_DEFAULT 8192 /* Human Body Detection maximum detection size */
#define HAND_SIZE_RANGE_MIN_DEFAULT 40 /* Hand Detection minimum detection size */
#define HAND_SIZE_RANGE_MAX_DEFAULT 8192 /* Hand Detection maximum detection size */
#define FACE_SIZE_RANGE_MIN_DEFAULT 64 /* Face Detection minimum detection size */
#define FACE_SIZE_RANGE_MAX_DEFAULT 8192 /* Face Detection maximum detection size */
#define FACE_POSE_DEFAULT 0 /* Face Detection facial pose (frontal face)*/
#define FACE_ANGLE_DEFAULT 0 /* Face Detection roll angle (±15°)*/
#define PIXEL_WIDTH (320)
#define PIXEL_HEIGHT (240)
#define BYTE_PER_PIXEL_YUV (2u)
#define BYTE_PER_PIXEL_RGB (3u)
#define FRAME_STRIDE_YUV (((PIXEL_WIDTH * BYTE_PER_PIXEL_YUV) + 31u) & ~31u)
#define FRAME_STRIDE_RGB (((PIXEL_WIDTH * BYTE_PER_PIXEL_RGB) + 31u) & ~31u)
/*! Frame buffer stride: Frame buffer stride should be set to a multiple of 32 or 128
in accordance with the frame buffer burst transfer mode. */
static uint8_t frame_buffer_YUV422[FRAME_STRIDE_YUV * PIXEL_HEIGHT]__attribute((section("NC_BSS"),aligned(32)));
static uint8_t frame_buffer_RGB888[FRAME_STRIDE_RGB * PIXEL_HEIGHT]__attribute((section("NC_BSS"),aligned(32)));
static uint8_t JpegBuffer[1024 * 200]__attribute((aligned(8))); //8 bytes aligned!;
static volatile int jcu_encoding = 1;
static volatile int jcu_encode_size = 1;
static JPEG_Converter Jcu;
static RTC rtc;
static int year, mon, day, hour, min, sec, week;
void sd_timestamp(uint16_t* date, uint16_t* time) {
*date = FAT_DATE(year, mon, day);
*time = FAT_TIME(hour, min, sec);
}
static USBHostSerial * p_cdc;
extern "C" int UART_SendData(int inDataSize, UINT8 *inData) {
return p_cdc->writeBuf((char *) inData, inDataSize);
}
extern "C" int UART_ReceiveData(int inTimeOutTime, int inDataSize,
UINT8 *outResult) {
return p_cdc->readBuf((char *) outResult, inDataSize, inTimeOutTime);
}
void led_blink(int pin, int num) {
for (int i = 0; i < num; i++) {
digitalWrite(pin, HIGH);
delay(200);
digitalWrite(pin, LOW);
delay(200);
}
}
static void EraseImage(uint8_t* buf, uint32_t size) {
uint32_t i = 0;
while (i < size) {
buf[i++] = 0x10;
buf[i++] = 0x80;
}
}
static void dcache_invalid(void * p_buf, uint32_t size) {
uint32_t start_addr = (uint32_t) p_buf & 0xFFFFFFE0;
uint32_t end_addr = (uint32_t) p_buf + size;
uint32_t addr;
// Data cache invalid
for (addr = start_addr; addr < end_addr; addr += 0x20) {
__v7_inv_dcache_mva((void *) addr);
}
}
void JcuEncodeCallBackFunc(JPEG_Converter::jpeg_conv_error_t err_code) {
jcu_encoding = 0;
}
size_t JpegEncode(uint8_t* buf, int len, int width, int height, uint8_t* inbuf) {
size_t encode_size;
JPEG_Converter::bitmap_buff_info_t bitmap_buff_info;
JPEG_Converter::encode_options_t encode_options;
bitmap_buff_info.width = width;
bitmap_buff_info.height = height;
bitmap_buff_info.format = JPEG_Converter::WR_RD_YCbCr422;
bitmap_buff_info.buffer_address = (void *) inbuf;
encode_options.encode_buff_size = sizeof(buf);
encode_options.p_EncodeCallBackFunc = &JcuEncodeCallBackFunc;
// encode_options.input_swapsetting = JPEG_Converter::WR_RD_WRSWA_32_16_8BIT;
jcu_encoding = 1; // flag for waiting callback function of JCU
jcu_encode_size = 0;
dcache_invalid(buf, len);
if (Jcu.encode(&bitmap_buff_info, buf, &encode_size, &encode_options)
!= JPEG_Converter::JPEG_CONV_OK) {
jcu_encode_size = 0;
jcu_encoding = 0;
}
while (jcu_encoding == 1) {
delay(1);
}
return encode_size;
}
static void DrawSquare(int x, int y, int size, uint32_t const colour, uint8_t* inbuf) {
int wk_x;
int wk_y;
int wk_w = 0;
int wk_h = 0;
int idx_base;
int wk_idx;
int i;
int j;
uint8_t coller_pix[BYTE_PER_PIXEL_RGB];
bool l_draw = true;
bool r_draw = true;
bool t_draw = true;
bool b_draw = true;
if ((x - (size / 2)) < 0) {
l_draw = false;
wk_w += x;
wk_x = 0;
} else {
wk_w += (size / 2);
wk_x = x - (size / 2);
}
if ((x + (size / 2)) >= 1600) {
r_draw = false;
wk_w += (1600 - x);
} else {
wk_w += (size / 2);
}
if ((y - (size / 2)) < 0) {
t_draw = false;
wk_h += y;
wk_y = 0;
} else {
wk_h += (size / 2);
wk_y = y - (size / 2);
}
if ((y + (size / 2)) >= 1200) {
b_draw = false;
wk_h += (1200 - y);
} else {
wk_h += (size / 2);
}
wk_x = wk_x / 5;
wk_y = wk_y / 5;
wk_w = wk_w / 5;
wk_h = wk_h / 5;
idx_base = (wk_x + (PIXEL_WIDTH * wk_y)) * BYTE_PER_PIXEL_RGB;
/* Select color */
coller_pix[0] = (colour >> 16) & 0xff;
coller_pix[1] = (colour >> 8) & 0xff;
coller_pix[2] = colour & 0xff;
/* top */
if (t_draw) {
wk_idx = idx_base;
for (j = 0; j < wk_w; j++) {
inbuf[wk_idx++] = coller_pix[0];
inbuf[wk_idx++] = coller_pix[1];
inbuf[wk_idx++] = coller_pix[2];
}
}
/* middle */
for (i = 1; i < (wk_h - 1); i++) {
wk_idx = idx_base + (PIXEL_WIDTH * BYTE_PER_PIXEL_RGB * i);
if (l_draw) {
inbuf[wk_idx + 0] = coller_pix[0];
inbuf[wk_idx + 1] = coller_pix[1];
inbuf[wk_idx + 2] = coller_pix[2];
}
wk_idx += (wk_w - 1) * 3;
if (r_draw) {
inbuf[wk_idx + 0] = coller_pix[0];
inbuf[wk_idx + 1] = coller_pix[1];
inbuf[wk_idx + 2] = coller_pix[2];
}
}
/* bottom */
if (b_draw) {
wk_idx = idx_base + (PIXEL_WIDTH * BYTE_PER_PIXEL_RGB * (wk_h - 1));
for (j = 0; j < wk_w; j++) {
inbuf[wk_idx++] = coller_pix[0];
inbuf[wk_idx++] = coller_pix[1];
inbuf[wk_idx++] = coller_pix[2];
}
}
}
void setup() {
INT32 ret = 0; /* Return code */
UINT8 status;
HVC_RESULT *pHVCResult = NULL;
HVC_IMAGE *pImage = NULL;
INT32 agleNo;
HVC_THRESHOLD threshold;
HVC_SIZERANGE sizeRange;
INT32 pose;
INT32 angle;
INT32 timeOutTime;
INT32 execFlag;
const char *pExStr[] = { "?", "Neutral", "Happiness", "Surprise", "Anger",
"Sadness" };
int i;
int ch = 0;
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_LED_GREEN, OUTPUT);
pinMode(PIN_LED_BLUE, OUTPUT);
Serial.begin(9600);
Serial.println("Program starts");
USBHostSerial cdc;
p_cdc = &cdc; // for HVC P2 API
Serial.print("SD & RTC initialization...");
year = 2017;
mon = 2;
day = 15;
hour = 11;
min = 14;
sec = 0;
week = RTC_WEEK_WEDNESDAY;
rtc.begin();
rtc.setDateTime(year, mon, day, hour, min, sec, week);
SdFile::dateTimeCallback(&sd_timestamp);
if (!SD.begin()) {
Serial.println("initialization failed!");
return;
}
Serial.println("done.");
Serial.print("Waiting USB device...");
while (!p_cdc->connect()) { // wait for connecting HVC
led_blink(PIN_LED_RED, 1);
Thread::wait(500);
}
Serial.println("found.");
led_blink(PIN_LED_GREEN, 2);
p_cdc->baud(921600);
/*********************************/
/* Result Structure Allocation */
/*********************************/
pHVCResult = (HVC_RESULT *) malloc(sizeof(HVC_RESULT));
if (pHVCResult == NULL) { /* Error processing */
Serial.println("Memory Allocation Error");
mbed_die();
}
/* Image Structure allocation */
pImage = (HVC_IMAGE *) malloc(sizeof(HVC_IMAGE));
if (pImage == NULL) {
printf("Memory Allocation Error : %08x\n", sizeof(HVC_RESULT));
mbed_die();
}
/*********************************/
/* Set Camera Angle */
/*********************************/
agleNo = SENSOR_ROLL_ANGLE_DEFAULT;
ret = HVC_SetCameraAngle(USB_SETTING_TIMEOUT, agleNo, &status);
/*********************************/
/* Set Threshold Values */
/*********************************/
threshold.bdThreshold = BODY_THRESHOLD_DEFAULT;
threshold.hdThreshold = HAND_THRESHOLD_DEFAULT;
threshold.dtThreshold = FACE_THRESHOLD_DEFAULT;
threshold.rsThreshold = REC_THRESHOLD_DEFAULT;
ret = HVC_SetThreshold(USB_SETTING_TIMEOUT, &threshold, &status);
/*********************************/
/* Set Detection Size */
/*********************************/
sizeRange.bdMinSize = BODY_SIZE_RANGE_MIN_DEFAULT;
sizeRange.bdMaxSize = BODY_SIZE_RANGE_MAX_DEFAULT;
sizeRange.hdMinSize = HAND_SIZE_RANGE_MIN_DEFAULT;
sizeRange.hdMaxSize = HAND_SIZE_RANGE_MAX_DEFAULT;
sizeRange.dtMinSize = FACE_SIZE_RANGE_MIN_DEFAULT;
sizeRange.dtMaxSize = FACE_SIZE_RANGE_MAX_DEFAULT;
ret = HVC_SetSizeRange(USB_SETTING_TIMEOUT, &sizeRange, &status);
/*********************************/
/* Set Face Angle */
/*********************************/
pose = FACE_POSE_DEFAULT;
angle = FACE_ANGLE_DEFAULT;
ret = HVC_SetFaceDetectionAngle(USB_SETTING_TIMEOUT, pose, angle, &status);
/*********************************/
/* Execute Detection */
/*********************************/
do {
timeOutTime = USB_EXECUTE_TIMEOUT;
#ifdef ALL_DETECTION
execFlag = HVC_ACTIV_BODY_DETECTION | HVC_ACTIV_HAND_DETECTION |
HVC_ACTIV_FACE_DETECTION | HVC_ACTIV_FACE_DIRECTION |
HVC_ACTIV_AGE_ESTIMATION | HVC_ACTIV_GENDER_ESTIMATION |
HVC_ACTIV_GAZE_ESTIMATION | HVC_ACTIV_BLINK_ESTIMATION |
HVC_ACTIV_EXPRESSION_ESTIMATION;
#else
execFlag = HVC_ACTIV_FACE_DETECTION | HVC_ACTIV_FACE_DIRECTION |
HVC_ACTIV_AGE_ESTIMATION | HVC_ACTIV_GENDER_ESTIMATION |
HVC_ACTIV_GAZE_ESTIMATION | HVC_ACTIV_BLINK_ESTIMATION |
HVC_ACTIV_EXPRESSION_ESTIMATION;
#endif
Serial.println("Executing Detection");
ret = HVC_ExecuteEx(timeOutTime, execFlag, HVC_EXECUTE_IMAGE_QVGA,
pHVCResult, &status);
if ((ret != 0) || (status != 0)) {
Serial.println("HVC_ExecuteEx Error");
}
if(pHVCResult->bdResult.num | pHVCResult->hdResult.num | pHVCResult->fdResult.num){
// Prepare image data
// HVC-P2 outputs Y in order 4-3-2-1
// To simplify data processing, convert from 4-3-2-1 to 1-2-3-4
led_blink(PIN_LED_BLUE, 2);
for (int i = 0; i < PIXEL_HEIGHT; i++){
for (int j = 0; j < (PIXEL_WIDTH / 4); j++){
uint8_t temp[4];
temp[0] = pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 3];
temp[1] = pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 2];
temp[2] = pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 1];
temp[3] = pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 0];
pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 0] = temp[0];
pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 1] = temp[1];
pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 2] = temp[2];
pHVCResult->image.image[i * PIXEL_WIDTH + j * 4 + 3] = temp[3];
}
}
EraseImage(frame_buffer_YUV422, sizeof(frame_buffer_YUV422));
#if 0 // Y to YUV422
for (int i = 0; i < PIXEL_HEIGHT; i++) {
for (int j = 0; j < (PIXEL_WIDTH); j++) {
frame_buffer_YUV422[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_YUV)
+ BYTE_PER_PIXEL_YUV * j] = pHVCResult->image.image[i * PIXEL_WIDTH + j];
}
}
#endif
for (int i = 0; i < PIXEL_HEIGHT; i++) {
for (int j = 0; j < PIXEL_WIDTH; j++) {
uint8_t Y = pHVCResult->image.image[i * PIXEL_WIDTH + j];
for (int k = 0; k < 3; k++){
frame_buffer_RGB888[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_RGB)
+ BYTE_PER_PIXEL_RGB * j + k] = Y;
}
}
}
}
if(pHVCResult->executedFunc & HVC_ACTIV_BODY_DETECTION){
/* Body Detection result string */
Serial.print("Body result count:"); Serial.println(pHVCResult->bdResult.num);
for(i = 0; i < pHVCResult->bdResult.num; i++){
Serial.print("Index:"); Serial.println(i);
Serial.print("X = "); Serial.print(pHVCResult->bdResult.bdResult[i].posX);
Serial.print(" Y = "); Serial.print(pHVCResult->bdResult.bdResult[i].posY);
Serial.print(" Size = "); Serial.print(pHVCResult->bdResult.bdResult[i].size);
Serial.print(" Confidence = "); Serial.print(pHVCResult->bdResult.bdResult[i].confidence);
Serial.println();
// Draw red square
DrawSquare(pHVCResult->bdResult.bdResult[i].posX,
pHVCResult->bdResult.bdResult[i].posY,
pHVCResult->bdResult.bdResult[i].size,
0x00f00000, frame_buffer_RGB888);
}
}
if(pHVCResult->executedFunc & HVC_ACTIV_HAND_DETECTION){
/* Hand Detection result string */
Serial.print("Hand result count:"); Serial.println(pHVCResult->hdResult.num);
for(i = 0; i < pHVCResult->hdResult.num; i++){
Serial.print("Index:"); Serial.println(i);
Serial.print("X = "); Serial.print(pHVCResult->hdResult.hdResult[i].posX);
Serial.print(" Y = "); Serial.print(pHVCResult->hdResult.hdResult[i].posY);
Serial.print(" Size = "); Serial.print(pHVCResult->hdResult.hdResult[i].size);
Serial.print(" Confidence = "); Serial.print(pHVCResult->hdResult.hdResult[i].confidence);
Serial.println();
// Draw yellow square
DrawSquare(pHVCResult->hdResult.hdResult[i].posX,
pHVCResult->hdResult.hdResult[i].posY,
pHVCResult->hdResult.hdResult[i].size,
0x00f0f000, frame_buffer_RGB888);
}
}
/* Face Detection result string */
if(pHVCResult->executedFunc &
(HVC_ACTIV_FACE_DETECTION | HVC_ACTIV_FACE_DIRECTION |
HVC_ACTIV_AGE_ESTIMATION | HVC_ACTIV_GENDER_ESTIMATION |
HVC_ACTIV_GAZE_ESTIMATION | HVC_ACTIV_BLINK_ESTIMATION |
HVC_ACTIV_EXPRESSION_ESTIMATION | HVC_ACTIV_FACE_RECOGNITION)){
Serial.print("Face result count:"); Serial.println(pHVCResult->fdResult.num);
for(i = 0; i < pHVCResult->fdResult.num; i++){
if(pHVCResult->executedFunc & HVC_ACTIV_FACE_DETECTION){
/* Detection */
Serial.print("Index:"); Serial.println(i);
Serial.print("X = "); Serial.print(pHVCResult->fdResult.fcResult[i].dtResult.posX);
Serial.print(" Y = "); Serial.print(pHVCResult->fdResult.fcResult[i].dtResult.posY);
Serial.print(" Size = "); Serial.print(pHVCResult->fdResult.fcResult[i].dtResult.size);
Serial.print(" Confidence = "); Serial.print(pHVCResult->fdResult.fcResult[i].dtResult.confidence);
Serial.println();
}
if(pHVCResult->executedFunc & HVC_ACTIV_FACE_DIRECTION){
/* Face Direction */
Serial.print("Face Direction : ");
Serial.print("LR = "); Serial.print(pHVCResult->fdResult.fcResult[i].dirResult.yaw);
Serial.print(" UD = "); Serial.print(pHVCResult->fdResult.fcResult[i].dirResult.pitch);
Serial.print(" Roll = "); Serial.print(pHVCResult->fdResult.fcResult[i].dirResult.roll);
Serial.print(" Confidence = "); Serial.print(pHVCResult->fdResult.fcResult[i].dirResult.confidence);
Serial.println();
}
if(pHVCResult->executedFunc & HVC_ACTIV_AGE_ESTIMATION){
/* Age */
if(-128 == pHVCResult->fdResult.fcResult[i].ageResult.age){
Serial.println("Age Estimation not possible");
} else {
Serial.print("Age = ");
Serial.print(pHVCResult->fdResult.fcResult[i].ageResult.age);
Serial.print(" Confidence = ");
Serial.print(pHVCResult->fdResult.fcResult[i].ageResult.confidence);
Serial.println();
}
}
if(pHVCResult->executedFunc & HVC_ACTIV_GENDER_ESTIMATION){
/* Gender */
if(-128 == pHVCResult->fdResult.fcResult[i].genderResult.gender){
Serial.println("Gender Estimation not possible");
}
else{
if(1 == pHVCResult->fdResult.fcResult[i].genderResult.gender){
Serial.print("Gender Male Confidence = ");
Serial.print(pHVCResult->fdResult.fcResult[i].genderResult.confidence);
Serial.println();
// Draw sky blue square
DrawSquare(pHVCResult->fdResult.fcResult[i].dtResult.posX,
pHVCResult->fdResult.fcResult[i].dtResult.posY,
pHVCResult->fdResult.fcResult[i].dtResult.size,
0x0000f0f0, frame_buffer_RGB888);
}
else{
Serial.print("Gender Female Confidence = ");
Serial.print(pHVCResult->fdResult.fcResult[i].genderResult.confidence);
Serial.println();
// Draw pink square
DrawSquare(pHVCResult->fdResult.fcResult[i].dtResult.posX,
pHVCResult->fdResult.fcResult[i].dtResult.posY,
pHVCResult->fdResult.fcResult[i].dtResult.size,
0x00f000f0, frame_buffer_RGB888);
}
}
}
if(pHVCResult->executedFunc & HVC_ACTIV_GAZE_ESTIMATION){
/* Gaze */
if((-128 == pHVCResult->fdResult.fcResult[i].gazeResult.gazeLR) ||
(-128 == pHVCResult->fdResult.fcResult[i].gazeResult.gazeUD)){
Serial.println("Gaze Estimation not possible");
}
else{
Serial.print("Gaze : ");
Serial.print("LR = "); Serial.print(pHVCResult->fdResult.fcResult[i].gazeResult.gazeLR);
Serial.print(" UD = "); Serial.print(pHVCResult->fdResult.fcResult[i].gazeResult.gazeUD);
Serial.println();
}
}
if(pHVCResult->executedFunc & HVC_ACTIV_BLINK_ESTIMATION){
/* Blink */
if((-128 == pHVCResult->fdResult.fcResult[i].blinkResult.ratioL) ||
(-128 == pHVCResult->fdResult.fcResult[i].blinkResult.ratioR)){
Serial.println("Gaze Estimation not possible");
}
else{
Serial.print("Blink : ");
Serial.print("Left = "); Serial.print(pHVCResult->fdResult.fcResult[i].blinkResult.ratioL);
Serial.print(" Right = "); Serial.print(pHVCResult->fdResult.fcResult[i].blinkResult.ratioR);
Serial.println();
}
}
if(pHVCResult->executedFunc & HVC_ACTIV_EXPRESSION_ESTIMATION){
/* Expression */
if(-128 == pHVCResult->fdResult.fcResult[i].expressionResult.score[0]){
Serial.println("Expression Estimation not possible");
}
else{
if(pHVCResult->fdResult.fcResult[i].expressionResult.topExpression > EX_SADNESS){
pHVCResult->fdResult.fcResult[i].expressionResult.topExpression = 0;
}
Serial.print("Expression : ");
Serial.print("Expression = "); Serial.print(pExStr[pHVCResult->fdResult.fcResult[i].expressionResult.topExpression]);
Serial.print(" Score = ");
Serial.print(pHVCResult->fdResult.fcResult[i].expressionResult.score[0]);
Serial.print(" ");
Serial.print(pHVCResult->fdResult.fcResult[i].expressionResult.score[1]);
Serial.print(" ");
Serial.print(pHVCResult->fdResult.fcResult[i].expressionResult.score[2]);
Serial.print(" ");
Serial.print(pHVCResult->fdResult.fcResult[i].expressionResult.score[3]);
Serial.print(" ");
Serial.print(pHVCResult->fdResult.fcResult[i].expressionResult.score[4]);
Serial.print(" Degree = ");
Serial.print(pHVCResult->fdResult.fcResult[i].expressionResult.degree);
Serial.println();
}
}
}
}
if(pHVCResult->bdResult.num | pHVCResult->hdResult.num | pHVCResult->fdResult.num){
// Save image to SD
for (int i = 0; i < PIXEL_HEIGHT; i++) {
for (int j = 0; j < PIXEL_WIDTH; j+=2) { // processing 2 pixels
uint8_t r0,g0,b0,r1,g1,b1,y0,y1,u,v;
r1 = frame_buffer_RGB888[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_RGB)
+ BYTE_PER_PIXEL_RGB * j + 5];
g1 = frame_buffer_RGB888[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_RGB)
+ BYTE_PER_PIXEL_RGB * j + 4];
b1 = frame_buffer_RGB888[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_RGB)
+ BYTE_PER_PIXEL_RGB * j + 3];
r0 = frame_buffer_RGB888[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_RGB)
+ BYTE_PER_PIXEL_RGB * j + 2];
g0 = frame_buffer_RGB888[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_RGB)
+ BYTE_PER_PIXEL_RGB * j + 1];
b0 = frame_buffer_RGB888[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_RGB)
+ BYTE_PER_PIXEL_RGB * j + 0];
y0 = round( 0.256788 * r0 + 0.504129 * g0 + 0.097906 * b0) + 16;
y1 = round( 0.256788 * r1 + 0.504129 * g1 + 0.097906 * b1) + 16;
if(r0!=g0){ // it's not gray that means color line
u = round(-0.148223 * r0 - 0.290993 * g0 + 0.439216 * b0) + 128;
v = round( 0.439216 * r0 - 0.367788 * g0 - 0.071427 * b0) + 128;
} else if (r1!=g1){ // it's not gray that means color line
u = round(-0.148223 * r1 - 0.290993 * g1 + 0.439216 * b1) + 128;
v = round( 0.439216 * r1 - 0.367788 * g1 - 0.071427 * b1) + 128;
} else { // it's gray.
u = round(-0.148223 * r0 - 0.290993 * g0 + 0.439216 * b0) + 128;
v = round( 0.439216 * r0 - 0.367788 * g0 - 0.071427 * b0) + 128;
}
frame_buffer_YUV422[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_YUV)
+ BYTE_PER_PIXEL_YUV * j + 0] = y0;
frame_buffer_YUV422[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_YUV)
+ BYTE_PER_PIXEL_YUV * j + 1] = u;
frame_buffer_YUV422[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_YUV)
+ BYTE_PER_PIXEL_YUV * j + 2] = y1;
frame_buffer_YUV422[(i * PIXEL_WIDTH * BYTE_PER_PIXEL_YUV)
+ BYTE_PER_PIXEL_YUV * j + 3] = v;
}
}
Serial.print("JPEG encoding...");
int encode_size = JpegEncode(JpegBuffer, sizeof(JpegBuffer), PIXEL_WIDTH, PIXEL_HEIGHT, frame_buffer_YUV422);
Serial.print(encode_size); Serial.println("byte");
static int file_index;
char filename[11];
file_index++;
sprintf(filename, "image%d.jpg", file_index);
Serial.print(filename); Serial.print(" writing... ");
File myFile = SD.open(filename, 0x13); //WRITE, READ, CREATE
if (myFile) {
for (int i = 0; i < encode_size; i++) {
myFile.write(JpegBuffer[i]);
}
} else {
Serial.println("Fail to open file");
}
myFile.close();
Serial.println("done.");
}
if (Serial.available()) {
ch = Serial.read();
}
} while (ch != ' ');
while (1)
;
}
void loop() {
}
正常に動作するとマイクロSDに写真が保存されます。少し長いプログラムですので簡単に流れを説明します。
まず、HVC-P2を初期設定後に検出がスタートします。検出後にY 8bitで出力されたグレー画像を一旦RGB888形式でバッファリングします。RGB形式にしているのは四角を描くためです。
検出された位置、サイズをもとにRGB画像にDrawSqare関数で四角を描きます。その後JPEG画像にするため、一旦YUV422形式に変換します。ちなみにYUV422では2ピクセルに1つのカラー情報しかないため、変換することで四角の縦の線が若干が崩れてしまいます。RGBのままJPEG変換できればよいのですが、未サポートになっています。
なお、デフォルトのサンプルでは顔、ボディ、手のすべてを検出対象にしており、検出速度はやや遅いです。#define ALL_DETECTIONをコメントアウトすると顔検出だけになり、検出速度が早くなります。