• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:ピクセルの座標を取得するには)

ピクセルの座標を取得する方法

このQ&Aのポイント
  • OpenCVを使ってピクセルの座標を取得する方法について教えてください。
  • 輪郭抽出のプログラムでうまくいかないところがあります。頂点を保存する方法を教えてください。
  • ピクセルの座標を取得するための修正方法について教えてください。

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

画像は小さくて、全然わかりません。 lap_img->imageData[lap_img->widthStep * k + (j + 1) * 3 ] = 0; を直したようですが、そもそもこれは何のために入れているのですか? 範囲外になる、という他にも、ループの最後にある cb = lap_img->imageData[lap_img->widthStep * k + j * 3]; は、 その前でj++された状態なので、 lap_img->imageData[lap_img->widthStep * k + (j + 1) * 3 ] = 0; で0にした場所です。ということは、cbは必ず0になります。 つまり  j=0、cb=-1でループに入る  x座標0 を0にする  x座標1 も0にする  j++  x座標j(つまりx座標1) の値をcbに代入する。(つまり、cb=0)  ループ終了 となります j = j++; これ、意味わかってますか? たまたま期待通りに動いているかもしれませんが、それはたまたまであって、常にそうなるわけではありません。 j ++ のように、++を後に付けると j の値を使う → j=j+1 にする と動作します。  j0 = j ++ なら  oldJ = j ;  j0 = oldJ ;  j = j + 1 ; と等価です。 では、 j= j++ がどうなるか、というと、決まっていません。  j= oldJ と  j=j+1 が、どちらが先に実行されるか、C言語としては決まっていないのです。  oldJ = j ;  j = oldJ ;  j = j + 1 ; で実行されれば、 j は一つ増えますが  oldJ = j ;  j = j + 1 ;  j = oldJ ; だったら、jは前のままです。 単に一つ増やしたいだけなら、 j++ だけ書きましょう。 で、前回も書きましたが、 jを0にしてから始めるのですから、素直に  for( j=0; j < 11 && cb == -1; j ++ ) にして、ループ後のj++を抜いた方がいいのではないでしょうか? さらに  while(j < 11 && cb == -1){ // j = x軸 となっているのを  for( j=0; j < 11; j ++ ) {   cb = lap_img->imageData[lap_img->widthStep * k + j * 3];   if ( cb != -1 ) { break ; } とすれば、ループ終わりのcb=~が不要になります。

rosafilipes
質問者

お礼

kmeeさま 2度も長い丁寧なコメントをくださいまして、本当にありがとうございました! 間違いがわかり、ようやく、ようやくまともに動きました。 もちろん、ピクセルの座標もまともに取得できるようになりました。 ひとつひとつどこがどうおかしいか、自分で自覚して確認できるアドバイスを くださいまして、本当にありがとうございました。 もう、毎回ですけれども、本当に感謝しています! ありがとうございました!!!

すると、全ての回答が全文表示されます。

その他の回答 (3)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

追記します。 まず、やろうとしていることを、日本語(またはあなたが普段使う母国語)で書いてみましょう。 最初はおおざっぱでいいです。 次に「おおざっぱ」の各項目で何をするのか、より細かく書きます。 さらに細かく... と続けて、機械的にC言語の命令に置き換えられる、というくらいまでになったら、C言語に「翻訳」してください。 この設計がちゃんとできていないから、プログラムをどう直していいかもわからないのでは? うまく動作しないときも、設計図通りに動作していてるなら直すべきは設計図、設計図通りに動作していないなら直すべきはプログラム、と修正箇所の切り分けができます。 この設計図が無ければ、「明らかにおかしい」という箇所しか指摘できません。 指摘できても、修正方法まで指摘できないこともあります。 ・j=j++ は「明らかにおかしい」し、意図を推測できたので、修正方法も指摘できました ・+ j * 3 + 3 は範囲外になるという点では「明らかにおかしい」ですが、これが何を意図したものかが理解できないので、修正方法は指摘できません。 ・top変数の扱いは、top変数が何を意図したものかがわからないので、指摘も修正もできません。 画像全体で境界線の最も右の座標、なら、このプログラムの通りになりますが 注目y座標での境界線の座標、なら、jのループの前に初期化する必要があります。 コメントが少ないのも、わかりずらい理由の一つです。 先のtopについても、コメントで説明があれば解決します 例えば、設計図からプログラムへは次のような流れになります 輪郭の座標を抽出する ↓ 左上から走査して、白→黒になった座標を抽出する ↓ 「左上から走査」とは 「左から右へ走査」を上から下まで順番に行う  ↓  「上から下まで」とは y座標を0から最大y座標(今回は10)まで繰り返すこと  ↓  for( k=0 ; k < 11 ; k ++ ) {   「左から右へ走査して変化点を探す」  }

rosafilipes
質問者

お礼

はい、わかりました。 次回からもっとコメントを多く書いておおまかな流れを誰が見てもわかるように残すようにします。 足りないところを補足して考えてくださいまして、ありがとうございました。 毎回 貴重なアドバイスをありがとうございます。

すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

いちおうねんのため: j=j++; でどうなるかは確かに #2 でいわれているように「決まっていない」のですが, 正確にいうと 未定義動作である と決まっています. 「未定義動作」ですから, 何が起きても規格上は全く問題ありません. たとえプログラムを実行している途中で突然鼻歌を歌い出したとしても文句を言ってはいけないのです.

rosafilipes
質問者

お礼

そうなのですね、知りませんでした。 鼻歌を歌いださないように気を付けます(笑) いろいろとわかっていなくて、アドバイスいただけるととても助かります。 ありがとうございました!

すると、全ての回答が全文表示されます。
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

そもそも、何をどうしたいのかが、プログラムから読み取るのが困難です。 ・ while(j < 11 && cb == -1){ // j = x軸 のループの中で j = 0; k = k + 1; を実行しています。つまり、 lap_img->imageData[lap_img->widthStep * k + j * 3] = 0; のjは常に0であり、「左上から右へ走査し」ているつもりが、一番左を縦に走査しています。 ただ、それだと printf("%d, %d\n", tate[k],top); でtopの値が変化する理由がわかりません。 本当にこのプログラムの結果なのでしょうか? 質問する際に、実際のプログラムをコピーして貼り付けていますか? 結果、またはプログラムをここに書き込む際に間違えていませんか? あとは、今回とは関係無いかもしれませんが。 ○ 変数cbの型は? IPLImageのimageDataはchar * 型であり、char が符号付き整数になっていることがよくあります。 そのため cb = lap_img->imageData[lap_img->widthStep * k + j * 3]; だと、画素の値が255 だと cb = -1 になったりします。 0か255かの判定くらいならまだいいのですが、 画素Aと画素Bのどちらが明るいか、とかの場合には、判定が難しくなります。 ( 0と64では64の方が明るいですが、 64 と -1では-1の方が明るい、ということになります) cbをunsignd charとか、int等の整数にして、255までの正の整数が扱えるようにして cb =(uchar)( lap_img->imageData[lap_img->widthStep * k + j * 3] ); 等と、符号無しcharに型変換するとかしましょう。 ○次の処理 lap_img->imageData[lap_img->widthStep * k + j * 3 + 3] = 0; lap_img->imageData[lap_img->widthStep * k + j * 3 + 4] = 0; は lap_img->imageData[lap_img->widthStep * k + (j + 1) * 3 ] = 0; lap_img->imageData[lap_img->widthStep * k + (j + 1) * 3 + 1] = 0; と同じであり、x座標 j+1の画素のうち、2つのチャンネルを0にしています。 これは意図した操作なのでしょうか? このままだと、 j=10 のときに X座標11という範囲外にアクセスします。 C言語の仕様で、範囲外にアクセスすること自体は可能ですが、その結果どうなるかは保証されていません。 ○同じく j = j + 1; の後で cb = lap_img->imageData[lap_img->widthStep * k + j * 3]; をしていますが、 j=10のループのときは j=j+1でj=11になり、そのj=11を使って座標を求めようとします。 これも範囲外です。 ○このプログラムだと、y座標kの一番左が白でないとその横一列はなにもしないことになります。 それでいいのでしょうか? ○変数topが初期化されていないようですが、それでいいのですか? 例えば k=0のとき top=6 だと k=1の境界線が4でもtop=6のままです。 ○この例ならwhileではなくforの方がいいのでは? ○ (top == j || top < j) は (top<=j)とも書けます。というより、普通はそうします。

rosafilipes
質問者

お礼

kmeeさま いつもとても迅速に丁寧なアドバイスをくださいまして、ありがとうございます。 プログラムの処理経過のスクリーンショットを添付致しますので ご参照いただけますでしょうか。 なお、コードは以下のように修正致しました。 ==== tate[11] = { 0}; yoko[11] = { 0}; if (ue == 1 && shita == 1) { top = 0; while (k < 11){ // k = y軸 tate[k] = k; // y方向 cb = lap_img->imageData[lap_img->widthStep * k + j * 3]; while(j < 11 && cb == -1){ // j = x軸 lap_img->imageData[lap_img->widthStep * k + j * 3] = 0; lap_img->imageData[lap_img->widthStep * k + j * 3 + 1] = 0; lap_img->imageData[lap_img->widthStep * k + j * 3 + 2] = 0; if (j < 11){ lap_img->imageData[lap_img->widthStep * k + (j + 1) * 3] = 0; lap_img->imageData[lap_img->widthStep * k + (j + 1) * 3 + 1] = 0; } yoko[j] = j; // x方向 if (top <= j){ top =j; } j = j++; cb = lap_img->imageData[lap_img->widthStep * k + j * 3]; printf("%d, %d\n", k, j); //printf("%d\n", k); //printf("%d\n", j); } cvShowImage("Shirokuro", lap_img); cvWaitKey(0); k =k ++; j = 0; } } =====

すると、全ての回答が全文表示されます。