cv::VideoCapture capのcv::CAP_PROP_FRAME_WIDTHの中身とどのようにPCのシステムに働くのか知りたいです。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,311

carnage0216

score 133

cv::VideoCapture cap(0);
cap.set(cv::CAP_PROP_FRAME_WIDTH,  幅);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 高さ);


はopencvから提供されたソースコードです。出力ウィンドのサイズを変える働きをします。
以上のソースコードに関しての質問なのですが、載せましたプログラム

 * eye-tracking.cpp:
 * Eye detection and tracking with OpenCV
 *
 * This program tries to detect and tracking the user's eye with webcam.
 * At startup, the program performs face detection followed by eye detection 
 * using OpenCV's built-in Haar cascade classifier. If the user's eye detected
 * successfully, an eye template is extracted. This template will be used in 
 * the subsequent template matching for tracking the eye.
 */
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/objdetect/objdetect.hpp>

cv::CascadeClassifier face_cascade;
cv::CascadeClassifier eye_cascade;

/**
 * Function to detect human face and the eyes from an image.
 *
 * @param  im    The source image
 * @param  tpl   Will be filled with the eye template, if detection success.
 * @param  rect  Will be filled with the bounding box of the eye
 * @return zero=failed, nonzero=success
 */
int detectEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect)
{
    std::vector<cv::Rect> faces, eyes;
    face_cascade.detectMultiScale(im, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cv::Size(30,30));

    for (int i = 0; i < faces.size(); i++)
    {
        cv::Mat face = im(faces[i]);
        eye_cascade.detectMultiScale(face, eyes, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cv::Size(20,20));

        if (eyes.size())
        {
            rect = eyes[0] + cv::Point(faces[i].x, faces[i].y);
            tpl  = im(rect);
        }
    }

    return eyes.size();
}

/**
 * Perform template matching to search the user's eye in the given image.
 *
 * @param   im    The source image
 * @param   tpl   The eye template
 * @param   rect  The eye bounding box, will be updated with the new location of the eye
 */
void trackEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect)
{
    cv::Size size(rect.width * 2, rect.height * 2);
    cv::Rect window(rect + size - cv::Point(size.width/2, size.height/2));

    window &= cv::Rect(0, 0, im.cols, im.rows);

    cv::Mat dst(window.width - tpl.rows + 1, window.height - tpl.cols + 1, CV_32FC1);
    cv::matchTemplate(im(window), tpl, dst, CV_TM_SQDIFF_NORMED);

    double minval, maxval;
    cv::Point minloc, maxloc;
    cv::minMaxLoc(dst, &minval, &maxval, &minloc, &maxloc);

    if (minval <= 0.2)
    {
        rect.x = window.x + minloc.x;
        rect.y = window.y + minloc.y;
    }
    else
        rect.x = rect.y = rect.width = rect.height = 0;
}

int main(int argc, char** argv)
{
    // Load the cascade classifiers
    // Make sure you point the XML files to the right path, or 
    // just copy the files from [OPENCV_DIR]/data/haarcascades directory
    face_cascade.load("haarcascade_frontalface_alt2.xml");
    eye_cascade.load("haarcascade_eye.xml");

    // Open webcam
    cv::VideoCapture cap(0);

    // Check if everything is ok
    if (face_cascade.empty() || eye_cascade.empty() || !cap.isOpened())
        return 1;

    // Set video to 320x240
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 320);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 240);

    cv::Mat frame, eye_tpl;
    cv::Rect eye_bb;

    while (cv::waitKey(15) != 'q')
    {
        cap >> frame;
        if (frame.empty())
            break;

        // Flip the frame horizontally, Windows users might need this
        cv::flip(frame, frame, 1);

        // Convert to grayscale and 
        // adjust the image contrast using histogram equalization
        cv::Mat gray;
        cv::cvtColor(frame, gray, CV_BGR2GRAY);

        if (eye_bb.width == 0 && eye_bb.height == 0)
        {
            // Detection stage
            // Try to detect the face and the eye of the user
            detectEye(gray, eye_tpl, eye_bb);
        }
        else
        {
            // Tracking stage with template matching
            trackEye(gray, eye_tpl, eye_bb);

            // Draw bounding rectangle for the eye
            cv::rectangle(frame, eye_bb, CV_RGB(0,255,0));
        }

        // Display video
        cv::imshow("video", frame);
    }

    return 0;
}


の91~93行目の

cv::VideoCapture cap(0);
cap.set(cv::CAP_PROP_FRAME_WIDTH,  幅);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 高さ);



プログラムのヘッダファイル
<opencv2/imgproc/imgproc.hpp>
<opencv2/highgui/highgui.hpp>
<opencv2/objdetect/objdetect.hpp>のいずれかにcv::CAP_PROP_FRAME_WIDTHとcv::CAP_PROP_FRAME_HEIGHTの定義などが標準関数で書いてあるのでしょうか?

コンパイルする際に標準関数でないとコンパイル出来ないような気もしますが。

もう一つ質問があるのですが、以上に書いた

cv::VideoCapture cap(0);
cap.set(cv::CAP_PROP_FRAME_WIDTH,  幅);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 高さ);


がWindowsのウィンドの大きさに関与したシステムのデータに働くため出力ウィンドのサイズを変えることができるのでしょうか?

長文ですが、どうかよろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • carnage0216

    2018/02/11 08:57

    こちらこそ、申し訳ありませんでした。epistemeさんにはいつも助けて頂き、感謝しております。

    キャンセル

  • yumetodo

    2018/02/12 14:38 編集

    無宣言のマルチポストは個人的には即BANものだと思っています(宣言してやるなら許す人です、私もここで質問してやっぱり本家StackOveflowに投げるとかやるので)。「umetodoさんにもお世話になっているので複雑ですが、人の質問を勝手に載せるのはやめてください。 」ってWeb上の公開されているページのURLを貼ることに許諾が必要というのは王政復古感ある話ですね、ばかばかしい。URLは著作物ではないのだから著作権法の定める引用を持ち出すまでもない。teratailと日本語版StackOveflowは回答者がかぶっているのでマルチポストはすぐわかります。

    キャンセル

  • carnage0216

    2018/02/12 21:33

    わたしはyumetodoさんほど賢くないのでよくわかりませんが、気分を害されたなら悪いことをしました。ごめんなさい。

    キャンセル

回答 2

checkベストアンサー

0

後学のためにこういうときの調べ方を。

幸いOpenCVはdoxygenによってドキュメントがまともに生成されているプロジェクトなので、まず公式ドキュメントを見ます。
https://docs.opencv.org/
から利用しているOpenCVのバージョンを選びます。
ex.) OpenCV 3.4ならhttps://docs.opencv.org/3.4.0/

検索枠に試しにCAP_PROP_FRAME_WIDTHと入れてみると選択肢が出ます。今回は一つだけですね。
OpenCV: Flags for video I/O
するとVideoCapturePropertiesというenum定数だとわかるわけです。

Width of the frames in the video stream. 

なんていう説明がかかれていますね。

ついでにSee alsoと書かれているのでVideoCapture::set()も見てみましょうか。

ParametersのpropIdに

Property identifier from...

とあります。メンバ関数名がsetだけじゃ何をセットするやらわからんので第1引数はそれを識別するものだ、ということがわかりますね。

Noteに

Even if it returns true this doesn't ensure that the property value has been accepted by the capture device. See note in VideoCapture::get()

とかいう脅し文句があるので急いでVideoCapture::get()も見に行きましょう。

すると

The returned value might be different from what really used by the device or it could be encoded using device dependant rules (eg. steps or percentage). Effective behaviour depends from device driver and API Backend 

とあります。まあそりゃそうだよなって内容ですね、たとえばVFRな映像にcv::CAP_PROP_FPSをidentifierにsetやらgetやらしても意味のある結果はどう考えても産まないですよね。

そんな感じで公式ドキュメント眺めるとええぞ!みたいな話でした。


しかしこの整数の必要性は何なのでしょうか?

という疑問が出るだろうと思って

メンバ関数名がsetだけじゃ何をセットするやらわからんので第1引数はそれを識別するものだ、ということがわかりますね。

と書いたんですが不十分だったようなので補足します。まあ別にset/getっていう関数にenumを渡して動的ディスパッチしなくても、例えばset_cap_prop_fps()みたいな関数を作る実装にしても良かったと思うんですが、シンボル名を減らしたかったのか何なのか、とにかくOpenCVの開発者たちはその選択肢を選ばなかったようです。


CV_CAP_PROP_FRAME_WIDTHの正体についてはCamera.Handle,"Width", &nTempを引数とする関数PvAttrUint32Getとしてもいいのでしょうか?

だめです。落ち着いて上で取り上げたVideoCapture::set()を読んでください。

Reading / writing properties involves many layers. Some unexpected result might happens along this chain.
VideoCapture -> API Backend -> Operating System -> Device Driver -> Device Hardware

とあります。いいですか?API Backendですよ?で、ググればわかるのですでにお調べのことと思いますが、PvAttrUint32GetっていうのはPvAPIのものです。他のAPIの場合も当然ありえます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/02/10 18:55

    すいませんでした。
    もう一度、まとめてから改めて質問させて頂きます。

    キャンセル

  • 2018/02/10 20:02

    もしかしたら既に答えて頂いているかも知れませんが、なぜcv::VideoCapture cap(0);の
    cap.set(cv::CAP_PROP_FRAME_WIDTH, 幅);
    cap.set(cv::CAP_PROP_FRAME_HEIGHT, 高さ);
    に関して、CAP_PROP_FRAME_WIDTH =3,
    CAP_PROP_FRAME_HEIGHT =4,
    と定義がありますが
    定数3,4の情報のみで幅や高さが変えられるのか全く理解できません。なぜでしょうか?
    CAP_PROP_FRAME_WIDTH の定数3が別の何かに働くのですか?
    定数3.4のみでどうやって幅や高さを設定できるのか。
    CAP_PROP_FRAME_WIDTH は定数3でありますが、その3がどのように作用してサイズの幅をどのように決めているのか知りたいです。

    キャンセル

  • 2018/02/10 20:08 編集

    cap.set(なにを, どんだけ); ってことなんだが...

    // たとえば
    class 長方形 {
    int 幅;
    int 高さ;
    public:
    void set(int なにを, int どんだけ) {
    if ( なにを == 0 ) { 幅 = どんだけ; }
    if ( なにを == 1 ) { 高さ = どんだけ; }
    ...

    なんかわからんとこある?

    キャンセル

0

cv::CAP_PROP_FRAME_WIDTHとcv::CAP_PROP_FRAME_HEIGHTの定義などが標準関数で書いてあるのでしょうか?

それらはただの整数です。opencv/videoio.hpp #L128

enum VideoCaptureProperties {
       CAP_PROP_POS_MSEC       =0, //!< Current position of the video file in milliseconds.
       CAP_PROP_POS_FRAMES     =1, //!< 0-based index of the frame to be decoded/captured next.
       CAP_PROP_POS_AVI_RATIO  =2, //!< Relative position of the video file: 0=start of the film, 1=end of the film.
       CAP_PROP_FRAME_WIDTH    =3, //!< Width of the frames in the video stream.
       CAP_PROP_FRAME_HEIGHT   =4, //!< Height of the frames in the video stream.
       ...

あくまでもどのプロパティを参照するか示す役割しかありませんので。
『3番の棚に書類あるじゃん、これに置き換えといて!』みたいな。


Windowsのウィンドの大きさに関与したシステムのデータに働くため出力ウィンドのサイズを変えることができるのでしょうか?

以前の私の回答にepistemeさんがコメントされていますね。

違うってば。
VideoCapture は Web-cameraとかが作るframeの連続から1-frame切り取るクラスで、
cap >> image; によって切り取られた1-frameがimageに取り込まれます。
なので cap.set(...) は切り取られた cv::Mat imageの幅/高さ(つまり行列の列数/行数)を決定します。
画面に書いてるのは imshow("video", image)、 関数 imshow が、与えたimageの幅/高さに応じてウィンドウのclient-areaを設定してます。

ウィンドウのサイズを変えているわけでなく、
取得する画像の大きさが変わることで、追随してウィンドウのサイズが変わるだけです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/02/09 19:25

    いつもどうもありがとうございます。あの解釈が間違っているかもしれませんが、
    VideoCapturePropertiesのCAP_PROP_FRAME_WIDTH =3,やCAP_PROP_FRAME_HEIGHT =4はあくまで目印みたいなもので、実際はVideoCaptureの関数imshowがclient-areaに働くことで出力ウィンドウのサイズを変えることができるということでしょうか?

    キャンセル

  • 2018/02/09 19:30

    imshowはVideoCaptureのメソッドではないですよ。
    VideoCaptureのインスタンスはあくまで1フレームを持ってくるだけ、imshowはあくまで画像(Mat)を画面に出力するだけ、それらの働きは独立です。

    キャンセル

  • 2018/02/09 19:33

    前もってVideoCaptureのプロパティを書き換えることで、持ってくる画像の大きさを変えているんです。
    imshowは指定された画像をよしなに表示しているだけです。
    なお、表示ウィンドウ自体には別のプロパティがあります。

    キャンセル

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

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

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

  • トップ
  • Cに関する質問
  • cv::VideoCapture capのcv::CAP_PROP_FRAME_WIDTHの中身とどのようにPCのシステムに働くのか知りたいです。