導入課題のすべて


卒研に配属されて、先輩達の研究を引き継いだり、新しい研究を始めるためにはプログラム能力が必要です。
研究成果デモを作ったり、実験を行うため、得られたデータを解析するためにプログラムは欠かせません。
そのために、最低限必要なスキルをこの導入課題で習得してください。
さらに、発表はパワーポイントにて行いますが、発表資料を作る際の注意点について何点か書いておきます。
また、発表予定についての概要情報も載せています。ただし、研究室でまわってくるメールの情報を優先してください。


課題1.C++の勉強 (iostream/class/STL)

まず、C++本を一冊買って読んでください。
推薦図書はこちら入門に並んだ図書です。
C++を始める人は入門から、一通り見たことがあれば初級から選んでください。

個人的なオススメは これならわかるC++ → Accelerated C++ → Effective C++ → More Effective C++ という順です。

なぜ、C++を勉強する必要があるか。
それはCに比べC++では、便利になった入出力、分かりやすいインターフェース設計と再利用化のためのクラス、プログラムの一般化のためのSTLがあります。
そのためC++は、C言語と比べて内容にかなりボリュームがあります。以下には、C++の内容を3つのカテゴリーに分けています。
この順番で勉強すると理解しやすいと思います。また、参考サイトは非常に参考になります。



参考サイト1STL & iostream primer
ダウンロード教材テキスト(.txt)
参考サイト2教材テキスト(HTML版)




課題2.C++とOPENGLを用いて24bitBITMAPファイルを読み込み
2値化、エッジ検出、とオリジナル処理を行う

この課題では、課題1で学んだC++を実際に書いて深く理解しようというのが狙いです。
C++は、Cに比べてインターフェースが優れているので、他人が分かりやすいソースコード作りができます。 そこで、Cで書いたことのある画像処理プログラムを、C++を使ってもっと見やすいソースにしましょう。
(注意)課題2で作成したプログラムは、課題3で使います。画像処理は、USBカメラのキャプチャ画像に対して行います。


読み込んだBITMAPファイルを表示させるプログラム(OpenGL使用)のテンプレートはこちら



step1 : 参考サイトを読んで、BITMAPファイルのフォーマットを理解する

BITMAPファイルのフォーマットは以下のサイトを参考にしてください。
参考サイトbmpファイルフォーマット

今回、対象にしているのは24bitのBITMAPファイルです。そのフォーマットは以下のようになります。

ファイルヘッダ
14 byte
2 byte 'BM' ファイルタイプ
4 byte ファイルサイズ (byte) 14 + 40 + 画像の総ピクセル数×3 + α(注意)
2 byte 予約領域 0
2 byte 予約領域 0
4 byte ファイル先頭から画像データまでのオフセット (byte) 54
情報ヘッダ
40 byte
4 byte 情報ヘッダのサイズ (byte) 40
4 byte 画像の幅 (ピクセル) 40
4 byte 画像の高さ (ピクセル) biHeight の値が正数なら,画像データは下から上へ
biHeight の値が負数なら,画像データは上から下へ
2 byte プレーン数 常に 1
2 byte 1 画素あたりのデータサイズ (bit) 24 - 1677万色(true color)ビットマップ
4 byte 圧縮形式 0 - BI_RGB (無圧縮)
4 byte 画像データ部のサイズ (byte) 0
4 byte 横方向解像度 (1mあたりの画素数) 2834
4 byte 縦方向解像度 (1mあたりの画素数) 2834
4 byte 格納されているパレット数 (使用色数) 0
4 byte 重要なパレットのインデックス 0
画像データ
N byte
N byte RGBデータ 左下から右上に向かってB(1 byte),G(1 byte),R(1 byte)の順(注意)

(注意)1ラインのデータ長は 4 byte 境界にあわせる必要があります。



step2 : 24bitBITMAPファイルの読み書きクラスを作成

さて、課題1で学んだC++を実際に書いて練習しましょう。
ただし、ここで作るクラスは24bitBITMAPファイルを読み書きするクラスです。

画像処理関数はクラス内かクラス外か選びましょう。
メンバ変数には何が必要か。
メンバ関数には何が必要か。

まず、bmp画像ファイルを読み込んでみましょう。そして、ファイルヘッダ/情報ヘッダ/画像データの値を表示してただしく読み込めているか Let's try!

データ読み込みのヒント

次に、画像データが左下から右上に向かって入っているのはややこしいですね。
普通は、画像の左上から右下に向かってデータが並んでいると考えます。
そこで、この違いをメンバ関数で吸収してみましょう。
以下の図を見てみましょう。




画像の位置を考える時は、上のように一番左上のピクセルが (0,0) で、一つ右のピクセルが (0,1)で、もう一つ右のピクセルが (0,2)で、一つ下のピクセルが (1,0)と考えています。
この考えに合わせてメンバ関数を作成すれば、頭の中にある位置とプログラム上での位置が一致し、自分も他人も読みやすいコードになるはずです。

具体的には
(0,0)のピクセルのR値をR(0,0)と表現すればいいでしょう。
このために

unsigned char R(const int x, const int y); // 戻り値はR値

というメンバ関数を定義します。
G、Bも同様のメンバ関数を定義します。
step1の注意には気をつけながら。
このメンバ関数があれば、どこのピクセルのRGB値でも簡単に取り出すことができます。

std::cout << "(0,0)のR値は " << (int)R(0,0) << std::endl;
std::cout << "(0,0)のG値は " << (int)G(0,0) << std::endl;
std::cout << "(0,0)のB値は " << (int)B(0,0) << std::endl;

さらに、このメンバ関数をもっと使いやすくしましょう。
例えば、画像をネガポジ反転する場合は

R(0,0) = 255 - R(0,0);
G(0,0) = 255 - G(0,0);
B(0,0) = 255 - B(0,0);
// この計算を全ピクセルに対し、行う。

と書ければ、便利ですね。 しかし、今のままでは(0,0)のR値に255を代入するといった操作はできないでしょう。

R(0,0)=255; // エラー

そこで関数に値を代入できるように参照を使いましょう。
参照のヒント

これで随分使いやすい画像クラスができました。
画像の保存はいずもがな。パパッと書きましょう。



step3 : 画像処理関数(2値化・エッジ検出・オリジナル処理)の作成

step2で作ったメンバ関数を用いれば、画像処理は簡単です。
ここでは、クラス設計とオブジェクト指向について考えて行きます。
ここでいうオブジェクトとは意味のある塊だと考えてください。

画像には各ピクセルに色データがあり、白色なら(R:255 G:255 B:255)と表せます。
また、画像は2次元のデータなので、表現する際は幅と高さが必要です。
つまり、画像というオブジェクトには画像の幅、高さ、ピクセルの色データがあると考えられます。

そしてビットマップファイルは、step1にあったような仕様のファイルフォーマットで書かれたデータです。
つまり、ビットマップファイルは画像というオブジェクトをある仕様に従い、記述されたオブジェクトなのです。
この仕様が変われば、jpegなど他のフォーマットの画像データになります。
だから、どんな形式の画像、つまり .bmp や .jpeg でも画像というオブジェクトは共通ですね。
つまり、ビットマップでもjpegでも、データの中にピクセルの色データ、画像の幅、高さがあります。
この包含関係を下の図に示します。



では、この関係をうまくクラス設計に活かすためにはどうしたらよいでしょうか?
ここは、継承を使いましょう。

まず、基本クラスとして画像クラスを設計します。
画像クラスには画像を表現するのに最低限必要なパーツをメンバ変数に宣言します。
つまり、メンバ変数には画像の幅、高さ、ピクセルの色データを格納する配列が必要です。
あと、メンバ関数には、そのメンバ変数を十分に直感的に使いやすい関数を定義します。
step2で作ったRGBを操作する関数はこの画像クラスに書きましょう。

次に、この画像クラスを継承するビットマップクラスを設計しましょう。
ビットマップクラスには何が必要でしょうか?
メンバ関数にはファイルの読み込み、書き込み関数が必要です。
また、メンバ変数にはヘッダー情報が必要です。

この構造にしておけば、jpegに対応する場合は画像クラスはそのままで、JPEGのフォーマットを参考に、ビットマップクラスを改造すればよいです。
JPEGは圧縮アルゴリズムが難しいので既存のライブラリを使用することもオススメします。
他のフォーマットも色々あるので調べてみましょう。なぜなら、ビットマップはゴミバイトがうっとおしいです。
簡単なのはTGAフォーマットと思います。ただし、このフォーマットはビットマップやJPEGほどメインストリームではありません。

で、ここstep3では画像処理関数を作るのが目的でしたが、どこに関数を定義しますか?
画像クラス中でもいいです。画像クラスの外で定義してもいいですね。
ただし、画像処理はどれも画像オブジェクトと深く関係していますので、画像クラスと同じファイル中で定義したほうが分かりやすくなります。




最後に
クラス設計、コーディング方法の考え方には人それぞれ、細かい点まで異なります。
例えば、変数名を規則にしたがって名づけるコーディング規約や、特定のライブラリを使うことによりある変数へのアクセス方法が制限される場合など。
ただし、読みやすいコードを書くのは共通の目標で、そのためにはどうすればよいかというと
人が頭で考えていることに近い実装方法を考えるとこです。
今回の例では画像に関係することだったので、RGB値を取り出すメンバ関数を工夫しました。

規約や制限にこだわりすぎず、自分の思考に従った設計をしましょう。
また、人の書いたソースコードを読み、どういった設計をしているか考えることが重要です。
特に、STLで書かれたコードを見ることは、C++で優れたコーディングをするために必要です。
本やネット検索を十分有効に活用してC++を使いこなしてください。




課題3.動画像処理(発表)

USBカメラからのキャプチャ画像をリアルタイムで処理する。
以下にある雛形サンプルプログラムを穴埋めし、カメラの初期化を行い、課題2で作った画像処理プログラムをくっつけてみましょう。
非常に参考になるHPのURLをソース中のコメントに書いてます。

カメラの初期化プログラムの雛形を用意しました。これ(camera.cppを変更してください)を使ってください。
島田先生verの雛形サンプルはこれ(MFC入ってますよ)。




課題4.OPENGLを用いてオリジナルのアニメーション作成(発表)

OPENGLはグラフィックスライブラリで、OPENGLを使えば2次元、3次元の画像を生成することができます。
このOPENGLを使って、オリジナルのアニメーションを作ってみましょう。
去年のS藤くんの作品はこれ(クリックすると始まります)


注意
実行環境(CPU性能)によって,アニメーションの再生速度が早くなったり遅くなったりします.
対策としてglutTimerFunc 関数を使いましょう.
glutTimerFunc 関数の例: http://wisdom.sakura.ne.jp/system/opengl/gl10.html
glutIdleFunc 関数の例: http://www.wakhok.ac.jp/~momma/lec2004/Graphics_Programming/12/lecture12.html

参考サイト1手抜きOPENGL
参考サイト2OpenGL入門






発表資料を作る際の注意点

発表資料は、パワーポイントやデモ用実行ファイル、ムービーなどがあります。

パワーポイントを作る際の注意点

ゼミ、学会発表はパワーポイントにて行います。
発表内容の順番や内容はそれぞれの発表内容によって異なります。
しかし、どの発表内容であっても決まりごとがあります。
この基準を守らないと、発表見学者は文字が読めない、線が見えないといった障害が起こりやすいです。
基本的には見えにくい、読みにくい資料を作るのはやめましょう。
まだまだ細かい点はありますが、それは発表回数を重ねるごとに学んでいってください。

デモ用ファイル用意時の注意点

デモ用の実行ファイル、ムービーを発表会場で動かす場合、以下の点に注意してください。
せっかく作ったデモ用ファイルを発表時に無駄にしないよう気をつけてください。






最後に導入課題発表について

以上の課題を全て終え、発表してもらいます。
発表予定は
1月第2週 : B3発表ゼミ(全員発表)
3月後半  : 院進組 導入課題発表(課題3,4のできた範囲)
1月後半はテストに集中してください。
2月初旬に一度B3全員を集めて導入課題のミーティングを行います。
院進組は、4月中に導入課題を終えてください。
就職組は、就活状況に合わせて対応していきます。
以上は現在の予定なので、正確な発表スケジュールはゼミのスケジュールに従ってください。














戻る