CQ出版 Interface記事用サンプル。 トラ技カメラ+FIFOからデータを得て、 エリア判定後、デバイスに保存

Dependencies:   SDFileSystem mbed

main.cpp

Committer:
TETSUYA
Date:
2014-02-04
Revision:
4:ed062dc75c52
Parent:
3:8d5594ce5b00

File content as of revision 4:ed062dc75c52:

/* 
Toragi-CCD-Cam OV7670andFIFO sample use driver

Sadaei Osakabe ( http://mbed.org/users/diasea/ )
  http://mbed.org/users/diasea/code/OV7670_with_AL422B_Color_Size_test/

SDFileSystem
http://mbed.org/users/mbed_official/code/SDFileSystem/docs/tip/

mbed_debug.h
https://github.com/adamgreen/SmoothieTest/blob/master/mbed/src/capi/mbed_debug.h
*/
#include "mbed.h"
#include "SDFileSystem.h"
#include <string.h>
#include <math.h>
#include <algorithm>
#include "ov7670.h"


#define QQVGA
#ifdef QQVGA
# define SIZEX (160)
# define SIZEY (120)
#else
# define SIZEX (320)
# define SIZEY (240)
#endif

#define COLORS 8     // 8bit colors
//#define COLORS 24    // 24bit colors

int create_header(FILE *fp, int width, int height) ;

#define FILEHEADERSIZE 14                   //ファイルヘッダのサイズ
#define INFOHEADERSIZE 40                   //情報ヘッダのサイズ
#define HEADERSIZE (FILEHEADERSIZE+INFOHEADERSIZE)


OV7670 camera(
    p28,p27,       // SDA,SCL(I2C / SCCB)
    p25,p26,p29,   // VSYNC,HREF,WEN(FIFO)
    p24,p23,p22,p21,p20,p19,p18,p17, // D7-D0
    p5,p6,p7) ; // RRST,OE,RCLK

 

SDFileSystem sd(p11, p12, p13, p14, "sd"); // mosi, miso, sclk, cs

LocalFileSystem local("local");
BusOut myleds(LED1, LED2, LED3, LED4);
 
Serial pc(USBTX,USBRX) ;

int sizex = 0;
int sizey = 0;
int FileNo = 0;

#define AREA_X 32
#define AREA_Y 24
#define AREA_DIV_X 5
#define AREA_DIV_Y 5
//#define AREA_THRESH  12000
#define AREA_THRESH  5000


char canvas[SIZEX][SIZEY] ; //18.5KB  [0]gray [1]Median
signed short  AreaDiff[2][AREA_DIV_X][AREA_DIV_Y];   // 5x5 Area = 32x24dot Each Block
int face_bank = 0;
int  Dbmode = 0;    
void MedianFilter(void);
void SaveBMP(int flag);
void SearchNewFileNo();


int main() {
    char color_format = 0;
    char c;
    int d1,d2 ;
    //int mx, pixel , i;
    int pixel ;
    int pixc,  pixelg;
    int sort[3];    
    int ay = 0;
    //char UseMedian = 0;

    memset( AreaDiff, '\0', sizeof(AreaDiff));

    pc.baud(115200);
//RESJMP:
    //pc.printf("Camera resetting..\r\n");
    camera.Reset();

    //pc.printf("Before Init...\r\n");
    //camera.PrintRegister();
    switch( color_format ){
    case '1':   
        camera.InitRGB444(); 
        break;
    case '2':   
        camera.InitRGB555(); 
        break;
    default:
        camera.InitRGB565(); 
        break;
    }
    
    //sizex = 160;
    //sizey = 120;
    camera.InitQQVGA();

    camera.InitForFIFOWriteReset();
    camera.InitDefaultReg(true, true);  // flipv/flipH

    //pc.printf("After Init...\r\n");
    //camera.PrintRegister();
    SearchNewFileNo();


    // CAPTURE and SEND LOOP
    while(1)
    {
        memset( &AreaDiff[face_bank], '\0', sizeof(AreaDiff[face_bank]));
        if ( Dbmode ){
            pc.printf("Debug Mode [d][s]  Any Charactor is Capture Start!  \r\n") ;
            while(!pc.readable()) ;
            c = pc.getc() ;
            /*
            if (( c == '1' )|| ( c == '2' )||( c == '3' )){
                color_format = c;
                goto RESJMP;
            }else if ( ( c== 'm')||( c== 'M')) {
                    UseMedian = 1;
                    continue;
            }else if ( ( c== 'n')||( c== 'N')) {
                    UseMedian = 0;
                    continue;
            }else  
            */
            if (( c == 'd' )|| ( c == 'D' )){
                    Dbmode = 0;     // GO FreeRun
                    continue;
            }else if ( ( c== 's')||( c== 'S')) {
                    SaveBMP(COLORS);
                    continue;
            }
        }else{
            if ( pc.readable()) {
                c = pc.getc() ;
                if (( c == 'd' )|| ( c == 'D' )){
                    Dbmode = 1;     // GO DEBUGmode
                    continue;
                } 
                /*
                else if ( ( c== 'm')||( c== 'M')) {
                    UseMedian = 1;
                    continue;
                }else if ( ( c== 'n')||( c== 'N')) {
                    UseMedian = 0;
                    continue;
                }
                */
            }
            pc.printf(" \r\n") ;
        }
        camera.CaptureNext();   // sample start!
        while(camera.CaptureDone() == false);
        camera.ReadStart();
        pixc = 0;
        ay = 0;
        for (int y = 0;y < SIZEY;y++) {
            ay = y / AREA_Y;    
            for (int x = 0;x < SIZEX;x++) {
                d1 = camera.ReadOneByte() ; // upper nibble is XXX , lower nibble is B
                d2 = camera.ReadOneByte() ; // upper nibble is G   , lower nibble is R
                pixel = ((unsigned int)d2 << 8) + ((unsigned int)d1 & 0xff);
                
                // Make GrayScale
                // make 6bit Code on Each Color
                sort[0] = ((pixel >> 11) & 0x1f)<<1;    // r
                sort[1] = ((pixel >>  5) & 0x3f);       // g
                sort[2] = ((pixel      ) & 0x1f)<<1;    // b
                
                int max = 0, min = 0xffff;
                for (int i=0;i<3;i++){
                    if (sort[i] > max) max = sort[i];
                    if (sort[i] < min) min = sort[i];
                }
                int gray = ((max + min) / 2) ;  
                
                pixelg = ((gray>>1)<<11) + (gray<<5) + (gray>>1);
                pixel = pixelg;
                canvas[x][y] = (char)( gray ) & 0x3f;    // 6bit gray scale
                
                // Make Difference AreaData
                AreaDiff[face_bank][x/AREA_X][ay] += ( gray  );    // 6bit scaler! 
                
                if ( Dbmode ){
                    // send <CRLF> and Count on each 16dot.
                    if ( !(x%16) ){
                        pc.printf("\r\n%04x: ",pixc ) ;
                        pixc +=16;
                    }
                    pc.printf("%04x ",pixel) ;
                }
            }
        }
        camera.ReadStop();
        /*
        if ( UseMedian ){
            MedianFilter();            
        }
        */
        
        // Difference Check!!
        pc.printf("\r\n" ) ;
        
        int err_c=0;
        int backArea = ( face_bank + 1 )&0x01;
        for (int y = 0; y < AREA_DIV_Y; y++) {
            if ( Dbmode ) pc.printf("Diff: " ) ;

            for (int x = 0; x < AREA_DIV_X; x++) {
                int dif = abs( AreaDiff[backArea][x][y] - AreaDiff[face_bank][x][y] );
                if (dif >= AREA_THRESH) {
                    err_c++;        // Error Count

                    if ( Dbmode ) pc.printf("X%6d  " , dif) ;
                }else{
                    if ( Dbmode ) pc.printf("O%6d  " , dif) ;
                }
            }
            if ( Dbmode ) {
                pc.printf("                                                  " ) ;
                pc.printf("                                             \r\n" ) ;
            }
        }
        int led_s =0;
        switch ( err_c ){
        case 1:
            led_s =1;
            break;
        case 2:
            led_s =3;
            break;
        case 3:
            led_s =7;
            break;
        default:
            if ( err_c >= 3) {
                led_s =7;
            }else{
                led_s =0;
            }
            break;
        } 

        led_s |=  ( face_bank )? 0x08 : 0x00 ;
        myleds = led_s ;  
        if ( err_c >= 3 ){
            //pc.printf("\r\n") ;
            if ( Dbmode ){
                pixc = 0;
                for (int y = 0;y < SIZEY;y++) {
                    for (int x = 0;x < SIZEX;x++) {
                        char gray = 0;
                        gray = canvas[x][y];
                        pixel = ((gray>>1)<<11) + (gray<<5) + (gray>>1);
    
                        // send <CRLF> and Count on each 16dot.
                        if ( !(x%16) ){
                            pc.printf("\r\n%04x: ",pixc ) ;
                            pixc +=16;
                        }
                        pc.printf("%04x ",pixel) ;
                    }
                }
            }
            SaveBMP(COLORS);
            
        }        
        face_bank++;
        face_bank&=0x01;


        //pc.printf("\r\n") ;
    }
}

void MedianFilter(void)
{
    int sortM[9] = { 0 };
    int p;
    int ay;
    
    // Median Filter
    memset( &AreaDiff[face_bank], '\0', sizeof(AreaDiff[face_bank]));
    ay = 0;
    for (int y = 1;y < SIZEY-1;y++) {
        for (int x = 1;x < SIZEX-1;x++) {
            p=0;

            // Get Around Pixels
            for (int k = -1; k < 2; k++) {
                for (int j = -1; j < 2; j++) {
                    sortM[p++] = canvas[x+j][y+k];   //grayscale data
                }
            }
            // sort now...
            for (int k = 0; k < 8; k++){
                for (int j = 8; j > k; j--) {
                    if (sortM[j] < sortM[j - 1]) {
                        int dmy = sortM[j];
                        sortM[j] = sortM[j - 1];
                        sortM[j - 1] = dmy; 
                    }
                }
            }

            canvas[x][y] = sortM[4]; // Center Data!
            AreaDiff[face_bank][x/AREA_X][ay] += ( canvas[x][y] );    // 6bit scaler! 
        }            
    }
}

char *filebase =  "/local/Bmap";
//char *filebase =  "/sd/Bmap";

void SearchNewFileNo()
{
    FILE *fp;
    char filename[30] ;
    while( 1 ){    
        sprintf( filename, "%s%04d.bmp", filebase , FileNo);
        if((fp = fopen(filename, "rb")) == NULL){
            pc.printf("%s is not Exist.", filename);
            return ;
        }else{
            pc.printf("%s is Exist. Increment no...", filename);
            fclose(fp);
            FileNo++;
        }
    }
    
    
    
}

//flag 24: 24bit Clolr   8:8itGrayScale
void SaveBMP(int flag)
{
    unsigned char gray8;
    unsigned char bmp_line_data[SIZEX*3]; //画像1行分のRGB情報を格納する
    unsigned char RGBQUAD[4]; //Palette Data
    int back ;
    FILE *fp;
    char filename[30] ;
    
    sprintf( filename, "%s%04d.bmp", filebase , FileNo);
    FileNo++;
    back = myleds;
    
    myleds = 0xff;
    if((fp = fopen(filename, "wb")) == NULL){
        pc.printf("Error: %s could not open.", filename);
        return ;
    }

    // Make BITMAPHEADER to FileHead.
    create_header(fp, SIZEX, SIZEY);
    
    if ( flag==8 ){
        // if 8bit Gray Scale , Make Palette Data
        for (int i=0;i<256;i++){
            RGBQUAD[0] = i;    // 
            RGBQUAD[1] = i;
            RGBQUAD[2] = i;
            RGBQUAD[3] = 0;
            fwrite(RGBQUAD, sizeof(RGBQUAD), 1, fp);
        }
    }
    
    for (int y=0; y<SIZEY; y++) {
        if ( flag==24 ){
            for (int x=0; x<SIZEX; x++) {
                // RGB888
                gray8 = (unsigned char)(canvas[x][y] << 2);   //grayscale data 6bit
    
                bmp_line_data[x*3]     = (unsigned char)gray8;  // b
                bmp_line_data[x*3 + 1] = (unsigned char)gray8;  // g
                bmp_line_data[x*3 + 2] = (unsigned char)gray8;  // r
            }
            fwrite(bmp_line_data, sizeof(unsigned char), sizeof(bmp_line_data), fp);
        }else{
            // GrayScale
            for (int x=0; x<SIZEX; x++) {
                gray8 = (unsigned char)(canvas[x][y] << 2);   //grayscale data 6bit
                fwrite(&gray8 , 1, 1, fp);
            }
        }
    }
    fclose(fp);
    
    myleds = back ;
}
    

int create_header(FILE *fp, int width, int height) {
    int real_width;
    unsigned char header_buf[HEADERSIZE]; //ヘッダを格納する
    unsigned int file_size;
    unsigned int offset_to_data;
    unsigned long info_header_size;
    unsigned int planes;
    unsigned int color;
    unsigned long compress;
    unsigned long data_size;
    long xppm;
    long yppm;

    real_width = width*3 + width%4;

    //ここからヘッダ作成
    file_size = height * real_width + HEADERSIZE;

    offset_to_data = HEADERSIZE;
    if ( COLORS == 8 ) {
        offset_to_data += 256 * 4;
    }

    info_header_size = INFOHEADERSIZE;
    planes = 1;
    color =  COLORS;    // 24;
    compress = 0;
    data_size = height * real_width;
    xppm = 1;
    yppm = 1;

    header_buf[0] = 'B';
    header_buf[1] = 'M';
    memcpy(header_buf + 2, &file_size, sizeof(file_size));
    header_buf[6] = 0;
    header_buf[7] = 0;
    header_buf[8] = 0;
    header_buf[9] = 0;
    memcpy(header_buf + 10, &offset_to_data, sizeof(offset_to_data));
    memcpy(header_buf + 14, &info_header_size, sizeof(info_header_size));
    memcpy(header_buf + 18, &width, sizeof(width));
    height = height * -1; // データ格納順が逆なので、高さをマイナスとしている
    memcpy(header_buf + 22, &height, sizeof(height));
    memcpy(header_buf + 26, &planes, sizeof(planes));
    memcpy(header_buf + 28, &color, sizeof(color));
    memcpy(header_buf + 30, &compress, sizeof(compress));
    memcpy(header_buf + 34, &data_size, sizeof(data_size));
    memcpy(header_buf + 38, &xppm, sizeof(xppm));
    memcpy(header_buf + 42, &yppm, sizeof(yppm));
    header_buf[46] = 0;     // Palette Color (long)
    header_buf[47] = 0;
    header_buf[48] = 0;
    header_buf[49] = 0;
    header_buf[50] = 0;     // Important Color (long)
    header_buf[51] = 0;
    header_buf[52] = 0;
    header_buf[53] = 0;

    //ヘッダの書き込み
    fwrite(header_buf, sizeof(unsigned char), HEADERSIZE, fp);

    return 0;
}