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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

11846閲覧

C++での画面上のRGB値取得の高速化

YNN35

総合スコア22

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2018/12/19 05:46

実現したいこと

高速で画面上の指定座標上のRGB値を取得する(欲張った目標としては毎秒10000ピクセル程度の速度での解析、最低でも毎秒1500~3000ピクセル)
##問題点

以下のサンプルコードを参考に色々いじって30x16ピクセル分を取得するプログラムを作成したのですが、GetPixelのせいでたったそれだけを解析するのに五秒くらい時間がかかってしまいます。(printfもなにげに処理に時間を使うのでそれを取り除いた場合でも同じくらい時間がかかります)
bmp画像上のRGBを取得するプログラムをメモリに展開し、解析するプログラムでやったことがありますがその時は全く処理に時間を必要としなかったので頑張ればいけるのではないのかなと思っています。

C++

1#include <windows.h> 2#include <stdio.h> 3#include<string> 4#include<iostream> 5using namespace std; 6 7int main(void) 8{ 9 int exit; 10 11 HWND hWnd; 12 HDC hdc; 13 COLORREF clr; 14 INT x, y; 15 x = 1; 16 y = 1; 17 18 hWnd = GetDesktopWindow(); 19 hdc = GetWindowDC(hWnd); 20 clr = GetPixel(hdc, x, y); 21 ReleaseDC(hWnd, hdc); 22 printf("RGB = (%d,%d,%d)\n", 23 GetRValue(clr), 24 GetGValue(clr), 25 GetBValue(clr)); 26 27 cin >> exit;//なぜかキーを入力したら終了しますと表示されずに勝手に終了してしまうための対策用 28 return 0; 29}

【参考】Yahoo知恵袋

試したこと

処理の並列化をしたら少しは早くなるのでは?と思いやろうとしたのですがなぜかOpenMPを有効化にして、とりあえず動作確認でサンプルコードで動かしてみたのですが、”2フェーズの名前参照は、C++/CLI、C++/CX、OpenMP ではサポートされていません。/Zc:twoPhase- を使用します”と警告が出てきてったので諦めました...(このことについても質問したいのですが今回は大丈夫です。)

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

VisualStuido2017,Windws10

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

高速化のポイントは他の方がおっしゃっている通り一旦メモリにキャプチャしてから値を取れば良いです。

Visual StudioであればATLのCImageというDIBSECTIONをラップしたクラスが使えますので、
これを使って実現してやると楽です。

32x32でキャプチャした値を出力する例:

cpp

1// プロジェクト作成時にATLの使用にチェックを入れています。 2 3#include "stdafx.h" 4#include <atlimage.h> 5#include <iostream> 6#include <stdio.h> 7 8int main() 9{ 10 // キャプチャしたいデスクトップの矩形 11 CRect targetRect(0, 0, 32, 32); 12 13 HWND hWnd = GetDesktopWindow(); 14 HDC hWndDC = GetDC(hWnd); 15 16 // DIBSECTIONの作成 17 CImage img; 18 img.Create(targetRect.Width(), targetRect.Height(), 24); 19 CImageDC imgDC(img); 20 21 // デスクトップ画像をDIBSECTIONへ転送 22 BitBlt(imgDC, 0, 0, targetRect.Width(), targetRect.Height(), hWndDC, targetRect.left, targetRect.top, SRCCOPY); 23 24 // 各種開放 25 ReleaseDC(hWnd, hWndDC); 26 27 // ここからのアクセスは、もう少し高速化できないこともない 28 for (int y = 0; y < img.GetHeight(); y++) { 29 for (int x = 0; x < img.GetWidth(); x++) { 30 COLORREF color = img.GetPixel(x, y); 31 printf("[%d,%d] RGB(%d, %d, %d)\n", x + targetRect.left, y + targetRect.top, GetRValue(color), GetGValue(color), GetBValue(color)); 32 } 33 } 34 35 return 0; 36} 37

投稿2018/12/19 07:59

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YNN35

2018/12/19 11:36

回答ありがとうございます!サンプルコードまで書いて頂きとてもありがたいです!ただATLのプロジェクトを作成したのはいいものの、どこにそのサンプルコードを書き込めばいいのかわからないのですがどうか教えていただけませんでしょうか...? 空のプロジェクトを作成した際はソースファイル直下にソースをかけばいいのですがこの場合、ソースファイル直下にそちらのサンプルコードを配置したらCImageのところがしっかり処理されず園周辺でエラーが出てきてしまいます… 初歩的な質問申し訳ありませんが、どうかよろしくおねがいします。
takabosoft

2018/12/20 01:01

ATLのプロジェクトではなく、普通にC++ Win32コンソールアプリケーションのテンプレートで新規作成すればOKです(テンプレ内のATLのチェックは不要でした)。
YNN35

2018/12/21 07:57

なるほど!ありがとうございます! しっかり動きました!!! いろいろ初心者なりに調べた結果エラーも出てましたが解消しました!!ありがとうございます!(teratailを使ったばっかりで初めて質問しましたが予想以上にいい回答がたくさん帰ってきて驚いていますw)
guest

0

GetPixelのせいでたったそれだけを解析するのに五秒くらい時間がかかってしまいます。
(欲張った目標としては毎秒10000ピクセル程度の速度での解析、最低でも毎秒1500~3000ピクセル)

Windows API GetPixel関数によるRGB値アクセスは、ものすごく重たい処理です。代わりに GetDIBits関数 で自身が管理するメモリ領域上へとビットマップデータ展開し、通常のメモリアクセスとしてRGB値取得するのが最も効率的になります。(経験則からの推測ですが、変更後は目標速度を余裕で越えられると思います。)

デバイスコンテキスト(HDC)からデバイス非依存ビットマップ(DIB)への変換は、下記ページなどを参考にください:

投稿2018/12/19 06:08

yohhoy

総合スコア6189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

GetPixel()で領域全体を調べるというのは遅いと思います。

「GetDesktopWindow CreateCompatibleDC BitBlt」あたりでググって、まずスクショのように自分側(自プロセス側)のメモリに画像を取り込むのが良いです。あとはbmp扱うのと同じようなものです。

投稿2018/12/19 06:03

daisuke7

総合スコア1563

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Windows 7以上ではGetPixelがかなり遅くなってしまったとのことで、いったんメモリにBitBltでコピーしてからそっちを読み出すという方法もあるとのことです。

投稿2018/12/19 05:59

maisumakun

総合スコア145123

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YNN35

2018/12/19 08:50

なるほど。BitBltという物があったのですか。ただいろいろ調べて様々な記事を読んでもC++初心者の自分には難易度が高かったのでどうか助言をいただきたいのですが、freadの場合第一因数で記憶先のメモリを指定しますがBitBltではどのようにすればいいのでしょうか...? もっと簡単に言うと fread(p, 1, BMPREAD, fp); // bmpに書き込まれているデータをメモリに展開する BMPINFO *bmpinf; RGBDATA *rgbdat; bmpinf = (BMPINFO*)(p + 2); rgbdat = (RGBDATA*)(p + (bmpinf->offset)); というプログラムでの”p”をどのように書き換えたら良いのでしょうか..?(ついでにBMPファイルのRGBを解析するプログラムも大半サンプルコードを使わせていただきました)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問