TOP > 電子部品 > カメラ(OV7670) > ソフト
(2020.12.19 作成)
このページでは安価なカメラモジュールを使用するために作成したソフトウェアについて説明してみたいと思います。ソフト自体はこちらでダウンロードすることができます。
ただ上記のページでも説明した通りコードのすべてを説明することはできないので、もし参考にされる方がおられれば頑張って解読していただければと思います。
このページで公開しているFWはFIFOなしモジュールを使い、遅くても良いので640x480画素のRawデータをPCへ転送することが目的です。
また貧乏な管理人はマイコンも安価なSTM32F103C8T6基板を使用しています。このため複雑な処理はすべてPC側へお任せすることとしてマイコン基板側ではデータを転送する以外の処理は一切行っていません。
OV7670に供給するクロックはmin.10MHz, typ.24MHzです。24MHzを供給しても良いと思うのですが、あまり早くしても意味がないので下限の10MHzを狙って設定しました。具体的にはF103のタイマを使用してPWMモードでメインクロック72MHzを7分周して72/7=10.3MHzを入力としています。
またPCへのデータ送信はUSBのCDC通信を使用したのですが、F103のUSBはFull speedまで対応なので12Mbpsが最大速度です。画像転送はここがボトルネックとなり画像のフレームレートが決まっています。
具体的に言うと画像データサイズは 640pixel x 480pixel x 1byte= 300kByteなのですが、 USBは12Mbps=1536kByte/sなので最大でも5fps程度が限界です。
しかも実際にはPCに接続されているUSB機器はこれだけではありませんし、オーバーヘッドもあるので実際にはここまでの速度は出ません。
画像の搬出速度はClock Pre-scalar(レジスタCLKRC[5:0])で設定できるのですが、管理人の環境ではクロックを1/15(レジスタ値で7)に落とし、2.56fpsとすることで転送することができました。
管理人の場合VGAのRAWデータを送ろうとしたので2.5fpsなのですが、画像サイズを小さくするなど画像フォーマットを変更すれば60pfsのいわゆる普通の動画も送れると思います。
おそらく画像データの取得法は一般的なものだと思うのですが、VSYNCでフレームデータの始まり、HSYNCでラインデータの始まりを表し、画像データの周囲にブランキング期間があるものです。おそらくグーグル先生に聞けば詳しく解説しているサイト様があると思います。
私が作成したプログラムはV/H SYNCとPCLKそれぞれで割り込みを発生させてデータを同期させています。詳しくはソースコードを見ていただければと思います。
取得したデータはマイコンのメモリ内のラインバッファにデータを蓄積し、満杯になったところでUSBでデータを送出しています。USBのオーバーヘッドを減らすためラインバッファはなるべく大きくとった方が良いのですが、F103のRAMは20kByteしかなく、またデータ蓄積用とUSB送信用の2面のバッファを持つ必要があるため結局12ライン分しかラインバッファを持てませんでした。これでもRAMの使用率は99.38%とほぼ使い切っています。
PCへのデータ送信は上記の通りUSB-CDCを使用しています。データを送るだけなのですが、2点ほど注意があります。
1つ目はUSBの割り込みの優先順位をVSYNC, HSYNC, PCLKの各割り込みよりも下げないとUSB通信のタイミングで画像データの欠損が発生します。
2つ目はラインバッファになるべく多くのメモリを割り当てたいため、USB用のバッファをなるべく小さくしています。具体的にはusbd_cdc_if.h/c内のUserTxBufferFSを使用せず、APP_RX_DATA_SIZEも使用する最小サイズ64byteまで小さくしています。
PCで受信したデータは何かの処理をして活用するわけですが、画像処理と言えばOpenCVが最適だと思います。以前一度PythonからOpenCVを使用したのですが、とても使いにくかったので今回はC++を使用しています。この際OpenCVの自家ビルドをやっており、こちらに紹介記事を書いているので興味があれば見てみてください。
さてC++とOpenCVで処理を行うことにしたのはいいのですが、マイコンからUSB通信でデータを受け取る際には何らかのGUIがあった方が使いやすいです。C++/CLIという手もあったのですが、とても使いにくく、また最近は非推奨のようです。Qtを使うという手もあるとは思うのですが、ずいぶんと面倒な気がしました。
というわけで今回はC++でOpenCVをDLL化し、C#でGUIのフロントエンドを作成することにしました。
で、最終的に出来上がったGUIが右のようなコントロールソフトです。ソースコードを見ていただければわかると思いますが、単にOpenCVとマイコンの橋渡しをしているだけで何も処理は行っていません。
ガンマ測定用にプロセス間通信(IPC)のコードが入っているので少し見づらいかもしれませんが、C#側は特筆すべき内容は特にないです。
一方C++の注意点は一つあります。マイコンから送られてきたデータはイメージセンサーのBayer配列のデータになっています。このBayer配列からRGB画像を生成するためにOpenCVのcvtColor関数を使用していますが、その際の引数としてCOLOR_BayerGR2BGRを設定しています。しかしこれはもしかしたらCOLOR_BayerRG2BGRが正解かもしれません。マイコンのクロックレジスタを遅くすると後者が正解になるので、もしかしたら最初の1pixelはデータを取りこぼしている可能性があります。
ところでC++のDLLを使用するのって面倒だった記憶があるのですが、C#からシームレスにデバッグ実行できるので意外と簡単なんだなという印象でした。
マイコンにせよPC側にせよ、作成したソフトについて覚えている範囲で書いてみたつもりですが、説明が十分足りているとは全く思えません。もしソースコードを読んでわからない点があれば下のコメント欄に入れていただければと思います。覚えている範囲で回答したいと思います。
今は覚えていますが、もう歳なのですぐに中身は忘れると思いますが、、