きょうはCMOSカメラのネタです。そういえば、トラ技来月号(2009年7月号)はCMOSイメージ・センサの特集のようですね。
これまでカメラで撮影した画像をLCDで確認することを中心に実験をしてきました。しかしながら、LCDの画素数がQVGA(320X240)であることから、カメラが本来撮影できる画像を縮小して表示しているというものでした。そこで、今度はカメラが撮影した元画像をPCに持ってきて確認する実験をしてみました。
AT91SAM9260のISIにはCodec pathと呼ばれる機能が用意されており、ISI_CR1レジスタを操作するだけで、ISI_CDBA (ISI Codec DMA Base)レジスタで指定されるメモリアドレス以降にカメラで撮像したデータを自動的に格納することができます。したがって、このデータを吸い出してやれば元画像を確認することができます。あいからわらずSDカードが使えないままなので、いったんボードをリセットしてSAM-BAを使ってSDRAMからデータを読み出してPCにもってくる方法でVGAで撮影された画像を確認することにしました。
カメラから送出される画像データの形式はYCbCr 4:2:2の形式を使っています。現在使っているカメラの設定だと、メモリ上には次のように画像データが展開されて入ってきます。
この形式では4バイト分の領域を使って2つの画素のデータを表現しています。Y(i)とY(i+1)が2つの画素それぞれの輝度を表現していますが、色差情報であるCb(i)とCr(i)については2つの画素に共通のデータを適用して、データ量を減らしています。VGA画像であれば、640*480*2 = 614,400バイトのデータとなります。
このままの形式では、パソコン上では表示できないので、変換が必要です。まず、それぞれの画素のデータを明示的に表現してYCbCrの順番に並び換えてやれば、次のように各画素には24bitのデータが使われ、2画素では6バイトのデータとなります。
このデータを色空間の変換式を適用してRGBデータに変換してやり、適切なヘッダを付与してやれば、RGB24bitのBMPファイルを作成できます。まずは試しに色空間の変換をおこなわずに無理やりYCbCrをRGBに読み替えてBMPファイルを作成してみたのが、この↓画像です。(ブログにアップするために、BMPからさらにPNGに変換してあります。)
オォッ! 色がオカシイのはあたりまえなのですが、どんな画像かはそれなりにわかるもんなんですねぇ。
あとは色空間の変換をおこなえばまっとうな色になるわけですが、BMPファイルを作成してもデータ量としては画素あたり24bit(3バイト)必要なので640*480*3=921,600バイトも必要になってしまいます。そこで、どうせならJPEGに変換してみようと考え、Linux上でJPEGファイルに変換するプログラムを作成することにしました。JPEGファイルを作成するにはIJGのlibjpegが使えます。そうは言っても、名前は知っていても実際には使ったこともないライブラリなので、ドキュメントにざっと目をとおすとともにこのサイトの使い方説明を参考にさせていただきました。みなさんRGBのビットマップデータをJPEGに圧縮する場合の例を説明されているようなのですが、libjpegでは入力データの色空間形式を指定することができるので、YCbCr形式のデータからJPEGファイルを作成することも可能です。具体的には、
と指定し、上述のように画素あたり3バイトに並び換えたデータを jpeg_write_scanlines() に渡してやればいいだけでした。こうして変換してできたJPEG画像がこれ↓です。サイズは229,817バイトになりました。
今回の画像形式変換処理は、全てLinux PC上でおこなっています。libjpegの変換処理は整数演算でおこなえるようにコードが書かれているようなので、この変換処理をARM9ボード上にもっていくこともできそうです。そうすれば、撮影した画像をJPEGファイルとして保存でき、デジカメごっこができることになります。ぜひとも試してみたいのですが、そのためにはSDカードが使えなくなってしまっている問題をなんとか解決しないと。。
これまでカメラで撮影した画像をLCDで確認することを中心に実験をしてきました。しかしながら、LCDの画素数がQVGA(320X240)であることから、カメラが本来撮影できる画像を縮小して表示しているというものでした。そこで、今度はカメラが撮影した元画像をPCに持ってきて確認する実験をしてみました。
AT91SAM9260のISIにはCodec pathと呼ばれる機能が用意されており、ISI_CR1レジスタを操作するだけで、ISI_CDBA (ISI Codec DMA Base)レジスタで指定されるメモリアドレス以降にカメラで撮像したデータを自動的に格納することができます。したがって、このデータを吸い出してやれば元画像を確認することができます。あいからわらずSDカードが使えないままなので、いったんボードをリセットしてSAM-BAを使ってSDRAMからデータを読み出してPCにもってくる方法でVGAで撮影された画像を確認することにしました。
カメラから送出される画像データの形式はYCbCr 4:2:2の形式を使っています。現在使っているカメラの設定だと、メモリ上には次のように画像データが展開されて入ってきます。
n番地 | Cr(i) |
n+1番地 | Y(i) |
n+2番地 | Cb(i) |
n+3番地 | Y(i+1) |
この形式では4バイト分の領域を使って2つの画素のデータを表現しています。Y(i)とY(i+1)が2つの画素それぞれの輝度を表現していますが、色差情報であるCb(i)とCr(i)については2つの画素に共通のデータを適用して、データ量を減らしています。VGA画像であれば、640*480*2 = 614,400バイトのデータとなります。
このままの形式では、パソコン上では表示できないので、変換が必要です。まず、それぞれの画素のデータを明示的に表現してYCbCrの順番に並び換えてやれば、次のように各画素には24bitのデータが使われ、2画素では6バイトのデータとなります。
n番地 | Y(i) |
n+1番地 | Cb(i) |
n+2番地 | Cr(i) |
n+3番地 | Y(i+1) |
n+4番地 | Cb(i) |
n+5番地 | Cr(i) |
このデータを色空間の変換式を適用してRGBデータに変換してやり、適切なヘッダを付与してやれば、RGB24bitのBMPファイルを作成できます。まずは試しに色空間の変換をおこなわずに無理やりYCbCrをRGBに読み替えてBMPファイルを作成してみたのが、この↓画像です。(ブログにアップするために、BMPからさらにPNGに変換してあります。)
オォッ! 色がオカシイのはあたりまえなのですが、どんな画像かはそれなりにわかるもんなんですねぇ。
あとは色空間の変換をおこなえばまっとうな色になるわけですが、BMPファイルを作成してもデータ量としては画素あたり24bit(3バイト)必要なので640*480*3=921,600バイトも必要になってしまいます。そこで、どうせならJPEGに変換してみようと考え、Linux上でJPEGファイルに変換するプログラムを作成することにしました。JPEGファイルを作成するにはIJGのlibjpegが使えます。そうは言っても、名前は知っていても実際には使ったこともないライブラリなので、ドキュメントにざっと目をとおすとともにこのサイトの使い方説明を参考にさせていただきました。みなさんRGBのビットマップデータをJPEGに圧縮する場合の例を説明されているようなのですが、libjpegでは入力データの色空間形式を指定することができるので、YCbCr形式のデータからJPEGファイルを作成することも可能です。具体的には、
input_components = 3; in_color_space = JCS_YCbCr;
と指定し、上述のように画素あたり3バイトに並び換えたデータを jpeg_write_scanlines() に渡してやればいいだけでした。こうして変換してできたJPEG画像がこれ↓です。サイズは229,817バイトになりました。
今回の画像形式変換処理は、全てLinux PC上でおこなっています。libjpegの変換処理は整数演算でおこなえるようにコードが書かれているようなので、この変換処理をARM9ボード上にもっていくこともできそうです。そうすれば、撮影した画像をJPEGファイルとして保存でき、デジカメごっこができることになります。ぜひとも試してみたいのですが、そのためにはSDカードが使えなくなってしまっている問題をなんとか解決しないと。。