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を使わない場合は表示用のコードはコメントアウトしてください.
Diff: main.cpp
- Revision:
- 0:f31ceb6058cb
diff -r 000000000000 -r f31ceb6058cb main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Sep 24 20:44:56 2014 +0000 @@ -0,0 +1,304 @@ +/* + * 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 \ No newline at end of file