Sample code of section 3 in Nov 2014 issue of the Interface Magazine, published by CQ publishing in Japan. CQ出版社インターフェース誌 2014年11月号3章に掲載のサンプルコードです. FRDM-K64FにOV7670カメラを接続して映像を取得するとともに,簡単なフィルタ処理も施すサンプルです.このコードのうちカメラ制御部には,Sadaei Osakabe氏のコードを流用させていただいています.
Dependencies: SDFileSystem TextLCD mbed
このコードでは,Arduino用のLCDシールド(http://www.switch-science.com/catalog/724/)を接続することを想定しています.ただしLCDは必須ではないので,LCDを使わない場合は表示用のコードはコメントアウトしてください.
main.cpp
- Committer:
- smorioka
- Date:
- 2014-09-24
- Revision:
- 0:f31ceb6058cb
File content as of revision 0:f31ceb6058cb:
/* * Copyright (c) 2014, Sumio Morioka * All rights reserved. * * This source code was originally written by Dr.Sumio Morioka for use in the Nov 2014 issue of * "the Interface magazine", published by CQ publishing Co.Ltd in Japan (http://www.cqpub.co.jp). * The author has no responsibility on any results caused by using this code. * * - Distribution date of this code: Sep 24, 2014 * - Author: Dr.Sumio Morioka (http://www002.upp.so-net.ne.jp/morioka) * * * IMPORTANT NOTICE: * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mbed.h" #include "SDFileSystem.h" #include "TextLCD.h" #include "ov7670.h" DigitalOut led1(LED1), led2(LED2), led3(LED3); SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS TextLCD lcd(PTD3, PTD2, PTA2, PTB23, PTA1, PTB9); // Arduino LCD sheild; OV7670 camera( PTE25,PTE24, // SDA,SCL(I2C / SCCB) PTB2,PTB3,PTB10, // VSYNC,HREF,WEN(FIFO) PTC5,PTC7,PTC0,PTC9,PTC8,PTC1,PTB19,PTB18, // D7-D0 PTB11,PTC11,PTC10); // RRST,OE,RCLK Timer tmr; //#define QQVGA #define QVGA //#define VGA34 #ifdef QQVGA #define SIZEX 160 #define SIZEY 120 #endif #ifdef QVGA #define SIZEX 320 #define SIZEY 240 #endif #ifdef VGA34 #define SIZEX 480 #define SIZEY 360 #endif unsigned char image_buf_g[SIZEX * SIZEY * 3]; void cam_cap(void); void save_bmp(void); int memfree(void) { int ret = 1; while (1) { char *p = (char *)malloc(ret); if (p == NULL) break; free(p); ret++; } return (ret - 1); } int main() { led1 = 0; led2 = 0; led3 = 0; ///////////////////////////////////////// // init camera camera.WriteReg(0x12, 0x80); // com7; reset wait_ms(200); camera.InitDefaultReg(); // negate vsync camera.WriteReg(0x15, 0x02); // com10; negative vsync #ifdef QQVGA camera.InitQQVGA(); #endif #ifdef QVGA camera.InitQVGA(); #endif #ifdef VGA34 camera.InitVGA_3_4(); #endif // data format camera.WriteReg(0x12, 0x04 + 0); // com7 RGB (bit1...test pattern) camera.WriteReg(0x40, 0xD0); // com15 RGB565 camera.WriteReg(0x8c, 0x00); // RGB444 wait_ms(300); /////////////////////////////////////// // display free memory size int cur_mem = memfree(); lcd.locate(0, 0); lcd.printf("mem %d", cur_mem); /////////////////////////////////////// // capture tmr.reset(); tmr.start(); // timer cam_cap(); // capture photo tmr.stop(); // timer lcd.locate(0, 0); lcd.printf("cap %dms", tmr.read_ms()); //////////////////////////////////////// // apply filter tmr.reset(); tmr.start(); // timer { int kernel_size = 3; int kernel_dotnum = kernel_size * kernel_size; int kernel_halfsize = (kernel_size - 1) / 2; // calc average value for (int y = 0; y < SIZEY; y++) { int r_new, g_new, b_new; // scan for (int x = 0; x < SIZEX; x++) { int r, g, b; int acc_r = 0; int acc_g = 0; int acc_b = 0; for (int ky = 0; ky < kernel_size; ky++) { int ypos = y - kernel_halfsize + ky; if (ypos < 0 || ypos >= SIZEY) continue; for (int kx = 0; kx < kernel_size; kx++) { int xpos = x - kernel_halfsize + kx; if (xpos < 0 || xpos >= SIZEX) continue; b = image_buf_g[(ypos * SIZEX + xpos) * 3]; g = image_buf_g[(ypos * SIZEX + xpos) * 3 + 1]; r = image_buf_g[(ypos * SIZEX + xpos) * 3 + 2]; acc_r += r; acc_g += g; acc_b += b; } } r_new = (unsigned char)(acc_r / kernel_dotnum); g_new = (unsigned char)(acc_g / kernel_dotnum); b_new = (unsigned char)(acc_b / kernel_dotnum); image_buf_g[(y * SIZEX + x) * 3] = b_new; image_buf_g[(y * SIZEX + x) * 3 + 1] = g_new; image_buf_g[(y * SIZEX + x) * 3 + 2] = r_new; } } } tmr.stop(); // timer lcd.locate(0, 1); lcd.printf("flt %dms", tmr.read_ms()); //////////////////////////////////////// // save BMP tmr.reset(); tmr.start(); // timer save_bmp(); tmr.stop(); // timer // lcd.locate(0, 1); // lcd.printf("bmp %dms", tmr.read_ms()); ////////////////////////////////////////////////// // (stop) while (1) { led1 = 1; wait_ms(100); } } void save_bmp(void) { FILE *fp_bmp; unsigned char sort[3]; unsigned int buf_ptr = 0; led3 = 1; fp_bmp = fopen("/sd/cam.bmp", "wb"); ///////////////////////// // file header ///////////////////////// fprintf(fp_bmp, "BM"); int val = 14 + 40 + SIZEX * SIZEY * 3; // file size fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000); fprintf(fp_bmp, "%c%c%c%c%c%c%c%c", 0, 0, 0, 0, 0x36, 0, 0, 0); ///////////////////////// // information header ///////////////////////// fprintf(fp_bmp, "%c%c%c%c", 0x28, 0, 0, 0); // header size fprintf(fp_bmp, "%c%c%c%c", SIZEX % 0x100, SIZEX / 0x100, SIZEX / 0x10000, SIZEX / 0x1000000); fprintf(fp_bmp, "%c%c%c%c", SIZEY % 0x100, SIZEY / 0x100, SIZEY / 0x10000, SIZEY / 0x1000000); fprintf(fp_bmp, "%c%c", 1, 0); // # of plane fprintf(fp_bmp, "%c%c", 24, 0); // bit count fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); // compression val = SIZEX * SIZEY * 3; // data size fprintf(fp_bmp, "%c%c%c%c", val % 0x100, val / 0x100, val / 0x10000, val / 0x1000000); fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); fprintf(fp_bmp, "%c%c%c%c", 0, 0, 0, 0); for (int y = 0;y < SIZEY;y++) { for (int x = 0;x < SIZEX;x++) { sort[0] = image_buf_g[buf_ptr++]; sort[1] = image_buf_g[buf_ptr++]; sort[2] = image_buf_g[buf_ptr++]; fprintf(fp_bmp, "%c%c%c", sort[2], sort[1], sort[0]); // B,G,R } } fclose(fp_bmp); led3 = 0; } //void cam_cap(Arguments* input, Reply* output) void cam_cap(void) { unsigned int d1, d2; unsigned char sort[3]; unsigned int buf_ptr = 0; led2 = 1; camera.CaptureNext(); // sample start! while(camera.CaptureDone() == false) ; camera.ReadStart(); // reset pointer for (int y = 0;y < SIZEY;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 // RGB565 to RGB888 sort[0] = ((d1 & 0xF8) >> 3) << 3; // R sort[1] = ( ((d1 & 0x07) << 3) + ((d2 & 0xE0) >> 5) ) << 2; // G sort[2] = (d2 & 0x1F) << 3; // B image_buf_g[buf_ptr++] = sort[2]; image_buf_g[buf_ptr++] = sort[1]; image_buf_g[buf_ptr++] = sort[0]; } } camera.ReadStop(); led2 = 0; } // end of file