質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.32%

ビルド正常終了した。デバッグできません

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,628

jiaxiaoyue

score 12

前提・実現したいこと

pmb画像を読んで、人が閾値を決め、ソーベルでエッジ検出します。
(例)visual studio 2008でopencvのc++を作っています。 
  実装中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

デバッグするとエラーメッセージがなく、画像のウィンドウが出ましたが、処理できずに止まりました。

該当のソースコード

// kadai6-2.2.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

include "stdafx.h"

ifdef _DEBUG

define new DEBUG_NEW

endif

IplImage *img;//, *img_out;,img
int width,height;
int edge_thresh_sobel = 0;            // 閾値の初期値 

IplImage *gray_sobel, *edge_sobel, *edgeX, *edgeY;

int sobel(int t) { 
    int    i, j, dx, dy, W, H; 
    double mag; 

    W = img->width;  H = img->height; 
    for(i=0;i<(W*H);i++) {
        j  = i * 2;
        dx = (int)edgeX->imageData[j];
        dy = (int)edgeY->imageData[j];
        mag = (double)(dx*dx + dy*dy);
        mag = sqrt(mag);

        if(mag >= (double)t)        edge_sobel->imageData[i] = (unsigned char)255;
        else                        edge_sobel->imageData[i] = 0;
        return t;

    }

}

int _tmain(int argc, _TCHAR* argv[])
{
    img = 0;      // 画像ファイル読み込み
    img = cvLoadImage( "airplane-gray.bmp");

     // 画像表示窓の準備
    cvNamedWindow("入力画像", 1); 

     // 画像表示
    cvShowImage("入力画像", img);

    //平滑化処理
    cvSmooth(img,img,CV_GAUSSIAN,3);
    // 画像表示窓の準備
    cvNamedWindow("平滑化", 1); 

     // 画像表示
    cvShowImage("平滑化", img);

     // エッジ点画像用データを作成
     edge_sobel = cvCreateImage( cvSize(img->width,img->height), IPL_DEPTH_8U, 1 );
     // X方向,Y方向のエッジ強度を保存するバッファを確保する. 
     // バッファのDEPTHはsigned short(IPL_DEPTH_16S)を指定する.  
     // (画素値が[0,255]の濃淡画像から3x3のマスクでエッジを検出すると 
     // エッジ強度は[-4*255,4*255]の値をとるため) 
     edgeX = cvCreateImage( cvSize(img->width,img->height), IPL_DEPTH_16S, 1 );
     edgeY = cvCreateImage( cvSize(img->width,img->height), IPL_DEPTH_16S, 1 );

     printf("閾値を入れてください:");
     scanf("%d",edge_thresh_sobel);

     // エッジ強度処理
     sobel(edge_thresh_sobel);

     //画像表示窓の準備
     cvNamedWindow("sobel", 1); 

    // 結果を表示
    cvShowImage("sobel",edge_sobel);

     // 終了処理
     cvWaitKey(0); 
     cvReleaseImage(&gray_sobel);
     cvReleaseImage(&edgeX); 
     cvReleaseImage(&edgeY); 
     cvReleaseImage(&edge_sobel);

     cvDestroyWindow("入力画像");
     cvDestroyWindow("平滑化");
     cvDestroyWindow("sobel");

    return 0;
}

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報
![イメージ説明](11356c7de1bedb37efd5440c264c081d.png)

/*---------------------------------------------------------------------------------------*/

// kadai6-2.2.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

include "stdafx.h"

ifdef _DEBUG

define new DEBUG_NEW

endif

IplImage *img;//, *img_out;,img
int width,height;
//int edge_thresh_sobel = 0;            // 閾値の初期値

IplImage *gray_sobel, *edge_sobel, *edgeX, *edgeY; 

int sobel(int t) {  
    int    i, j, dx, dy, W, H;  
    double mag;  
//t=edge_thresh_sobel;
    W = img->width;  H = img->height;  
    for(i=0;i<(W*H);i++) {
        j  = i * 2;
        dx = (int)edgeX->imageData[j];
        dy = (int)edgeY->imageData[j];
        mag = (double)(dx*dx + dy*dy);
        mag = sqrt(mag);

        if(mag >= (double)t)        edge_sobel->imageData[i] = (unsigned char)255;
        else                        edge_sobel->imageData[i] = 0;
        return t;

    } 

}

int _tmain(int argc, _TCHAR* argv[])
{
    img = 0;      // 画像ファイル読み込み
    img = cvLoadImage( "airplane-gray.bmp");

     // 画像表示窓の準備
    cvNamedWindow("入力画像", 1);  

     // 画像表示
    cvShowImage("入力画像", img); 
printf("1");

    //平滑化処理
    cvSmooth(img,img,CV_GAUSSIAN,3);
    // 画像表示窓の準備
    cvNamedWindow("平滑化", 1);  

     // 画像表示
    cvShowImage("平滑化", img); 
    printf("2");

     // エッジ点画像用データを作成 
     edge_sobel = cvCreateImage( cvSize(img->width,img->height), IPL_DEPTH_8U, 1 );
     // X方向,Y方向のエッジ強度を保存するバッファを確保する.  
     // バッファのDEPTHはsigned short(IPL_DEPTH_16S)を指定する.   
     // (画素値が[0,255]の濃淡画像から3x3のマスクでエッジを検出すると  
     // エッジ強度は[-4*255,4*255]の値をとるため)  
     printf("3");
     edgeX = cvCreateImage( cvSize(img->width,img->height), IPL_DEPTH_16S, 1 ); 
     edgeY = cvCreateImage( cvSize(img->width,img->height), IPL_DEPTH_16S, 1 ); 

printf("4");

sobel(200);     //呼び出し
     //画像表示窓の準備 
     cvNamedWindow("sobel", 1);  
printf("7");
    // 結果を表示
    cvShowImage("sobel",edge_sobel);

printf("8");

     // 終了処理 
     cvWaitKey(0);  
     cvReleaseImage(&gray_sobel); 
     cvReleaseImage(&edgeX);  
     cvReleaseImage(&edgeY);  
     cvReleaseImage(&edge_sobel);

     cvDestroyWindow("入力画像");
     cvDestroyWindow("平滑化");
     cvDestroyWindow("sobel");

     printf("9");
    return 0;
}

/*-----------------------------------------------------------------------------------*/
またこういうように単純に閾値を代入すると、ソーベルオペレータが使えない。。。
イメージ説明

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

0

こんにちは。

sobel(int t)関数がi=0の最初のループで単純にreturn t;しているようです。
でも、入力画像が表示されないのは、これが原因ではないですね。

airplane-gray.bmpは、ビルドしたプログラムのexeファイルと同じフォルダにおいてますか?
恐らく、これを読み出せてないです。
例えば、C:\airplane-gray.bmpへコピーしておき、img = cvLoadImage( "C:\\airplane-gray.bmp");としてみたらどうなりますか?(\\に注意下さい。""の中では\\と書いて初めて\へ展開されます。)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/03 16:03

    回答ありがとうございます。画像ファイルは正しいところに置いていましたと思っています。なぜなら、printf("閾値を入れてください:"); 前のプログラムが通常に動いています。ソーベルを呼び出しを/**/で隠したら、入力画像と平滑化画像が出ることができます。入力した値の代入が問題になったと思っています。つまりソーベル関数がどこかいけないではないかと思っています。今必死探す中(すみません、文法的な間違いがあったら許してくださいT^T)

    キャンセル

  • 2016/06/03 16:23

    > ソーベルを呼び出しを/**/で隠したら、入力画像と平滑化画像が出る

    質問の画像と矛盾しているように見えます。

    質問の画像は、「閾値を入れて下さい」に対してまだ閾値を入力していないように見えます。ですので、この時点でsobel()は呼ばれていない筈です。従って、sobel()関数呼び出しをコメントアウトするかどうか関係無い筈なのです。

    Visual Studio上で実行する場合と、exeを直接叩く場合でカレント・フォルダが異なりますので、仮に前者で画像が読めても後者では読めないです。(逆も真です。)
    exeの起動の仕方は統一されてますか?

    後、sobel()関数について、回答の冒頭で指摘させて頂いた不具合があると思います。

    キャンセル

  • 2016/06/03 18:28

    質問文を修正されたようですね。

    soble()関数に多数の不具合があります。

    ①edgeX, edgeYは恐らく、縦方向と横方向の微分値を入れていることが期待されている雰囲気が漂っていますが、単純にcvCreateImage()しているだけで微分しているコードが存在しません。
    従って、dx, dyの値は常に0となります。

    ②最初に指摘したようにreturn t;の位置がまずいままです。

    ③一般的なソーベル・フィルタのアルゴリズムとは異なる実装になっているようです。
    http://www.mvision.co.jp/WebHelpIM/_RESOURCE/Filter_Mvc_Sobel.html
    dx, dyを適切に計算していれば、期待しているものに近い結果はでそうですが。

    後、元のプログラムのscanf()は、eleanor2352011さんも指摘されているように、&がないので期待通りに動作しないと思います。

    キャンセル

0

いろいろツッコミどころはありますが、絞ります。
1.BMP画像は1ライン毎に4の倍数となってるはずですが、そこは考慮されてますか?
2.そもそもですが、SOBELオペレータって差分ですよね。自乗平均とっても意味がないように思えます。
3.画像深度が16ビットとされてるので、255でフィルタすると真っ黒に近い画像が表示されるはずです。
流れとしては、多分SOBELオペレータだけ作れという事だと思うので、まずは、sobel(edge_thresh_sobel); これをリマークして普通に画像が表示されるか確認されてはどうでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

私もChironian様と同意見で、Sobelはまともに動いていないと思います。
理由は2点あります。

printf("閾値を入れてください:");
scanf("%d",edge_thresh_sobel); 
→scanf("%d",&edge_thresh_sobel); 
「&」が無いので、ここでソフトが落ちてませんか?

もう1点目は既に上述されていますが

for(i=0;i<(W*H);i++) {
   j  = i * 2;
   dx = (int)edgeX->imageData[j];
  dy = (int)edgeY->imageData[j];
   mag = (double)(dx*dx + dy*dy);
   mag = sqrt(mag);

   if(mag >= (double)t)        edge_sobel->imageData[i] = (unsigned char)255;
   else                        edge_sobel->imageData[i] = 0;
   return t;
}

returnはfor文の外では無いでしょうか?
このままですと直ぐにループが終わりませんか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る