画像処理ソフトの研究をc言語で行っています。
GUIの導入を目指してVC++の勉強を始めたのですが、RAW画像をうまく表示できず困っています。
現在練習と言うことで、スクロールバーの値によって画像を二値化して表示する処理を行っています。
表示部分を以下のように書いた(ほとんど本を丸写したので意味もちゃんとわかっていませんが)のですが、動作が遅すぎて困っています。
(IMG:unsigned char型の二次元配列にRAWデータを格納したもの)
高速で表示することはできないのでしょうか?
アドバイス等、よろしくお願いします。
void Cimage_binView::writeImg(void)
{
CClientDC myDC(this);
CDC *pDC = m_pict.GetDC();
int col,row;
int I;
CRgn myRgn;
RECT rect;
m_pict.GetClientRect(&rect);
myRgn.CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
pDC->SelectObject(&myRgn);
//画像出力
for(col=0;col<256;col++)
for(row=0;row<256;row++)
{
I=IMG[col][row];
if(I<m_sbar1.GetScrollPos())I=0;//スクロールバーの値より小さければ黒
else I=255;//大きければ白にする
}
pDC->SetPixel(row,col,RGB(I,I,I));
}
}
No.3ベストアンサー
- 回答日時:
こんばんは。
補足いただきました。>>CONST VOID *lpvBitsにm_arrdwImage
>>CONST BITMAPINFO *lpbmiにビットマップヘッダ...
>>と言うことでしょうか?
はい。
>>ビットマップのヘッダについても勉強した方が良いのでしょうか?
24ビットと32ビットの二つの使用方法位には慣れた方が良いかも知れません。
24ビットの方がヘッダの準備が簡単なのですが、イメージが3バイトで1ピクセルである為、ループで変換等をする様な場面では面倒です。
そう言った意味では32ビットの方が簡単ですが、ヘッダの準備が面倒になります。
以下は32ビット用のヘッダを準備します、参考程度に。
+-----------------------------------------------------------------------------------
//初期化
static void InitHDR32BIT(BITMAPINFOHEADER& bmi, int width, int height)
{
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = width;
bmi.biHeight = height;
bmi.biBitCount = 32;
bmi.biPlanes = 1;
bmi.biCompression = BI_BITFIELDS;
bmi.biSizeImage = bmi.biWidth * bmi.biHeight * (bmi.biBitCount / 8);
}
//32ビット型ビットフィールドの設定
static void InitBitFields32BIT(LPRGBQUAD pRGB)
{
//RGBQUADとDWORDは同じサイズです。ビットフィールドを指定する場合はLPDWORDにキャストする方が楽です(16ビット等では特に)
LPDWORD pBF = reinterpret_cast<LPDWORD>(pRGB);
pBF[0] = 0xff0000;
pBF[1] = 0x00ff00;
pBF[2] = 0x0000ff;
}
//ヘッダを動的作成する
static LPBITMAPINFO CreateHDR32BIT(int width, int height)
{
//ヘッダのサイズ(RGBQUAD * 3は、ビットフィールド用に必要です)
const int nHDRSize = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * 3);
LPBITMAPINFO pbmi = static_cast<LPBITMAPINFO>(::calloc(nHDRSize, 1));
::InitHDR32BIT(pbmi->bmiHeader, width, height);
::InitBitFields32BIT(pbmi->bmiColors);
return pbmi;
}
-----------------------------------------------------------------------------------+
//遠くで割り当てておく(メンバに入れておく。当然、不要になった時には::free(m_lpbmi)で消します)
LPBITMAPINFO m_lpbmi = ::CreateHDR32BIT(256, 256);
//ココで描写する
::SetDIBitsToDevice(pDC, 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight, 0, 0, 0, pbmi->bmiHeader.biWidth, m_arrdwImage, m_lpbmi, DIB_RGB_COLORS);
ご丁寧に指導していただき、ありがとうございました。
お陰さまでサクサク動くようになりました!
自分ひとりではとても書けなかったと思います。
本当にありがとうございました。
No.4
- 回答日時:
RAWイメージから、DIBTIMAPを構築するプログラムの例)
--------------------
/**
* unsigned longの32bitイメージデータ配列から、bitmapデータを構築する
*
* @param[in] hdc デバイスコンテキストハンドル
* @param[in] unsigned long *pImage 入力イメージデータ(32bitの配列
* @param[in] width イメージの横幅
* @param[in] height イメージの縦幅
* @return ビットマップのハンドル(失敗時にはNULL)
*/
HBITMAP createBitmapFromImage32(HDC hdc, unsigned long *pImage
, int width, int height)
{
BITMAPINFOHEADERbmih;
BITMAPINFOHEADER*lpbmih;
BITMAPINFObmi;
DWORDfdwInit;
CONST VOID*lpbInit;
BITMAPINFO*lpbmi;
UINTfuUsage;
HBITMAPhBitmap;
memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
bmih.biSize= sizeof(bmih);
bmih.biWidth= width;
bmih.biHeight= -height;
bmih.biPlanes= 1;
bmih.biBitCount= 32;
bmih.biCompression= BI_RGB;
bmih.biSizeImage= 0;
bmih.biXPelsPerMeter= 0;
bmih.biYPelsPerMeter= 0;
bmih.biClrUsed= 0;
bmih.biClrImportant= 0;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader = bmih;
lpbmih= &bmih;
fdwInit= CBM_INIT;
lpbInit= pImage;
lpbmi= &bmi;
fuUsage= DIB_RGB_COLORS;
hBitmap = CreateDIBitmap(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage);
return hBitmap;
}
void Cimage_binView::writeImg(void)
{
CClientDC myDC(this);
CDC *pDC = m_pict.GetDC();
int col,row;
int I;
CRgn myRgn;
RECT rect;
m_pict.GetClientRect(&rect);
myRgn.CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
pDC->SelectObject(&myRgn);
unsigned long image[256][256];
unsigned char scrollPos = m_sbar1.GetScrollPos();
//画像出力
for(col=0;col<256;col++)
for(row=0;row<256;row++)
{
I=IMG[col][row];
if(I<scrollPos)
I=0;//スクロールバーの値より小さければ黒
else
I=255;//大きければ白にする
}
image[row][col] = RGB(I, I, I);
}
HBITMAP hBitmap = createBitmapFromImage32(pDC->m_hDC, image, 256, 256);
// 後は、BitBlt等を使って、描画する。
// 例えば、
BITMAPbitmap;
memset(&bitmap, 0, sizeof(BITMAP));
GetObject(hBitmap, sizeof(BITMAP), &bitmap);
HDChdcDest= pDC->m_hDC;
intnXDest= 0;
intnYDest= 0;
intnWidth= bitmap.bmWidth;
intnHeight= bitmap.bmHeight;
HDChdcSrc= CreateCompatibleDC(hdcDest);
intnXSrc= 0;
intnYSrc= 0;
DWORDdwRop= SRCCOPY;
SelectObject(hdcSrc, hBitmap);
BOOL boResult = BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight
, hdcSrc, nXSrc, nYSrc, dwRop);
DeleteDC(hdcSrc);
}
--------------------
こんな感じの関数を用意しておいてあげれば、RAWイメージからBITMAPデータを作成
出来ると思います。
RAWイメージのデータ構造もunsigned long(32bit)の配列にしておいてあげる必要がありますけどね。
HBITMAPが得られれば、後は、GDC関数での描画も出来ますので、
SetPixel()関数を呼び出す回数も減らせるのではないでしょうか。
サンプルプログラムは、コンパイルやテストしていないので、バグがあると思いますが、
ご了承ください。
>>forループなしのプログラム
>とは2値化処理の部分で(各ピクセルにアクセスせずに)可能なのでしょうか?
forなしには出来ませんでした。すいません。
No.2
- 回答日時:
こんばんは。
動作が遅すぎるのは、
pDC->SetPixel(row,col,RGB(I,I,I));
の仕業です。
「画像処理 SetPixel 重い」(検索)
http://www.google.co.jp/search?hl=ja&q=%E7%94%BB …
爆裂に重たい事で有名です。
DWORD型の配列を用意して(又は動的に)
DWORD m_arrdwImage[256*256];
I = IMG[col][row];
m_arrdwImage[idx] = RGB(I,I,I);
の様に変換してから
SetDIBitsToDevice(pDC, , , , , m_arrdwImage);
でpDCに向かって描写すると速くなると思います。
「SetDIBitsToDevice()API」
http://msdn.microsoft.com/ja-jp/library/cc410591 …
流れは以下の様な感じです。
//外に出しておく
const int nScrollPos = m_sbar1.GetScrollPos();
//変換
for(col=0;col<256;col++)
{
for(row=0;row<256;row++)
{
I=IMG[col][row];
//大きければ白にする
if(I<nScrollPos)I=0;
else I=255;
//一次元のインデックス
const int idx = (row * 256) + col;
//32ビットの配列に代入する
m_arrdwImage[idx] = RGB(I,I,I);
}
}
//ココで描写する ヘッダーの初期化などはURLを参考
::SetDIBitsToDevice(pDC, , , , , m_arrdwImage);
この回答への補足
ありがとうございます。
URLを見ましたが、よくわからない部分があります。
int SetDIBitsToDevice(
HDC hdc, // デバイスコンテキストのハンドル
int XDest, // 転送先長方形の左上隅の x 座標
int YDest, // 転送先長方形の左上隅の y 座標
DWORD dwWidth, // 転送元長方形の幅
DWORD dwHeight, // 転送元長方形の高さ
int XSrc, // 転送元長方形の左下隅の x 座標
int YSrc, // 転送元長方形の左下隅の y 座標
UINT uStartScan, // 配列内の最初の走査行
UINT cScanLines, // 走査行の数
CONST VOID *lpvBits, // DIB ビットからなる配列
CONST BITMAPINFO *lpbmi, // ビットマップ情報
UINT fuColorUse // RGB 値またはパレットインデックス
);
lpvBits
バイト配列として格納されている、DIB の色データへのポインタを指定します。詳細については、「解説」を参照してください。
lpbmi
DIB についての情報を保持している 1 個の 構造体へのポインタを指定します。
ということですが、
CONST VOID *lpvBitsにm_arrdwImage
CONST BITMAPINFO *lpbmiにビットマップヘッダ...
と言うことでしょうか?
ビットマップのヘッダについても勉強した方が良いのでしょうか?
よろしくお願いします。
No.1
- 回答日時:
パフォーマンスチューニングの話ですね。
こちらのプログラムの場合、
GetScrollPos()と、SetPixel()の呼び出し回数が多すぎるために、遅くなって
ると予測出来ると思います。
・呼び出し回数
GetScroll():65536回
SetPixel():65536回
なので、これを減らしてあげれば、速度が速くなると思われます。
CreateDIBitmap()とか、BitBlt()が有効かもしれないので、試してみてください。
あと、for ループなしのプログラムに書き換え可能と思われますので、
そちらも試してみてください。
この回答への補足
ありがとうございます。
GetScroll();をループの前に配置したら大分早くなりました。
>forループなしのプログラム
とは2値化処理の部分で(各ピクセルにアクセスせずに)可能なのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript ①入力フォーム→②確認表示画面→③送信完了画面のコードを書いているのです、 入力フォームから受け取っ 2 2022/05/10 16:45
- Excel(エクセル) Excel 、この式はどのように解釈すればいいのでしょうか 4 2023/02/03 08:53
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- PHP PHP MySql ページング 2 2022/09/20 06:38
- その他(コンピューター・テクノロジー) Pythonの np.indicesに関する質問です。 2 2023/02/07 08:19
- Excel(エクセル) エクセル VBA For Next 繰り返しの書き方を教えてください 6 2022/09/01 14:11
- その他(プログラミング・Web制作) pythonリストの特定の値を表示htmlで表示できない 2 2022/05/14 05:48
- その他(プログラミング・Web制作) pythonのグローバル変数 2 2022/11/25 18:02
- Excel(エクセル) エクセル VBA実行中のApplication.ScreenUpdatingについて 3 2023/07/13 21:06
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・【大喜利】【投稿~11/12】 急に朝起こしてきた母親に言われた一言とは?
- ・好きな和訳タイトルを教えてください
- ・うちのカレーにはこれが入ってる!って食材ありますか?
- ・好きな「お肉」は?
- ・あなたは何にトキメキますか?
- ・おすすめのモーニング・朝食メニューを教えて!
- ・「覚え間違い」を教えてください!
- ・とっておきの手土産を教えて
- ・「平成」を感じるもの
- ・秘密基地、どこに作った?
- ・【お題】NEW演歌
- ・カンパ〜イ!←最初の1杯目、なに頼む?
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
関数から配列を返すには?
-
配列の要素数に変数を入れたい...
-
define で 配列
-
c言語
-
C#で構造体の配列を持った構造...
-
C言語において、 配列要素をひ...
-
MFCのCArrayを使った二次元配列
-
C言語の2次元配列 容量が大き...
-
n人の教科ごとの最高点、最低点...
-
C言語についてです 5人のテスト...
-
構造体のextern方法
-
C言語 ファイルの指定された行...
-
c言語 構造体
-
MFC - ダイアログボックスのPic...
-
シマウマの模様を変えるプログラム
-
C言語を使って、ファイルの読み...
-
C言語 数値の連続入力について
-
c言語の初期化について
-
int i, int i[1];
-
C言語で重複組合せを全列挙
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
おすすめ情報