Chiaki Kanazawa / Mbed OS camera_oekaki
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "opencv.hpp"
00003 #include "EasyAttach_CameraAndLCD.h"
00004 #include "dcache-control.h"
00005 #include "AsciiFont.h"
00006 #include "hal/trng_api.h"
00007 #include "oekaki_theme.h"
00008 
00009 #define PLOT_INTERVAL          (30)
00010 #define DIST_SCALE_FACTOR_X    (6.0)
00011 #define DIST_SCALE_FACTOR_Y    (6.0)
00012 
00013 #define STRING_DISP_TEST       (1)
00014 #define DRAW_POINT (3)
00015 #define ERASER_POINT (10)
00016 #define TOUCH_BUFFER_BYTE_PER_PIXEL (2u)
00017 #define TOUCH_BUFFER_STRIDE           (((LCD_PIXEL_WIDTH * TOUCH_BUFFER_BYTE_PER_PIXEL) + 31u) & ~31u)
00018 #define COLOR_BLUE cv::Scalar(0,255,0)
00019 
00020 /*! Frame buffer stride: Frame buffer stride should be set to a multiple of 32 or 128
00021     in accordance with the frame buffer burst transfer mode. */
00022 #define VIDEO_PIXEL_HW         (160u)  /* HQVGA */
00023 #define VIDEO_PIXEL_VW         (120u)  /* HQVGA */
00024 
00025 #define FRAME_BUFFER_STRIDE    (((VIDEO_PIXEL_HW * 2) + 31u) & ~31u)
00026 #define FRAME_BUFFER_HEIGHT    (VIDEO_PIXEL_VW)
00027 
00028 #if defined(__ICCARM__)
00029 #pragma data_alignment=32
00030 static uint8_t user_frame_buffer0[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]@ ".mirrorram";
00031 static uint8_t user_frame_buffer1[TOUCH_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]@ ".mirrorram";
00032 #else
00033 static uint8_t user_frame_buffer0[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((section("NC_BSS"),aligned(32)));
00034 static uint8_t user_frame_buffer1[TOUCH_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]__attribute((section("NC_BSS"),aligned(32)));//cameraみたい
00035 #endif
00036 static volatile int Vfield_Int_Cnt = 0;
00037 
00038 static InterruptIn skip_btn0(USER_BUTTON0);
00039 static InterruptIn skip_btn1(USER_BUTTON1);
00040 static int clr=0;//カラー選択(0=青、 1=黒(消しゴム))
00041 static int layer2flg=0;
00042 static int kesiflg=0;//1のとき、消しゴムを使ったあと。
00043 static bool btndownflg=false;
00044 static int16_t RangeCorr(int16_t target ,int16_t uplimit,int16_t lowlimit);
00045 static uint8_t get_random(void);
00046 
00047 DisplayBase Display;
00048 DigitalOut  led1(LED1);
00049 static Thread mainTask(osPriorityNormal, 1024 * 16);
00050 
00051 static void IntCallbackFunc_Vfield(DisplayBase::int_type_t int_type) {
00052     if (Vfield_Int_Cnt > 0) {
00053         Vfield_Int_Cnt--;
00054     }
00055 }
00056 
00057 static void wait_new_image(void) {
00058     Vfield_Int_Cnt = 1;
00059     while (Vfield_Int_Cnt > 0) {
00060         ThisThread::sleep_for(1);
00061     }
00062 }
00063 
00064 static void Start_Video_Camera(void) {
00065     // Field end signal for recording function in scaler 0
00066     Display.Graphics_Irq_Handler_Set(DisplayBase::INT_TYPE_S0_VFIELD, 0, IntCallbackFunc_Vfield);
00067 
00068     // Video capture setting (progressive form fixed)
00069     Display.Video_Write_Setting(
00070         DisplayBase::VIDEO_INPUT_CHANNEL_0,
00071         DisplayBase::COL_SYS_NTSC_358,
00072         (void *)user_frame_buffer0,
00073         FRAME_BUFFER_STRIDE,
00074         DisplayBase::VIDEO_FORMAT_YCBCR422,
00075         DisplayBase::WR_RD_WRSWA_32_16BIT,
00076         VIDEO_PIXEL_VW,
00077         VIDEO_PIXEL_HW
00078     );
00079     EasyAttach_CameraStart(Display, DisplayBase::VIDEO_INPUT_CHANNEL_0);
00080 }
00081 
00082 #if MBED_CONF_APP_LCD
00083 static void Start_LCD_Display(void) {
00084     DisplayBase::rect_t rect;
00085 
00086     /* The layer by which the touch panel location is drawn */
00087     memset(user_frame_buffer1, 0, sizeof(user_frame_buffer1));//framebufferの名前を変えた、
00088     dcache_clean(user_frame_buffer1, sizeof(user_frame_buffer1));//framebufferの名前を変えた、
00089     rect.vs = 0;
00090     rect.vw = LCD_PIXEL_HEIGHT;
00091     rect.hs = 0;
00092     rect.hw = LCD_PIXEL_WIDTH;
00093     Display.Graphics_Read_Setting(
00094         DisplayBase::GRAPHICS_LAYER_0,
00095         (void *)user_frame_buffer1,
00096         TOUCH_BUFFER_STRIDE,
00097         DisplayBase::GRAPHICS_FORMAT_ARGB4444,
00098         DisplayBase::WR_RD_WRSWA_32_16BIT,
00099         &rect
00100     );
00101     Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_0);
00102 
00103     ThisThread::sleep_for(50);
00104     EasyAttach_LcdBacklight(true);
00105 }
00106 
00107 #if STRING_DISP_TEST
00108 //文字列出力
00109 #define STRING_PIXEL_HW               (129)
00110 #define STRING_PIXEL_VM               (24)
00111 #define STRING_BUFFER_BYTE_PER_PIXEL  (2u)
00112 #define STRING_BUFFER_STRIDE          (((LCD_PIXEL_WIDTH * STRING_BUFFER_BYTE_PER_PIXEL) + 31u) & ~31u)
00113 
00114 #if defined(__ICCARM__)
00115 #pragma data_alignment=32
00116 static uint8_t user_frame_buffer_string[STRING_BUFFER_STRIDE * STRING_PIXEL_VM];
00117 #else
00118 static uint8_t user_frame_buffer_string[STRING_BUFFER_STRIDE * STRING_PIXEL_VM]__attribute((aligned(32)));
00119 #endif
00120 
00121 static void string_task(void){
00122   DisplayBase::rect_t rect;
00123 
00124   memset(user_frame_buffer_string,0,sizeof(user_frame_buffer_string));
00125   dcache_clean(user_frame_buffer_string,sizeof(user_frame_buffer_string));
00126 
00127   rect.vs = LCD_PIXEL_HEIGHT - STRING_PIXEL_VM - 10;
00128   rect.vw = STRING_PIXEL_VM;
00129   rect.hs = LCD_PIXEL_WIDTH - STRING_PIXEL_HW-10;
00130   rect.hw = STRING_PIXEL_HW;
00131   Display.Graphics_Read_Setting(
00132     DisplayBase::GRAPHICS_LAYER_2,
00133     (void *)user_frame_buffer_string,
00134     STRING_BUFFER_STRIDE,
00135     DisplayBase::GRAPHICS_FORMAT_ARGB4444,
00136     DisplayBase::WR_RD_WRSWA_32_16BIT,
00137     &rect
00138   );
00139   Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_2);
00140 
00141   AsciiFont ascii_font(user_frame_buffer_string,STRING_PIXEL_HW,STRING_PIXEL_VM,
00142     STRING_BUFFER_STRIDE,STRING_BUFFER_BYTE_PER_PIXEL);
00143 
00144     int num=get_random();
00145     int layer2flg_last = -1;
00146     while(1){
00147     if(layer2flg_last!=layer2flg){
00148       if(layer2flg==0){
00149         ascii_font.DrawStr(ChooseTheme(num), 0, 0 , 0x0000ffff, 2);//白
00150       }else{
00151         memset(user_frame_buffer_string,0,sizeof(user_frame_buffer_string));
00152       }
00153       dcache_clean(user_frame_buffer_string,sizeof(user_frame_buffer_string));
00154       layer2flg_last=layer2flg;
00155     }
00156     ThisThread::sleep_for(50);
00157   }
00158 }
00159 #endif
00160 
00161 static void draw_touch_pos(uint8_t * p_buf, int id, int drawpoint,int x, int y) { //バッファ,色,線の太さ,x座標,y座標
00162     int idx_base;
00163     int wk_idx;
00164     int i;
00165     int j;
00166     uint8_t coller_pix[TOUCH_BUFFER_BYTE_PER_PIXEL];  /* ARGB4444 */
00167 
00168     /* A coordinate in the upper left is calculated from a central coordinate. */
00169     if ((x - (drawpoint / 2)) >= 0) {
00170         x -= (drawpoint / 2);
00171     }
00172     if (x > ((int)LCD_PIXEL_WIDTH - drawpoint)) {
00173         x = ((int)LCD_PIXEL_WIDTH - drawpoint);
00174     }
00175     if ((y - (drawpoint / 2)) >= 0) {
00176         y -= (drawpoint / 2);
00177     }
00178     if (y > ((int)LCD_PIXEL_HEIGHT - drawpoint)) {
00179         y = ((int)LCD_PIXEL_HEIGHT - drawpoint);
00180     }
00181     idx_base = (x + ((int)LCD_PIXEL_WIDTH * y)) * TOUCH_BUFFER_BYTE_PER_PIXEL;
00182 
00183     /* Select color */
00184     if (id == 0) {
00185         /* Blue */
00186         coller_pix[0] = 0x0F;  /* 4:Green 4:Blue */
00187         coller_pix[1] = 0xF0;  /* 4:Alpha 4:Red  */
00188     } else if (id == 1){
00189 
00190         /* black */
00191         coller_pix[0] = 0x00;  /* 4:Green 4:Blue */
00192         coller_pix[1] = 0x00;  /* 4:Alpha 4:Red  */
00193     } else {
00194         /* red */
00195         coller_pix[0] = 0x01;
00196         coller_pix[1] = 0xFF;
00197       }
00198 
00199     /* Drawing */
00200     for (i = 0; i < drawpoint; i++) {
00201         wk_idx = idx_base + ((int)LCD_PIXEL_WIDTH * TOUCH_BUFFER_BYTE_PER_PIXEL * i);
00202         for (j = 0; j < drawpoint; j++) {
00203             p_buf[wk_idx++] = coller_pix[0];
00204             p_buf[wk_idx++] = coller_pix[1];
00205         }
00206     }
00207 }
00208 #endif
00209 
00210 static void DrawLine(int32_t x1,int32_t y1,int32_t  x2, int32_t y2,int drawpoint){
00211   int32_t dx=x2-x1;
00212   int32_t dy=y2-y1;
00213   int32_t sx=1;
00214   int32_t sy=1;
00215   int32_t i;
00216   int32_t de;
00217 
00218   if(dx<0){
00219     dx *= -1;
00220     sx *= -1;
00221   }
00222 
00223   if(dy<0){
00224     dy*=-1;
00225     sy*=-1;
00226   }
00227   draw_touch_pos(user_frame_buffer1,clr,drawpoint,x1,y1);
00228 
00229   if(dx>dy){
00230       for(i=dx,de=i/2;i;i--){
00231         x1+=sx;
00232         de+=dy;
00233         if(de>dx){
00234           de-=dx;
00235           y1+=sy;
00236         }
00237         draw_touch_pos(user_frame_buffer1,clr,drawpoint,x1,y1);
00238       }
00239     }else{
00240       for(i=dy,de=i/2;i;i--){
00241         y1+=sy;
00242         de+=dx;
00243         if(de>dy){
00244           de-=dy;
00245           x1+=sx;
00246         }
00247         draw_touch_pos(user_frame_buffer1,clr,drawpoint,x1,y1);
00248       }
00249     }
00250 }
00251 
00252 void skip_btn_fall0(void){
00253   btndownflg=true;//ボタンおした
00254 }
00255 
00256 void skip_btn_fall1(void){
00257   clr=(clr+1)%2;  //消しゴム(黒色)と青色色分け
00258    if((layer2flg==1 && btndownflg==false)){
00259       layer2flg=0;
00260     }else{
00261       layer2flg=1;//非表示
00262     }
00263 }
00264 
00265 void skip_btn_rise0(void){
00266   btndownflg=false;//ボタンはなれた
00267 }
00268 
00269 static void main_task(void) {
00270     cv::Mat prev_image;
00271     cv::Mat curr_image;
00272     std::vector<cv::Point2f> prev_pts;
00273     std::vector<cv::Point2f> curr_pts;
00274     cv::Point2f point;
00275     int16_t  x = 0;
00276     int16_t  y = 0;
00277 
00278     EasyAttach_Init(Display);
00279     Start_Video_Camera();
00280 #if MBED_CONF_APP_LCD
00281     Start_LCD_Display();
00282 #endif
00283 
00284 #if STRING_DISP_TEST
00285     //string
00286     Thread stringTask;
00287     stringTask.start(callback(string_task));
00288 #endif // STRING_DISP_TEST
00289 
00290     // Initialization of optical flow
00291     point.y = (VIDEO_PIXEL_VW / 2) + (PLOT_INTERVAL * 1);
00292     for (int32_t i = 0; i < 3; i++) {
00293         point.x = (VIDEO_PIXEL_HW / 2) - (PLOT_INTERVAL * 1);
00294         for (int32_t j = 0; j < 3; j++) {
00295             prev_pts.push_back(point);
00296             point.x += PLOT_INTERVAL;
00297         }
00298         point.y -= PLOT_INTERVAL;
00299     }
00300     skip_btn0.fall(&skip_btn_fall0);
00301     skip_btn1.fall(&skip_btn_fall1);
00302     skip_btn0.rise(&skip_btn_rise0); //tuika ボタンを離したときに関数を呼び出す
00303 
00304 #if MBED_CONF_APP_LCD
00305     int16_t posx=LCD_PIXEL_WIDTH/2;
00306     int16_t posy=LCD_PIXEL_HEIGHT/2;
00307     int16_t prex=0;
00308     int16_t prey=0;
00309     int16_t akax=0;
00310     int16_t akay=0;
00311 
00312     while (1) {
00313         // Wait for image input
00314         wait_new_image();
00315 
00316         // Convert from YUV422 to grayscale
00317         cv::Mat img_yuv(VIDEO_PIXEL_VW, VIDEO_PIXEL_HW, CV_8UC2, user_frame_buffer0);
00318         cv::cvtColor(img_yuv, curr_image, cv::COLOR_YUV2GRAY_YUY2);
00319 
00320         point = cv::Point2f(0, 0);
00321         if ((!curr_image.empty()) && (!prev_image.empty())) {
00322             // Optical flow
00323             std::vector<uchar> status;
00324             std::vector<float> err;
00325             cv::calcOpticalFlowPyrLK(prev_image, curr_image, prev_pts, curr_pts, status, err, cv::Size(21, 21), 0);
00326 
00327             // Setting movement distance of feature point
00328             std::vector<cv::Scalar> samples;
00329             for (size_t i = 0; i < (size_t)status.size(); i++) {
00330                 if (status[i]) {
00331                     cv::Point2f vec = curr_pts[i] - prev_pts[i];
00332                     cv::Scalar sample = cv::Scalar(vec.x, vec.y);
00333                     samples.push_back(sample);
00334                 }
00335             }
00336 
00337             // Mean and standard deviation
00338             if (samples.size() >= 6) {
00339                 cv::Scalar mean;
00340                 cv::Scalar stddev;
00341                 cv::meanStdDev((cv::InputArray)samples, mean, stddev);
00342                 //printf("%d,  stddev=%lf, %lf\r\n", samples.size(), stddev[0], stddev[1]);  // for debug
00343                 if ((stddev[0] < 10.0) && (stddev[1] < 10.0)) {
00344                     point.x = mean[0];
00345                     point.y = mean[1];
00346                 }
00347             }
00348         }
00349         cv::swap(prev_image, curr_image);
00350 
00351         x = (int16_t)(point.x * DIST_SCALE_FACTOR_X) *- 1 * 0.8;
00352         y = (int16_t)(point.y * DIST_SCALE_FACTOR_Y) * -1 * 0.8;
00353 
00354         if(btndownflg==true){
00355           //xとyは移動量なので、現在地を算出する
00356           //その前に現在地を保存
00357           prex=posx;//移動前
00358           prey=posy;//移動前
00359           posx+=x;//移動後
00360           posy+=y;//移動後
00361         }
00362         //displayの外にはみでていたらdisplayの枠に値を矯正
00363         posx=RangeCorr(posx,(int)LCD_PIXEL_WIDTH,0);
00364         posy=RangeCorr(posy,(int)LCD_PIXEL_HEIGHT,0);
00365 
00366 #endif
00367         if ((x != 0) || (y != 0)) {
00368             led1 = 1;
00369             //printf("x=%d, y=%d\r\n", x, y);  // for debug
00370 #if MBED_CONF_APP_LCD
00371           if(btndownflg==true){//ub0のボタンが奇数回(1,,3, 5,・・・)押下されたら、線を描画する。(on,offスイッチ)
00372             if(clr==1){
00373              //円を描画して消す
00374              draw_touch_pos(user_frame_buffer1,clr,ERASER_POINT,prex,prey); //前の座標を消去
00375              DrawLine(prex,prey,posx,posy,ERASER_POINT);
00376              draw_touch_pos(user_frame_buffer1,2,ERASER_POINT,posx,posy); //赤いカーソルの描画
00377              akax=posx;
00378              akay=posy;
00379 
00380              kesiflg=1;//消しゴムモードになりました的な
00381 
00382            }else{
00383                if(kesiflg==1){//消しゴムモード→ペンモードに変わったとき、カーソルがディスプレイに残るので黒で上塗りして消す
00384                  draw_touch_pos(user_frame_buffer1,1,ERASER_POINT,akax,akay);
00385                  kesiflg=0;
00386                }
00387              draw_touch_pos(user_frame_buffer1,clr/*黒*/,DRAW_POINT,posx,posy); //ペン
00388              DrawLine(prex,prey,posx,posy,DRAW_POINT);
00389            }
00390          }/*else if(kesiflg==1){//消しゴムモードでUserBottun0を押すとカーソルが残ってしまうので、黒を上塗りして消す
00391            draw_touch_pos(user_frame_buffer1,1,ERASER_POINT,akax,akay);
00392            kesiflg=0;
00393          }*/
00394 
00395 
00396 #endif
00397         } else {
00398             led1 = 0;
00399         }
00400     }
00401 }
00402 
00403 #if MBED_CONF_APP_LCD
00404 //範囲の修正
00405 int16_t RangeCorr(int16_t target ,int16_t uplimit,int16_t lowlimit){
00406   if(target>=lowlimit &&  target<=uplimit){ //もし範囲内だったら
00407     return target;//そのまま返す
00408   }else if(target>uplimit){ //上限より値が大きかったら
00409     return uplimit; //上限の値を返す
00410   }else{ //下限より小さかったら
00411     return lowlimit; //下限の値を返す
00412   }
00413 }
00414 #endif
00415 
00416 
00417 uint8_t get_random(void){
00418     size_t olen;
00419     uint8_t data;
00420     trng_t trng_obj;
00421     static bool init_flg = false;
00422 
00423     trng_init(&trng_obj);
00424     if (init_flg == false) {
00425         init_flg = true;
00426         trng_get_bytes(&trng_obj, &data, 1, &olen);
00427     }
00428     trng_get_bytes(&trng_obj, &data, 1, &olen);
00429     trng_free(&trng_obj);
00430    return data;
00431 }
00432 
00433 int main(void) {
00434     mainTask.start(callback(main_task));
00435     mainTask.join();
00436 
00437 }
00438