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

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

ただいまの
回答率

88.60%

キャプチャ画像が取得できない

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 543

ShiiTakumi

score 15

「OpenCVプログラミングブック 第2版 OpenCV1.1対応」掲載サンプルを実行しながら画像処理について勉強しています。

現在、USB接続Webカメラによるライブ映像のキャプチャができなくて詰んでおります。
サンプルを実行してみるとwebカメラはちゃんと発見されているのですが、出現したウィンドウは真っ暗のままです。
画像が取得されているかどうか検証したところ「NULL」が返っており、ずっと取得出来ていない状態でした。
しかしARToolKit関係のサンプルではカメラは問題無く動作しておりました。

これはいったいどういうことなのでしょうか。
ネット検索したところwebカメラ性能に問題がありそうですが、どう対処すればよいのでしょうか。

ご教授いただければ幸いです。

(VisualStudio2017使用)
以下、掲載サンプル(s48/rockpaperscissors.cpp)に少し修正したコードです。
修正箇所:frameImageがNULLかどうかを追記

//---------------------------------------------------------
// 概要      : ジャンケンの判定
// File Name : rockpaperscissors.cpp
// Library   : OpenCV 1.1
//---------------------------------------------------------

#include "rockpaperscissors.h"

char windowNameCapture[] = "Capture";         //    キャプチャした画像を表示するウィンドウの名前
char windowNameSkin[] = "Skin";                //    肌色抽出画像を表示するウィンドウの名前
char windowNameConvexHull[] = "ConvexHull";    //    ConnvexHull画像を表示するウィンドウの名前

//
// ウィンドウを作成する
//
void createWindows() {
    cvNamedWindow( windowNameCapture );
    cvNamedWindow( windowNameSkin );
    cvNamedWindow( windowNameConvexHull );
}

//
//    肌色を抽出する
//
//    引数:
//        frameImage : キャプチャした画像用IplImage
//        hsvImage   : HSV画像用IplImage
//        skinImage  : 肌色抽出画像用IplImage
//
void extractSkinColor( IplImage *frameImage, IplImage *hsvImage, IplImage *skinImage ) {
    CvScalar color;        //    HSV表色系で表した色
    unsigned char h;    //    H成分
    unsigned char s;    //    S成分
    unsigned char v;    //    V成分

    //    BGRからHSVに変換する
    cvCvtColor( frameImage, hsvImage, CV_BGR2HSV );

    //肌色抽出
    for( int x = 0; x < skinImage->width; x++ ) {
        for( int y = 0 ; y < skinImage->height; y++ ) {

            color = cvGet2D( hsvImage, y, x );
            h = color.val[0];
            s = color.val[1];
            v = color.val[2];

            if( h <= HMAX && h >= HMIN &&
                s <= SMAX && s >= SMIN &&
                    v <= VMAX && v >= VMIN ) {
                //    肌色の場合
                cvSetReal2D( skinImage, y, x, 255 );
            } else {
                cvSetReal2D( skinImage, y, x, 0 );
            }
        }
    }
}

//
//    欠損領域を補間する
//
//    引数:
//        skinImage : 肌色抽出画像用IplImage
//        temp      : 一時保存用IplImage
//
void interpolate( IplImage *skinImage, IplImage *temp ) {
    //膨張をITERATIONS回行う
    cvDilate( skinImage, temp, NULL, ITERATIONS );

    //収縮をITERATIONS回行う
    cvErode( temp, skinImage, NULL, ITERATIONS );
}

//
//    最大領域(手領域)の抽出を行う
//
//    引数:
//        skinImage       : 肌色抽出画像用IplImage
//        label           : ラベリングした結果
//        convexHullImage : ConvexHull画像用IplImage
//
//    戻り値:
//        手領域の面積
//
int pickupMaxArea(IplImage *skinImage, IplImage *label, IplImage *convexHullImage ) {

    int handarea = 0;    //    手領域の面積

    for(int x = 0; x < skinImage->width; x++ ) {
        for( int y=0; y < skinImage->height; y++ ) {
            if( cvGetReal2D( label, y, x ) == 1 ) {
                //    最大領域だった場合
                handarea++;
                cvSet2D( convexHullImage, y, x, CV_RGB( 255, 255, 255 ) );
            } else {
                cvSetReal2D( skinImage, y, x, 0 );
                cvSet2D( convexHullImage, y, x, CV_RGB( 0, 0, 0 ) );
            }
        }
    }
    return handarea;
}

//
//    ConvexHullを生成する
//
//    引数:
//        skinImage   : 肌色抽出画像用IplImage
//        handarea    : 手領域の面積(点の数)
//        handpoint   : 手領域内の点の座標配列へのポインタ
//        hull        : ConvexHullの頂点のhandpointにおけるindex番号へのポインタ
//        pointMatrix : 手領域用行列へのポインタ
//        hullMatrix  : ConvexHull用行列へのポインタ
//
void createConvexHull(IplImage *skinImage, int handarea, CvPoint **handpoint, int **hull,
                      CvMat *pointMatrix, CvMat *hullMatrix ) {
    int i=0;

    //    ConvexHullを計算するために必要な行列を生成する
    *handpoint=( CvPoint * )malloc( sizeof( CvPoint ) * handarea );
    *hull = ( int * )malloc( sizeof( int ) * handarea );
    *pointMatrix = cvMat( 1, handarea, CV_32SC2, *handpoint );
    *hullMatrix = cvMat( 1, handarea, CV_32SC1, *hull );

    for( int x = 0; x < skinImage->width; x++ ) {
        for(  int y = 0; y < skinImage->height; y++ ) {
            if( cvGetReal2D( skinImage, y, x ) == 255 ) {
                ( *handpoint )[i].x = x;
                ( *handpoint )[i].y = y;
                i++;
            }
        }
    }

    //    ConvexHullを生成する
    cvConvexHull2( pointMatrix, hullMatrix, CV_CLOCKWISE, 0 );
}

//
//    ConvexHullを描画する
//
//    引数:
//        convexHullImage : ConvexHull画像用IplImage
//        handpoint       : 手領域内の点の座標配列
//        hull            : ConvexHullの頂点のhandpointにおけるindex番号
//        hullcount       : ConvexHullの頂点の数
//
void drawConvexHull(IplImage *convexHullImage, CvPoint *handpoint, int *hull, int hullcount ) {
    CvPoint pt0 = handpoint[hull[hullcount-1]];
    for( int i = 0; i < hullcount; i++ ) {
        CvPoint pt = handpoint[hull[i]];
        cvLine( convexHullImage, pt0, pt, CV_RGB( 0, 255, 0 ) );
        pt0 = pt;
    }
}

//
//    ConvexHull内の面積を求める
//
//    引数:
//        convexHullImage : ConvexHull画像用IplImage
//        handpoint       : 手領域内の点の座標配列
//        hull            : ConvexHullの頂点のhandpointにおけるindex番号
//        hullcount       : ConvexHullの頂点の数  
//
//    戻り値:
//        ConvexHull内の面積
//
int calcConvexHullArea( IplImage *convexHullImage, CvPoint *handpoint, int *hull, int hullcount ) {

    //    ConvexHullの頂点からなる行列を生成
    CvPoint *hullpoint = ( CvPoint * )malloc( sizeof( CvPoint ) * hullcount );
    CvMat hMatrix = cvMat( 1, hullcount, CV_32SC2, hullpoint );
    for( int i = 0; i < hullcount; i++ ) {
        hullpoint[i]=handpoint[hull[i]];
    }

    //    ConvexHull内の点の数を数える
    int hullarea = 0;
    for( int x = 0; x < convexHullImage->width; x++ ) {
        for( int y = 0;y < convexHullImage->height; y++ ) {
            if( cvPointPolygonTest( &hMatrix, cvPoint2D32f( x, y ), 0 ) > 0) {
                hullarea++;
            }
        }
    }

    free( hullpoint );
    return hullarea;
}

//
//    ジャンケンの判定を行う
//
//    引数:
//        handarea : 手領域の面積
//        hullarea : ConvexHull内の面積
//
void decide( int handarea, int hullarea ) {
    double ratio;    //    ConvexHull内の面積に対する手領域の面積の割合

    ratio=handarea / ( double )hullarea;    
    printf( "Ratio = %lf\n", ratio );

    if( ratio >= ROCKMIN && ratio <= ROCKMAX ) {
        printf( "グー\n" );
    } else if( ratio >= SCISSORMIN && ratio <= SCISSORMAX ) {
        printf( "チョキ\n" );
    } else if( ratio >= PAPERMIN && ratio <= PAPERMAX ) {
        printf( "パー\n" );
    }
}

int main( int argc, char **argv ) {
    int key;                    //    キー入力用の変数
    CvCapture *capture = NULL;    //    カメラキャプチャ用の構造体

    //    カメラを初期化する
    if( ( capture = cvCreateCameraCapture( CV_CAP_ANY ) ) == NULL ) {
        //    カメラが見つからなかった場合
        printf( "カメラが見つかりません\n" );
        return -1;
    }
    double w = 640, h = 480;
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, w);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, h);


    IplImage *frameImage = cvQueryFrame( capture );    //    キャプチャ画像用IplImage

    if (frameImage == NULL) {
        printf("キャプチャに失敗しました。\n");
    }

    IplImage *hsvImage;
    IplImage *convexHullImage;
    IplImage *skinImage;
    IplImage *temp;
    IplImage *label;

    //    画像を生成する
    hsvImage = cvCreateImage( cvGetSize( frameImage ),IPL_DEPTH_8U,3);        //    HSV画像用IplImage
    convexHullImage = cvCreateImage( cvGetSize( frameImage ),IPL_DEPTH_8U,3 );//    ConvexHull画像用IplImage
    skinImage = cvCreateImage( cvGetSize( frameImage ),IPL_DEPTH_8U,1);        //    肌色抽出画像用IplImage
    temp = cvCreateImage( cvGetSize( frameImage ),IPL_DEPTH_8U,1);            //    一時保存用IplImage
    label = cvCreateImage( cvGetSize( frameImage ),IPL_DEPTH_16S,1);            //    ラベル結果保存用IplImage

    //    ウィンドウを生成する
    createWindows();

    while( 1 ){

        frameImage = cvQueryFrame( capture );

        //    肌色を抽出する
        extractSkinColor( frameImage, hsvImage, skinImage );

        //    欠損領域を補間する
        interpolate( skinImage, temp );

        //    ラベリングを行う
        Label *labeling = createLabeling();
        exec( labeling, skinImage, label, true, IGNORE_SIZE );

        if( getNumOfResultRegions( labeling ) > 0 ) {
            //    IGNORE_SIZEよりも大きな領域があった場合

            int handarea;        //    手領域の面積
            int hullarea;        //    ConvexHull内の面積
            int hullcount;        //    ConvexHullの頂点の数
            CvPoint *handpoint;    //    手領域内の点の座標配列
            int *hull;            //    ConvexHullの頂点のhandpointにおけるindex番号
            CvMat pointMatrix;    //    手領域用行列
            CvMat hullMatrix;    //    ConvexHull用行列

            //    最大領域(手領域)の抽出を行う
            handarea = pickupMaxArea( skinImage, label, convexHullImage );

            //    ConvexHullを生成する
            createConvexHull( skinImage, handarea, &handpoint, &hull, &pointMatrix, &hullMatrix );

            hullcount = hullMatrix.cols;

            //    ConvexHullを描画する
            drawConvexHull( convexHullImage, handpoint, hull, hullcount );

            //    ConvexHull内の面積を求める
            hullarea = calcConvexHullArea( convexHullImage, handpoint,hull, hullcount );

            //    ジャンケンの判定を行う
            decide( handarea, hullarea );

            //    メモリを解放する
            free( handpoint );
            free( hull );
        } else {
            //    画像を初期化する
            cvSetZero( convexHullImage );
        }

        releaseLabeling( labeling );

        //if ( skinImage->origin == 0 ) {
        //    // 左上が原点の場合
        //    cvFlip( skinImage, skinImage, 0 );
        //}
        //if ( convexHullImage->origin == 0 ) {
        //    // 左上が原点の場合
        //            ( convexHullImage, convexHullImage, 0 );
        //}

        //    画像を表示する
        cvShowImage( windowNameCapture, frameImage );
        cvShowImage( windowNameSkin, skinImage );
        cvShowImage( windowNameConvexHull, convexHullImage );

        //    キー入力判定
        key = cvWaitKey( 10 );
        if( key == 'q' ) {
            //    'q'キーが押されたらループを抜ける
            break;
        }
    }

    //    キャプチャを解放する
    cvReleaseCapture( &capture );
    //    メモリを解放する
    cvReleaseImage( &hsvImage );
    cvReleaseImage( &skinImage );
    cvReleaseImage( &temp );
    cvReleaseImage( &label );
    cvReleaseImage( &convexHullImage );
    //    ウィンドウを破棄する
    cvDestroyWindow( windowNameCapture );
    cvDestroyWindow( windowNameSkin );
    cvDestroyWindow( windowNameConvexHull );

    return 0;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正の依頼

  • tiitoi

    2018/11/28 14:13 編集

    その書籍が出た当時の OpenCV 1.1 を導入すれば動くとは思いますが、今の OpenCV 3 を入れて書籍のプログラムを動かそうとしているのだとしたら、当時からは API 等一部変わったりしているので動かない可能性もあります。(実際に確認したわけではないですが)

    キャンセル

  • tiitoi

    2018/11/28 14:13 編集

    古いバージョン OpenCV を使わなければならない特殊な事情があるなら別ですが、そうでなく持っている書籍がたまたま OpenCV 1 のものだったからという理由であれば、その書籍で勉強するのではなく、OpenCV 3 に対応した書籍を購入されたほうがよいです。理由は上記 API は今は非推奨で OpenCV3までは互換性保持のためまだ残っていますが、今後のバージョンで削除されるからです。

    キャンセル

  • ShiiTakumi

    2018/11/28 14:17

    遊びたいサンプルがあっただだで、特殊な事情はございません(;^ω^)手元には全てのバージョンがありますので、書籍については心配ございません。アドバイスありがとうございます。また、 OpenCV 1.1を導入してサンプルを実行しているのですが、投稿通りでダメでした。もうあきらめようかなと思っているところです。

    キャンセル

まだ回答がついていません

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

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

関連した質問

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