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

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

ただいまの
回答率

89.21%

Win32APIを用いた動画として映るデスクトップキャプチャのプログラミングについて

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 3,872

watarusugimoto

score 49

デスクトップキャプチャを行い、その画像をOpenCVで画像解析したい

前段として、Win32APIを用いてデスクトップキャプチャのみのプログラムを作成しました。
これが完成したら、OpenCVへビットマップを渡してそれを解析するという方法を取ろうと考えています。

このプログラミングで動きますがちらつきが生じています。
このような方法でデスクトップキャプチャをすることで良いのか聞きたいと思います。
より効率的な方法がありましたら教えてください。

該当のソースコード

#include <windows.h>

TCHAR szClassName[] = TEXT("text01");    //TCHARはUNICODEとASCIIに対応するためのマクロ

//ウィンドウプロシージャ(コールバック関数)
LRESULT CALLBACK WndProc
(
    HWND hWnd,        //親ウィンドウのハンドル
    UINT msg,        //
    WPARAM wp,        //
    LPARAM lp        //アプリケーションで定義された値
)
{
    HDC hdc;
    PAINTSTRUCT ps;
    static BITMAPINFO bmpInfo;
    static LPDWORD lpPixel;
    static HBITMAP hBitmap;
    static HDC hMemDC;

    HWND desktop;
    RECT rc;
    static int width, height;

    switch (msg)
    {
    case WM_CREATE:
        //スクリーンの情報を得る
        desktop = GetDesktopWindow();
        GetWindowRect(desktop, &rc);
        width = rc.right;
        height = rc.bottom;

        //DIBの情報を設定する
        bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmpInfo.bmiHeader.biWidth = width;
        bmpInfo.bmiHeader.biHeight = height;
        bmpInfo.bmiHeader.biPlanes = 1;
        bmpInfo.bmiHeader.biBitCount = 32;
        bmpInfo.bmiHeader.biCompression = BI_RGB;

        //DIBSection作成
        //親ウィンドウのハンドルからデバイスコンテキストを取得
        hdc = GetDC(hWnd);
        //DIBの作成
        hBitmap = CreateDIBSection(hdc, &bmpInfo, DIB_RGB_COLORS, (void**)&lpPixel, NULL, 0);
        //メモリデバイスコンテキストの作成
        hMemDC = CreateCompatibleDC(hdc);
        SelectObject(hMemDC, hBitmap);
        ReleaseDC(hWnd, hdc);

        //スクリーンをDIBSectionにコピー
        hdc = GetDC(desktop);
        BitBlt(hMemDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
        ReleaseDC(desktop, hdc);

        //ウィンドウを一度再描画のために無効空間を発生させる
        InvalidateRect(hWnd,NULL,TRUE);

        return 0;

    case WM_DESTROY:
        DeleteDC(hMemDC);
        DeleteObject(hBitmap);//BMPを削除した時、lpPixelも自動的に開放される
        PostQuitMessage(0);

        return 0;

    case WM_PAINT:
        //再度desktopを取得
        desktop = GetDesktopWindow();
        //デバイスコンテキストハンドルを取得
        hdc = GetDC(desktop);
        //hMemDCへコピー
        BitBlt(hMemDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
        ReleaseDC(desktop, hdc);

        hdc = BeginPaint(hWnd, &ps);
        //表画面へ転送
        BitBlt(hdc, 0, 0, width, height, hMemDC, 0, 0, SRCCOPY);
        EndPaint(hWnd, &ps);

        //無効空間を発生させてさらにWM_PAINTを呼び出す。
        InvalidateRect(hWnd, NULL, TRUE);

        return 0;
    }
    return DefWindowProc(hWnd,msg,wp,lp);
}


//ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst) 
{
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);                                                                                            //構造体のサイズ
    wc.style = CS_HREDRAW | CS_VREDRAW;                                                                                        //クラスのスタイル
    wc.lpfnWndProc = WndProc;                                                                                                //プロシージャ名
    wc.cbClsExtra = 0;                                                                                                        //補助メモリ
    wc.cbWndExtra = 0;                                                                                                        //補助メモリ
    wc.hInstance = hInst;                                                                                                    //インスタンス
    wc.hIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);        //アイコン
    wc.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);        //カーソル
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);                                                                    //背景ブラシ
    wc.lpszMenuName = NULL;                                                                                                    //メニュー名
    wc.lpszClassName = szClassName;                                                                                            //クラス名
    wc.hIconSm = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);    //小さいアイコン

    return(RegisterClassEx(&wc));
}


//ウィンドウの生成
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
    HWND hWnd;

    hWnd = CreateWindow
    (
        szClassName,                                //クラス名
        TEXT("猫でもわかるWindowsプログラミング"),    //ウィンドウ名
        WS_OVERLAPPEDWINDOW,                        //ウィンドウスタイル
        CW_USEDEFAULT,                                //x位置
        CW_USEDEFAULT,                                //y位置
        CW_USEDEFAULT,                                //ウィンドウ幅
        CW_USEDEFAULT,                                //ウィンドウ高さ
        NULL,                                        //親ウィンドウのハンドル 親を作るときはNULL
        NULL,                                        //メニューハンドル クラスメニューを使うときはNULL
        hInst,                                        //インスタンスハンドル
        NULL                                        //ウィンドウ作成データ
    );
    if (!hWnd)
        return FALSE;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return TRUE;
}


//Windowsプログラムのエントリーポイント
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL bRet;

    if (!InitApp(hCurInst))
        return FALSE;

    if (!InitInstance(hCurInst, nCmdShow))
        return FALSE;

    //メッセージを取得
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (bRet == -1)
        {
            break;
        }
        else
        {
            TranslateMessage(&msg);        //メッセージを変換
            DispatchMessage(&msg);        //メッセージを送出
        }
    }
    return (int)msg.wParam;
}

試したこと

ウィンドウを作成した直後に、全画面について無効領域を作り、WM_PAINTというメッセージを発生させています。
WM_PAINT内でも、さらに全画面で無効領域を発生させ、WM_PAINTというメッセージを発生させ、WM_PAINTのループを作ることで動画として映るデスクトップキャプチャを作成しています。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

WM_PAINT内でも、さらに全画面で無効領域を発生させ、WM_PAINTというメッセージを発生させ

↑ これがちらつく理由です。

WM_TIMER などタイマーを利用して、画像を取得するように変えてみてください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/12/12 16:18

    ありがとうございます。
    WM_TIMERを使ったプログラミングに変更し、再度新たに質問させていただきたいと思います。

    キャンセル

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

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