はじめに
ここでは、Remo購入者向けに、Remoで圧縮データの画像を取得し、動画風に表示する方法を紹介します。
※このページで紹介する内容はあくまでも一例です。個別の作成のご相談ご質問はお答えできませんのでご了承下さい。
※以下の情報は2009年11月現在のものです。ご注意ください。
Remoついてはこちらを参照願います。
圧縮データ解凍プログラムについて
圧縮データを解凍し、高速で動画風に表示させるプログラムはこちらです。VisualC#2008のプロジェクトをまるごと圧縮してます。
RemoView2.lzh
右クリックで対象を保存し、解凍してください。
Remoでは画像を圧縮するのに、少し理解が面倒な数学的計算を使っています。とにかく自分のプログラムに機能を組み込むだけでいい、という方も多いかと思いますので、ここではプログラムの概要と関数の使い方だけ説明します。
まず、自分のプロジェクトを作り、PictureBoxコンポーネントを貼り付けます。それを160x56のサイズに設定します。
RemoView2プロジェクトのForm1の中にプログラムが入ってます。この中のdispPicture3というメソッド(関数)がRemoの圧縮画像を展開してPictureBoxに表示するものです。これを自分のプロジェクトにコピーしてください。
引数には160x56サイズに設定したPictureBoxを指定します。たとえば、pictureBox1という名前でPictureBoxコンポーネントを作ったとしたら、
dispPicture3(pictureBox1);
のように実行すると、そのPictureBoxに画像が表示されます。
dispPicture3メソッドは、chkmとusConvというメソッドも使いますので、Form1の中からこれらを探して、その2つもコピーしてください。
以下、圧縮画像の展開方法について説明しますが、単に機能を使いたいだけ、という方は読まなくても結構だと思います。
データの圧縮方法について
本プログラムを作るにあたり、次の書籍を参考にしました。詳しいことはこちらを参照願います。
ディジタル画像処理の基礎と応用 酒井幸市著 CQ出版
これなら分かる応用数学教室 金谷健一著 共立出版
画像データの圧縮はいろいろな方法があります。有名なのはWebなどで使われているJPEGだと思います。JPEGの圧縮手順は
1)画像をいくつかのブロックにわける
2)ブロックを離散コサイン変換 −>画像を周波数成分に変換
3)量子化 −>データの解像度を下げる
4)ジグザグスキャン −>0が連続しそうな順番にならびかえる
5)可変長コードに変換 −>0が連続した場合は大きくデータ量が下がる方式に変換
となります。圧縮画像を戻すには、この逆の手順をふむと、ほぼ元の画像にもどります。
RemoでもJPEG風の手法を使っています。大きく違うのは、可変長コードを使っていないのと、計算結果の3/4を単純に捨てるという方法を取っています。Remoの手順は
1)ブロックにわける。
2)ブロックを離散コサイン変換。1ブロックは8x8=64バイト
3)量子化
4)ジグザグスキャン
5)低周波データの上位16バイトだけ抜き取る。高周波成分の48バイトは捨てる。
という流れになります。
1)ブロックにわける
Remoの画像は160x56です。よってYデータは20x7ブロックになります。
CrとCbは横方向のとなり同士を共有します(くわしくはView1のページ参照)ので、Yよりも横方向に1/2の量になります。よって10x7ブロックとなります。
2)離散コサイン変換
とりあえず輝度データだけで考えた方がわかりやすいので輝度について説明します。輝度値は画像の濃淡を表します。8ビット値なので値は0〜255になります。
画像データは数値の羅列ですが、この数値を線グラフにして波と考えます。
工業系の大学生又は卒業者なら、応用数学の講座でフーリエ展開を習ったかと思います。フーリエ展開を使うと複雑な波形を、簡単な三角関数の合成(足し算)で表現ます。これを応用したのが離散コサイン変換です。英語でDiscreat
Cosin TransferとなるのでDCTと略されます。
8x8の画像を縦方向と横方向にDCT計算すると、8x8の係数が結果として残ります。この64個の係数を使って、DCTを逆に計算する(逆DCT)と、ほぼ元の8x8の画像になります。
これでは全然圧縮されていない、と思うかもしれませんが、ここからがポイントです。
8x8の元画像をDCTして8x8の係数を得ましたが、これは元画像の周波数成分を表したもの(のようなもの)になります。係数の左上の値が低周波、右下にいくほど高周波成分の係数となっています。
自然界の画像は、隣同士の画素の値が大きく違う、ということはあまり無いので”低周波成分が多い”、といえます。ということは、高周波成分をいくらか削っても、逆DCTを行えばもとの画像に近いものが得られる可能性があります。
ためしに、8x8の元画像からDCTで得られた64個の係数の、後半1/4を削ってみる(削った部分は0を代入)と、逆DCTをした結果は少しボヤけた感じになります。同じように後半をどんどんけずると、どんどんボヤけます。先頭の1個だけになると、元画像の平均値一色の画面になります。
このようにしても画像は圧縮できますが、劣化が激しいのでその他の処理も行います。それが量子化とジグザグスキャンです。
3)量子化
画素の濃淡を8ビットで表してますが、人間の目はそれほど解像度はよくありません。たとえば、PC画面で濃度120と濃度121の濃さを見ても、普通の人なら見分けられないでしょう。ということで、DCTした結果を割り算して、値を減らします。このとき、高周波成分は重要ではないので大きな値で割ります。低周波に近いほど少ない値でわります。
どのような値でどの画素を割るか、ということが問題になりますが、これは何度もテストしてみて出すしかありません。Remoの場合は浅草ギ研でテストした結果を元に、割る率を決めています。これについてはプログラムのところに実際の値が記載されています。
4)ジグザグスキャン
量子化まで行うと、実はDCT結果の8x8の係数の左上から右下の中心線に大きな値が集中し、それ以外は0に近くなることが多いです。よって、左上から右下の中心線付近を抜き出します。
5)上位16バイトだけ抜き取る
最終意的にはRemoでは、中心線付近のデータから上位16バイトを抜いて、それを転送しています。PC側ではこの16バイトを使って8x8=64画素の画像を再生します。
ここではおおまかな流れを説明しました。詳細や実際の計算式などは書籍などを参照して下さい。実際のところ、私も作っている時は理解していたのですが、2ヶ月経過した今、式を見ても理解できません。質問等はご遠慮下さい。
実際のプログラム
ではプログラムを解説します。Form1の中にソースコードが入っています。
おおまかな流れとしては、チェックボックスにチェックを入れると、Timerが有効になり、Timerイベントで一定周期で圧縮画像を要求するコマンドを送信します。コマンド送信後はdispPicture3メソッド(関数)で画像をPictureBoxに表示します。
<値修正メソッド>
チェックボックスとタイマーのイベントはそんなに難しくないので、ソースを参照すれば大体わかると思います。以降、画像を表示する部分を説明します。
まず、画像を表示する計算で使う、値を修正するメソッドです。chkmはView1の例で説明しましたが、小数点演算をするときに値が8ビットの範囲を超える場合があるのでそれを修正するものです。
usConvですが、Yデータは単純な濃淡ですが、CrとCbは色”差”の情報でマイナスの値も8ビットで表しています。
8ビット値の0〜127はそのまま整数の0〜127に相当します。128〜255は−128〜−1になります。128は−128、255はー1になります。(−1に1を足すと0になる。255に1を足しても0になる。)
本当の値はマイナスも表しているのですが、送られてくるデータはbyteつまり符号なしの形式で受け取ってしまうので、これを符号付きのintに変換しています。
<手順>
次に心臓部のdispPicture3メソッドです。行200〜217、行576〜605の部分はView1と同じなので割愛します。
まず、データ量ですが、非圧縮のときはヘッダ4バイト+画像17920バイトが送られてきましたが、圧縮の場合はヘッダがありません。画像データは1/4になっていますので4480バイトのデータが送られてくることになります。
圧縮データは、まずYの20x7ブロック、次にCbの10x7ブロック、最後にCrの10x7ブロックの順に送られてきます。1ブロックは1/4に圧縮されているので16バイト、つまり始めにYデータが連続で2240バイト、次にCbが1120バイト、最後にCrが1120バイト送られてきます。
圧縮は
1)DCT
2)量子化
3)ジグザグスキャン
4)16バイト抜き取り
の順でしたので、画像に戻すには
1)16バイトセット
2)逆ジグザグスキャン
3)逆量子化
4)逆DCT
の順で行います。
計算用にバッファを用意したのが上の部分です。
<逆ジグザグスキャン>
ジグザグスキャンを逆に戻しているところです。Remo側ではこの逆の組み換えをしています。
<逆量子化>
データは16バイトですが、8x8の画面に直すので8x8=64の配列を用意します。Remo側ではデータを減らすために値を割っています(量子化)ので、ここでは逆の同じ値を掛けてもどします。このプログラムでは値を受け取っていないデータに大しても演算をしていますが、わかりやすいように64バイト分全部計算しています。この計算値は浅草ギ研で実際に実験しながら得たものです。(実験時にはデータを1/4に減らしていないので64個分の計算値がある。Remo側の都合で2の倍数になっている。)
途中省略...
<逆DCT>
DCTは8x8の元画像に対して8x8の係数を求めています。コサインを使うので本来は複雑で長い計算になるのですが、途中の計算をあらかじめさせておき、それを定数として計算に使っています。これでプログラムは単純かつ高速になります。途中の計算をあらかじめした結果を格納したものがmCos[?,?]です。これはコンストラクタ内で値を代入しています。この計算値は浅草ギ研がRemo用に行って調整したものなので、他への流用はご遠慮下さい。
ここで、Remo内で行った計算の逆を行うと、8x8画像が得られます。
輝度調整プログラム
輝度調整は行613〜621の部分です。ここは単純にRemoへコマンドを送るだけなので説明は割愛します。テキストボックスの値をRemoへ送るだけです。数値が大きくなるほど明るくなります。Remo起動時のカメラの輝度は0に設定されています。
プログラムを動作させてみる
F5キーを押してプログラムを動作させます。
Liveのチェックボックスをチェックすると、左目の画像が動画風に出力されました。
非圧縮と比べると画質がボヤけているのがわかります。
2009年11月27日
|