• ベストアンサー

写真の抜き出し

「とてもよく出来る」先生の研究室に入って何も指導していただけないまま1年が過ぎました。 現在の私のC言語の実力はポインタがわかる程度です。 他の人も同じくらいのレベルなのですが、こんなレベルなのにも関わらず 今回出された課題が「給食の写真の中からご飯部分を抜き出すプログラムを作れ」という高度なもの。 本やネットで調べていいということで色々調べてみたのですが何せ知識が少ないのです。 流れとしてなんとなく考えて ・閾値を用いて画像を抜き出す ・(食器の)丸い形を探して画像を抜き出す という方法のどちらかでやればできるのではないかと考えています。 5月中の課題のはずがきまぐれの多い先生なので次の月曜までに作らないといけなくなりました。 あと3日間。バイトの時間を差し引くとあと42時間程度しかないのですが 出来る限り頑張ろうと思うのでヒントや、参考になるサイトなどを教えていただけませんか? 現在「c言語で学ぶ実践画像処理」という本を読んでそこにあるプログラムを Visual c++で打ってはみたのですがきちんと動作しません。 きっと本にも書かないような基本事項さえも身についていないのだと(゜Д゜;) 出てくる関数が知らないものばかりなので自分で一から組むこともできず困っています。 どうか、アドバイスをお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • lawson
  • ベストアンサー率44% (29/65)
回答No.6

正方形を構成する場合のピクセル数の変化として、 1ピクセル(1の2乗) 4ピクセル(2の2乗) 9ピクセル(3の2乗) 16ピクセル(4の2乗) 25ピクセル(5の2乗) という風に正方形を構成するピクセル数が 変化します。 0,0を左上にした場合に上記の大きさのバリエーション の正方形があります。 それは0,1を左上にした場合も同じです。 そうすると、先程の0~9までの値が格納された 2次元配列の中で正方形の組み合わせは 無数にあります。それらを再帰アルゴリズムなどで しらみつぶしに調べ、以下のような 正方形はどれであるかを検出するみたいな。 たとえば、 4ピクセル(2の2乗) から 9ピクセル(3の2乗) に正方形の大きさが変化しても 正方形をなす値の合計数に変化がない時。 4ピクセル(2の2乗)を成す、正方形を候補とする。 そして、2次元配列全体として、 どの候補の正方形(抜き出し時の4つ値) が最も、値の合計数が大きいかなどの基準で 選ばれたものが。 例のNo2のプログラムにての抜き出し対象となる。 みたいな。 考えただけで、かなりむずい。 そんなの学生が普通に課題とかで作るものなのだろう か。

bananapafe
質問者

お礼

アルゴリズムはなんとなくわかるのですが、それをプログラミングするとなるとさっぱりですね… 卒業論文にはニューラルネットワークを利用してプログラミングをするみたいなので こういったアルゴリズムをさっぱりだ、と投げ出さずに理解していかないとだめなんです。 抜き出す範囲の検索とかどうやるのかまったく見当もついていなかったのですが すごくわかりやすい検索方法だな、と思いました。 >そんなの学生が普通に課題とかで作るものなのだろうか。 本当にそうですよね。 1,2週間で独自でこなすような課題ではない気がします。 今ふと思いついたのですが、ひとまず今回は写真に100ピクセル単位くらいで格子状に線を引いて 範囲を指定しやすいようにする、ぐらいにしてみようかと思います。 そうすればほかの写真にも応用ができると思うので…。

bananapafe
質問者

補足

下の補足に書いた文なのですが、解決しました。 リンクができていなかったり、2重になっていたり、初級の本では「おまじない」として覚えること と言われていた<stdio.h>の役割もわかったので少しずつですが理解できています。 色々といじってみることはすごく大切ですね。 長文でお時間を割いて回答いただき本当にありがとうございました。

その他の回答 (5)

  • lawson
  • ベストアンサー率44% (29/65)
回答No.5

昨日、日中忙しくて昨日はすぐ寝たので いまになりましたが。 えっと、No2の時に動作確認したのは フリーウェアとして提供されている Borland C++ 5.5でコンパイル・リンクしました。 bmp.cをコンパイル。No2のソースをコンパイル。最後にリンクという具合にやりました。 正確に言えばBCC Developperというフリーの IDE上でやりましたが。 >現段階ではコンパイルのエラーはないですがビルドを>すると >>b.obj : error LNK2001: 外部シンボル "_WriteBmp" は未解決です >>b.obj : error LNK2001: 外部シンボル "_ReadBmp" >は未解決です >>Debug/b.exe : fatal error LNK1120: 外部参照 2 が未解決です。 >>link.exe の実行エラー >と表示されます。 bmp.cをプロジェクトに含めてないとか・・。 そんなことはないか・・・。 bmp.cをコンパイルしてできるオブジェクトファイル がなければ、リンク時にリンカは WriteBmpとReadBmpのコンパイル済みの実コード を見つけることができません。 一応、こちらのVS 2003 .NETのほうでやると、 別の内容ですがリンクエラーになってしまいます。 私のPCのVC++上のリンクエラーは bmp.cでbmp.hをインクルードして、コンパイルした bmp.objにbmp.hで定義されていた分の実コードが 含まれる。 No2のソースをコンパイルしたほうのobjファイルにも bmp.hの内容がコンパイルした分が含まれる。 そしてそれらをリンクすると、 既にあります。重複してますと怒られます。 error LNK2005: "unsigned char * Bmp_Pallet" (?Bmp_Pallet@@3PAEA) のようなエラーが複数, bmp.hに定義がある変数や 宣言がある関数に対してでます。 No2のソースではbmp.hをインクルードするのをやめて すべてextern参照しようと思いましたが。 img構造体の型そのものをexternする術がないので 結局無理。 bmp.hに http://shodai.hp.infoseek.co.jp/vc_pp/vc_pp_index.htm#020 2重インクルード防止をやっても無理。 しょーがないので、以下のような解決策を とりました。 ######################################### 私の環境での解決策####################### ######################################### No2のソース内容の #include<stdio.h> #include"bmp.h" の部分を除くすべてをコピーして、 bmp.cの末尾に追加しました。 そして、bmp.cとbmp.hだけをプロジェクトに 残してビルドするとVC++上で動作するモジュールを 作成することが一応できました。 ######################################### bananapafeさんのリンクエラーとは異なり ますが・・・・。 Borland C++ 5.5はフリーですので、 どうしてもだめならそちらでやれば動く模様。 >写真は机の上に牛乳、ご飯、おかず2種の皿が置いてあって真上から撮影されたものです。 >皿はすべて丸いので形を探し出して抜き出すのでも大丈夫かな? 私が示したのは位置が分った後の抜き出し方に すぎないです。 位置情報は四角形です。 x, y, width, heightこの4つがわかれば、 抜き出す方法が分っている。 となると、どうやってその4つの値を検出するか という問題にすりかわります。 ご飯部分とは、このような色をしているものだ。 という定義が必要だと思います。 RGB値のうち、色相が白に近いもの。 どこまで許容させるかは別にして。 ご飯色の範囲はまず、きめうちにするしかない。 img構造体はweightメンバ、heightメンバ と同じよう要素数を持つ2次元配列を設ける。 その2次元配列において、 img構造体上のご飯色の範囲の色であるピクセルに 対応する部分は9をたて、そうでない部分は0 をたてる。そうすると9と0が詰まった2次元配列 ができあがる。 0のピクセルについて、自分の八方に対して 9であるピクセルが何個存在するかで、 0~8までの数字を格納していく。 うーん。そこから、どう先程の4つの値を 検出するかなのだ。 なにか、突飛な方法があるかもしれないが。 ひらめかないですね。 0~9までの値の大きさとその分布状況で。 密度が濃い部分を囲むような四角形を成す。 4つの値をどのようにして見つけるかという 問題にすりかわるとおもいます。 今回の課題が全体として・・。 なにか、再帰アルゴリズムのようなものを 全ピクセルに対して行うようなうまいやり方 みたいな。

bananapafe
質問者

お礼

VMirror2()の内容は理解できたので、課題となった写真と置き換えてとりあえず一枚、 ご飯部分だけ抜き出すことができました。 本当にありがとうございました。 今までやってきたことがただの基礎中の基礎だったということもあってVC++の使い方さえままならず 新規作成→ソース入力→コンパイル→実行 このような動きのみしか行っていなかったのでプロジェクトを作る?リンク? のように今回の課題で今までの使い方がいかに最小だったかを実感しました。 .c ファイルしか作ったことなかったのに .h ファイルが出てきたのも脅威でしたし…。 ひとまずは安心、な気がします。でもまだ時間はあるので別の方法で出来る限りやってみたいと思います。

bananapafe
質問者

補足

お礼に書き忘れていました。 エラーの原因は、まさかのプロジェクトに含めていなかった、だと思います(^^;) 一度窓を閉じて、一から丁寧にやり直したらできましたので…。 ものすごく基本的なことだと思うのですが、.hファイルというのは定義をする為のファイルなのですか? インクルードしていればプロジェクトに追加をしなくてもいいのですよね? 友人に別のサンプルソースをもらったのですが、.hファイルで定義されているのにコンパイルすると 定義されていませんとなってしまいました。 その部分を.cに貼り付けると大丈夫だったのですが…。 (でも普段定義しないようなものまで定義されていませんとなっているので ファイル自体が少しおかしいのかもしれないです。 もう少ししっかり見てみようと思います。)

  • neKo_deux
  • ベストアンサー率44% (5541/12319)
回答No.4

> 「給食の写真の中からご飯部分を抜き出すプログラムを作れ」 課題がこのままなら、必ずしも画像を出力する必要も無いと思います。 最悪、 c:\>nukidashi.exe kyuusyoku.bmp ご飯の範囲は(122,215)-(315,409)の範囲です。 とかの出力でも良いのでは? 画像がどういうものか?とかにもよりますが。 -- > あと42時間程度しかないのですが 画像処理の研究室とかならば、 ・どういう処理でやろうとしたか? ・画像処理ツールや手計算でやった結果。 などを提示する方が、動かない、読めないプログラムよりはマシだと思いますし。

bananapafe
質問者

お礼

アドバイスありがとうございます。 さまざまな友人に聞いたときにも「画像は何で表示させるの?」というように聞かれたことで そういえば手法も結果表示も何も指定されていない、ということに気づきました。 ただ、自分が確認する為にも目に見えるように表示できたらいいなと思ったというのがあります。 >・どういう処理でやろうとしたか? >・画像処理ツールや手計算でやった結果。 まさに、そのとおりだと思いました。 出来てなかったらかなり怒られるとは思うのですが、ソースをコピーしただけで工夫もなく、 動きませんでした。と言うよりは、少しでも自分なりに手を加えて ここまでやったけどだめでした。の方が先生も納得してくださるのではないかと。 自分が納得できる程度にはきちんとがんばりたいと思います。

  • lawson
  • ベストアンサー率44% (29/65)
回答No.3

>URL先の内容、ざっと読んだだけでは難しかったのですが今後を考えても >しっかり読んで学んでみたいと思います。 肩の力を抜いて下さい。 とりあえず、No2の回答のプログラムを動かす ことに成功させてください。 詳細を理解したいのなら、その後でよいです。 なので、優先順位としては以下のような感じに なるでしょう。 1)No2の回答を確実に実行させることに成功させる。 コンパイル・リンク、実行まで、うまくいきましたか?もし、わからなければまた、質問に対する  お礼や補足で質問すればよいでしょう。 2)No2のプログラムのVMirror2()のみでよいから 理解して、自分が持っている給食の画像で ご飯の部分が抜き出せるように位置情報を 調整したプログラムを作ってみる。 VMirror2()をコピーしてVMirror3()でも つくったりしてやればよいでしょう。  ここまでやったら、課題は終了なので、 あとは、興味がなければ終了です。 もし、興味があって勉強したいなら、(3)を やればよいのです。 3) bmp.cにあるWriteBmp()関数の中の /* ヘッダ情報の準備 */ Bmp_xppm=Bmp_yppm=0; Bmp_image_size = tp->height*Real_width; Bmp_size = Bmp_image_size + HEADERSIZE; Bmp_headbuf[0]='B'; Bmp_headbuf[1]='M'; memcpy(Bmp_headbuf+2,&Bmp_size,sizeof(Bmp_size)); Bmp_headbuf[6]=Bmp_headbuf[7]=Bmp_headbuf[8]=Bmp_headbuf[9]=0; memcpy(Bmp_headbuf+10,&Bmp_header_size,sizeof(Bmp_header_size)); Bmp_headbuf[11]=Bmp_headbuf[12]=Bmp_headbuf[13]=0; memcpy(Bmp_headbuf+14,&Bmp_info_header_size,sizeof(Bmp_info_header_size)); Bmp_headbuf[15]=Bmp_headbuf[16]=Bmp_headbuf[17]=0; memcpy(Bmp_headbuf+18,&tp->width,sizeof(Bmp_width)); memcpy(Bmp_headbuf+22,&tp->height,sizeof(Bmp_height)); memcpy(Bmp_headbuf+26,&Bmp_planes,sizeof(Bmp_planes)); memcpy(Bmp_headbuf+28,&Bmp_color,sizeof(Bmp_color)); memcpy(Bmp_headbuf+34,&Bmp_image_size,sizeof(Bmp_image_size)); memcpy(Bmp_headbuf+38,&Bmp_xppm,sizeof(Bmp_xppm)); memcpy(Bmp_headbuf+42,&Bmp_yppm,sizeof(Bmp_yppm)); Bmp_headbuf[46]=Bmp_headbuf[47]=Bmp_headbuf[48]=Bmp_headbuf[49]=0; Bmp_headbuf[50]=Bmp_headbuf[51]=Bmp_headbuf[52]=Bmp_headbuf[53]=0; この部分のコードを理解する。 これが、今回のテーマでしょう。 http://coconut.sys.eng.shizuoka.ac.jp/bmp/ はその説明がほとんどでしょう。 コードの中身と、サイト上の説明を交互に 見ながら時間をかけて解析すれば、 少しづつ理解できるかもしれません。 せっかく、本をお持ちになっているので、 そちらも参考にしながらでもよいと思います。 おそらく、先生が課題を出した目的などが、 こういうところでしょうが。 私の頭では理解不能なので、 私自身はパスさせていただきます。 あとは、数学的な思考力でもって、 Rotate90()を理解する等がありますが。 画像の知識そのものとはあんまり関係ないです。 >目標の達成、というのが本当に大事な時があるので >すごくうらやましいです。 たしかに大事です。 しかし、あまり、それに走りすぎるのもよくない こともあります。 あまり、それに頼りすぎると勉強には ならないです。 学生であれば、少しぐらい遠回りしてでも 画像についての勉強になったほうがよいの かもしれません。 ただ、この科目が興味なくて、ただ、単位を とるだけの位置づけなら関係ない話です。 以上。

bananapafe
質問者

お礼

アドバイスありがとうございます。 肩の力を抜いて…本当にそうですよね。 できないことに焦ってイライラしていた気がします。 画像処理には興味があるのですがこういった形で勉強するのではなくきちんと基本から学びたかったです。 ゼミでの課題である為にきちんとやらないと卒論を放っておかれそうで怖くて… 今回の課題も「出来てなかったら知らんよ」という感じで脅迫(?)めいたものをされています(><) 写真は机の上に牛乳、ご飯、おかず2種の皿が置いてあって真上から撮影されたものです。 皿はすべて丸いので形を探し出して抜き出すのでも大丈夫かな?と思いました。 また、写真は数枚あってそれぞれで皿の位置が違うのでしっかりと位置情報を固定してしまうと 目的が果たせないのですが…一枚に対してがんばった、という姿勢を見せれば 先生も少しは納得してくれるのではないかと信じています。 現段階ではコンパイルのエラーはないですがビルドをすると >b.obj : error LNK2001: 外部シンボル "_WriteBmp" は未解決です >b.obj : error LNK2001: 外部シンボル "_ReadBmp" は未解決です >Debug/b.exe : fatal error LNK1120: 外部参照 2 が未解決です。 >link.exe の実行エラー と表示されます。 対策は正直に言うとわからなくて、過去ログに似たような質問があったのですが 新規プロジェクトをWin32 console applicationで作っても解決しませんでした。 今日、図書館でc/c++の用語辞典を借りてきたので調べてみようと思っています。

  • lawson
  • ベストアンサー率44% (29/65)
回答No.2

抜き出す方法としては大きく2つ考えられる かもしれない。 ・位置情報による抜き出し。 ・色情報による抜き出し 今回の回答としては位置による抜き出しを 考えました。 私は、画像についてはほとんど知識がありませんが http://coconut.sys.eng.shizuoka.ac.jp/bmp/ こちらのサイトによいサンプルプログラムがありました。 bmp.c bmp.h をコンパイルして、 以下のソースをコンパイルしたものと、 リンクして実行プログラムを作ってください。 実行プログラムがあるディレクトリに dog.bmpの画像ファイルを置いてください。 dog.bmpの画像の犬の顔の付近だけが 抜き出された85×85ピクセルの小さな画像の dog2.bmpのファイルが出力されます。 bmp.c bmp.h dog.bmp はすべて先ほどのサイトにあります。 なお、先程のサイトではソースがEUCコードで 改行コードもUNIXの改行コードで保管してあるので、 コンパイラエラー等で問題になるようでしたら、 エディタなどの機能でSHIFT-JISに変換してください。 インターネットエクスプローラで右クリックで エンコードをSHIFT-JISにあわせて右クリックで ソースの表示して、コピペした内容を秀丸エディタ などで開いて編集するなどすれば、大丈夫でしょう。 (メモ帳では改行コードの問題で改行されていないように見えますので。) では、以後ソースを示します。 test0.c を参考にしながら、 bmp.cにある VMirror()関数を改造した VMirror2()を定義することで 処理を行いました。 画像のヘッダーの書式はまったく 理解できませんでした。 とりあえず、目的は達成できたはず。 なので、詳細は私に聞かれても知りません。 ・色情報による抜き出し をしたければ bmp.hの img構造体のcolor構造体を使えばよいでしょうが、 色についてのRGB値の意味とかは別途調べて 下さい。 私は職業がら適当にやってでも 目的を達成する術は普段からしてなれているだけです。 ですが、画像についてはまったくの素人 なので詳細を聞かれてもよく知らないです ではっ勉強がんばってください。 ###以下ソースコード##### #include<stdio.h> #include "bmp.h" img imgObj; img imgObj2; img* imgObjFrom = &imgObj; img* imgObjTo = &imgObj2; void VMirror2(img *sp, img *tp); int main(int argc, char** argv) { ReadBmp(".\\dog.bmp", imgObjFrom); VMirror2(imgObjTo, imgObjFrom); WriteBmp(".\\dog2.bmp", imgObjTo); return 0; } void VMirror2(img *sp, img *tp) { int i,j; int i2,j2; long k; //for(i=0;i<tp->height;i++) for(i=70,i2=0;i<155;i++,i2++) { for(j=200,j2=0;j<285;j++,j2++) { //sp->data[i][tp->width-j-1]=tp->data[i][j]; sp->data[i2][j2]=tp->data[i][j]; } } //sp->height=tp->height; //sp->height=tp->weight; sp->height=85; sp->width=85; }

参考URL:
http://coconut.sys.eng.shizuoka.ac.jp/bmp/
bananapafe
質問者

お礼

アドバイスありがとうございます! URL先の内容、ざっと読んだだけでは難しかったのですが今後を考えても しっかり読んで学んでみたいと思います。 ソースコードを書いていただけて本当にありがとうございました。 上手に引用していきたいと思います! >目的を達成する術は普段からしてなれているだけです。 >ですが、画像についてはまったくの素人 目標の達成、というのが本当に大事な時があるのですごくうらやましいです。 画像については素人、ということはわざわざ調べてくださったということですよね! 本当にありがとうございました!

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

>・閾値を用いて画像を抜き出す >・(食器の)丸い形を探して画像を抜き出す >あと3日間 多分、ムリ >「給食の写真の中からご飯部分を抜き出すプログラムを作れ」 という課題には、自動的に範囲を認識してという限定がないので、手動でマウスで切り出す範囲を指定してやっても良いという解釈でやればいいのではないでしょうか

bananapafe
質問者

お礼

アドバイスありがとうございます。 なるほど、そういった抜き出し方法もあるのですね!! 全然思いつきもしなかったのですが面白そうだな、と思いました。 その方面でもいろいろと考えてみようと思います!! >多分、ムリ ちょっとショックでしたが、易しい問題ではないということですよね…。 これを機に今後もっと勉強していくようにします。

関連するQ&A