
現在VC++をつかった画像を扱うプログラミングを学習中なのですが、画像データの取り扱いについてわからないことがあるため教えていただきたいです。
BMP画像をバッファに取り込んだあとで、画像の縦横を拡大縮小したデータを新たなバッファに格納したいのですが、画像を拡大縮小する方法がわかりません。いくつかのプログラムのソースを見させていただいたのですが、BITMAPINFOHEADER構造体の中のbiWidthやbiHeightの値を変えているだけのようなのです。
これらの値を変えるだけで、指定した幅と高さに変換された画像データが得られるのでしょうか?
また、それで拡大縮小されるならば、変換された画像データは輝度情報が滑らかになるように何かしらの補正が加えられていたりするのでしょうか?それとも、途中途中の輝度を単純に抜いていたりするだけなのでしょうか。
その辺の原理についても教えていただけるとうれしいです。
お手数をかけますが、よろしくお願いします。
No.2ベストアンサー
- 回答日時:
> 実際に拡大縮小された画像のデータ(バッファ)がどこに格納されたのかわかりません・・・。
一般的には、メモリやVRAMに載ります。取得もできますが、DIBSectionを使うと、メモリとして参照しやすいです。
> また、StretchBlt関数は、描画を目的としているようなのですが、今回の場合、
> -- snip --
> 描画は無駄な手間のように思われます。
実際の画面に表示するかにかかわらず、WindowsのAPIにおける画像の操作は原則として「DC」という概念を使います。
メモリやプリンタもDCの一種と扱われますし、必ずしも画面描画は意味しません。
ビットマップに何か書くのも、DCと関連付けてそこに描画する仕組みです。
メモリ上で拡大縮小するということは、結局のところ突き詰めれば
元画像を読んで拡大縮小した画像をそこ(メモリ上)に描画している、
ということだと思いますが、いかがでしょう。
# C言語の入出力がコンソールにもファイルにも使えるようにFILE*を使うのとかと大差ない、
# DCってのはWindowsにおける「描画先」の抽象化された概念です。
> 何かスマートな方法はないものでしょうか?
DCという概念自体はWindows GDIの根底ですから、WindowsのAPIである限り、
他を使ってもIFは違えど内部的にはDCと大差ないと思われますが。
「質問者さんにとってのスマート」が不明ですが、自前で変換処理を書くか、
完全独自処理の画像変換ライブラリを持ってくるのがスマートですか。
この回答への補足
MrBanさんにご指導いただいたことを参考に、プログラムを書いてみました。img1構造体に格納されたビットマップを、伸縮してimg0構造体に格納するプログラムのつもりです。
このプログラムでは、すでにimg1構造体にビットマップ情報が格納された、として話を進めています。というのも、ビデオカメラで撮影することを目的として考えているため、専門の参考書をよんで、バッファを得るところまではプログラムが完成しているからです。
それから、遅くなりましたが、「スマート」という言葉は、「動画処理のためにわずかでも高速で処理してくれるよう、二度手間のようなことはせず、最適なプログラムにするためには?」という意味で使いました。言葉が足らず、ご迷惑をおかけしました。
まだまだ見苦しいプログラムかもしれませんが、丸一日かかってデバイスコンテキストの概念について勉強しました。間違っているところがあれば、ご指導いただけるとうれしいです。
/**********************************************************/
//グラフィック用ウィンドウのデータをまとめた構造体
typedef struct{
HINSTANCE hi;
int x;//表示開始位置
int y;
HWND hwnd;//自分のウィンドウハンドル
BYTE *lpBmpData;//BMPのデータ部分
BITMAPINFOHEADERbih;
BITMAPFILEHEADERbfh;
}IMG0;//クラス名
/************************************************************/
・・・・・・
IMG0 img0;//伸縮後のビットマップを格納する
IMG0 img1;//元のビットマップが格納されている
HDC bihdc;
static HDC hMemDC;//メモリデバイスコンテキスト
HBITMAP hBitmap;
//1.デバイスコンテキストを作成
bihdc = GetDC ( img1.hwnd );
//2.GDIビットマップ(DDB)を作成する
hBitmap = (HBITMAP) CreateDIBitmap (
bihdc,//デバイスコンテキストのハンドル
img1.bih,
0,NULL,NULL,0 );
//3.メモリデバイスコンテキストを作成
hMemDC = CreateCompatibleDC ( bihdc );
//4.メモリデバイスコンテキストの内容をhBitmap(DIB)で初期化?
SelectObject ( hMemDC, hBitmap );
//5.伸縮モードの変更
SetStretchBltMode ( hMemDC, COLORONCOLOR );
//6.拡大縮小(たとえば縦横とも1/2にする)
hBitmap = StretchBlt (
hMemDC,
0,0,
(img1.bih.biWidth)/2,(img1.bih.biHeight)/2,
bihdc,
0,0,
img1.bih.biWidth,img1.bih.biHeight,
SRCCOPY );
//7.ビットマップの選択
SelectObject ( hMemDC, hBitmap );
//8.メモリデバイスコンテキストの内容をバッファにコピー
img0.lpBmpData = (BYTE*)
GetDIBlts (
hMemDC,
hBitmap,
0,(img1.bih.Height)/2,
img0.lpBmpData,
img0.bih,
DIB_RGB_COLORS );
//9.ビットマップやメモリデバイスコンテキストの削除
DeleteObject ( hBitmap );//ビットマップの削除
ReleaseDC ( img1.hwnd, bihdc );
DeleteDC ( hMemDC );
・・・・・・・
/*********************************************************/
以上のようなステップでバッファに格納するようにしました。
自信はまったくありません。
SelectObjectをステップ4と7で二回もする必要があるのかどうかすらわかりません。また、ステップ9のDeleteObjectの位置も正しいのかわかりません。
また、今回目的が動画処理ということで、高速処理が要求されるので、上記の方法が適切か、それとも、もっと高速で伸縮処理してくれる関数があるのか、ご存知の方がいらっしゃったら、ご指導いただけないでしょうか。
本当にあつかましくてすいませんが、よろしくお願いします。
なるほど!ありがとうございます。
「DCはペンやブラシなどを持つための手で、このDCはこの色のペンとブラシをもつ」との決まりが書かれているものがデバイスコンテキストだと思っていました。まずはデバイスコンテキストの概念からきちんと勉強します。
何度もありがとうございました。
No.3
- 回答日時:
CreateDIBSectionを使う方がメモリ参照が多少効率的になるかもしれません。
また、SelectObjectは引数で以前のObjectを返します。
7 のSelectObjectは、4のSelectObjectした戻り値を保存しておいて再設定する必要があります。
// 処理イメージ
old = SelectObject(new); // 変更してから使う
...
SelectObject(old); // 使い終わったら戻しておく
BitmapをDeleteする時点で、DCにSelectされたままだと使用中のためDeleteに失敗し、
リソースがリークします。(Deleteでエラーが返っていませんか?)
更に、8より後に書くべきかと思います。(8でまだDCとBitmapを使ってるので)
# 動画処理が前提だと、元データ形式にもよりますが、
# DirectX等で伸張することを考えた方がいいかもしれません。
# 静止画の処理効率としてはDIBSectionにすればそう悪くないと思います。
この回答への補足
DIBSectionを勉強するのに時間がかかってしまい、返信が遅れてしまいました。この間のプログラムをDIBSection用に改良しました。
これもまた見苦しいプログラムかもしれませんが、間違い等ありましたらご指導いただけるとうれしいです。
HBITMAP hBitmap,copyhMemDC;
HDC hMemDC,hOld;
BITMAPINFO bmpInfo,copybmpInfo;
int X_SIZE,Y_SIZE;
int REF_X_SIZE,REF_Y_SIZE;//拡大縮小したいサイズを指定
LPVOID lpPixel,lpBmpData;
//1.まず、BMP画像をDIBSectionとして読み込む
//インターネットを参考に関数を作成
CreateDIBSection32FromFile (
infile,//入力画像BMP
&hBitmap,//入力画像のDDIへのポインタ
&lpPixel,//入力画像のDIBへのポインタ(バッファ)
&bmpInfo );//BITMAPINFO構造体に画像情報が格納される
//2.X_SIZE、Y_SIZEにBMP画像のサイズを指定した
X_SIZE = bmpInfo.bmiHeader.biWidth;
Y_SIZE = bmpInfo.bmiHeader.biHeight;
//3.メモリデバイスコンテキストの作成
hMemDC = CreateCompatibleDC ( NULL );
copyhMemDC = CreateCompatibleDC ( NULL );
//4.hBitmapの選択
SelectObject ( hMemDC, hBitmap)
hOld = SelectObject ( copyhMemDC, hBitmap );
//5.伸縮モードの変更
SetStretchBltMode ( copyhMemDC, COLORONCOLOR );
//6.拡大縮小(縦幅が参照画像と等しくなるように)
StretchBlt (copyhMemDC,0,0,
REF_X_SIZE,REF_Y_SIZE,//拡大縮小したいサイズを指定
hMemDC,0,0,X_SIZE,Y_SIZE,SRCCOPY );
//7.BITMAPINFO構造体の情報を設定
copybmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
copybmpInfo.bmiHeader.biWidth = REF_X_SIZE;
copybmpInfo.bmiHeader.biHeight = REF_Y_SIZE;
copybmpInfo.bmiHeader.biPlanes = 1;
copybmpInfo.bmiHeader.biBitCount = BITCOUNT;
copybmpInfo.bmiHeader.biCompression = BI_RGB;
//8.hBitmapの選択解除
SelectObject (copyhMemCD,hOld);
//9.メモリデバイスコンテキストの内容をバッファにコピー
//バッファとして伸縮後の情報を得ることが今回の目的なので
GetDIBlts (copyhMemDC,hBitmap,
0,REF_Y_SIZE,
lpBmpData,//バッファとして伸縮後の情報を格納
copybmpInfo.bmiHeader,DIB_RGB_COLORS );
}
//10.DCの削除
DeleteDC ( hMemDC );
DeleteDC ( copyhMemDC );
//DIBSectionの削除
DeleteDIBSection32 ( &hBitmap );//DeleteObjectしている
GetDIBltsにhBitmapを渡す前に、SelectDbjectを解除しなければならないとあったので、
SelectObject ( copyhMemCD, hOld );
としてみました。本当は、
StretchBlt (hMemDC,0,0,REF_X_SIZE,REF_Y_SIZE,
hMemDC,0,0,X_SIZE,Y_SIZE,SRCCOPY );
として、hMemDCを上書きしたかったのですが、それだとSelectObjectを解除できないので、上のような方法をとってみましたが、
もし、copyhMemDCを作らずにhMemDCに上書きする方法がありましたら
ご教授いただけるとうれしいです。
何度もご意見いただき、本当にありがとうございます。
上に、DIBSectionを使った前回と同じようなプログラムを作ってみたので、よろしければ見てやってください。
MrBanさんのおかげで、少しずつですがAPIプログラミングのイメージがつかめてきたようなきがします。
ありがとうございます。
No.1
- 回答日時:
DCというものを調べて、StretchBlt等を使ってください。
補正はSetStretchBltModeを。
なお、ヘッダ構造体のサイズを変えた場合、画像を伸張するわけではなく、
単にトリムしたりするだけです。
この回答への補足
上で書いたプログラムについて、自分で間違っていると思われるところを発見したので、訂正したかったのですが、訂正の仕方がわからなかったため、このような形でのコメントとなってしまいました。申し訳ないです。
/**********************************************************/
・・・・・・
IMG0 img0;//伸縮後のビットマップを格納する
IMG0 img1;//元のビットマップが格納されている
HDC bihdc;
static HDC hMemDC;//メモリデバイスコンテキスト
HBITMAP hBitmap;
//1.デバイスコンテキストを作成
bihdc = GetDC ( img1.hwnd );
//2.GDIビットマップ(DDB)を作成する
hBitmap = (HBITMAP) CreateDIBitmap (
bihdc,//デバイスコンテキストのハンドル
img1.bih,
0,NULL,NULL,0 );
//3.メモリデバイスコンテキストを作成
hMemDC = CreateCompatibleDC ( bihdc );
//4.メモリデバイスコンテキストの内容をhBitmap(DIB)で初期化?
SelectObject ( hMemDC, hBitmap );
//5.伸縮モードの変更
SetStretchBltMode ( hMemDC, COLORONCOLOR );
//6.拡大縮小(たとえば縦横とも1/2にする)
StretchBlt (
hMemDC,
0,0,
(img1.bih.biWidth)/2,(img1.bih.biHeight)/2,
bihdc,
0,0,
img1.bih.biWidth,img1.bih.biHeight,
SRCCOPY );
//7.メモリデバイスコンテキストの内容をバッファにコピー
img0.lpBmpData = (BYTE*) (すいません省略)
GetDIBlts (
hMemDC,
hBitmap,
0,(img1.bih.Height)/2,
img0.lpBmpData,
img0.bih,
DIB_RGB_COLORS );
//8.ビットマップやメモリデバイスコンテキストの削除
DeleteObject ( hBitmap );//ビットマップの削除
ReleaseDC ( img1.hwnd, bihdc );
DeleteDC ( hMemDC );
・・・・・・・
/*********************************************************/
どうもありがとうございます!
早速StretchBltとデバイスコンテキストについて調べてみました。そしたら、申し訳ないのですが、新しくわからないことがでてきてしまいました。
画像処理関係のプログラムは初めてなので、変なことを聞いてしまっていたらすいません。
StretchBlt関数等を使うと、画像を任意のサイズに拡大縮小できるということはわかったのですが、実際に拡大縮小された画像のデータ(バッファ)がどこに格納されたのかわかりません・・・。
また、StretchBlt関数は、描画を目的としているようなのですが、今回の場合、たとえば、「2倍、3倍にした画像データをバッファに一時格納して、必要とあれば、その時ファイルに書きだす」等の作業をしたいので、描画は無駄な手間のように思われます。
何かスマートな方法はないものでしょうか?
もしよろしければ、これらの質問にもお答えいただけないでしょうか。
お願いします。お手数をかけて申し訳ありません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- PDF 画像調整してスクショし保存した画像を印刷する方法 1 2022/03/31 18:42
- Excel(エクセル) Excelでこういうカードの作り方 枠線の引き方や、挿入画像の拡大縮小など わかる方教えてください、 2 2022/05/03 21:22
- デジタルカメラ 録画した4K動画を、フルピクセルで再生したい 5 2023/05/10 00:05
- PDF 画像調整してスクショし保存した画像をPC画面と同画質で印刷する方法 1 2022/03/31 19:09
- その他(IT・Webサービス) 画像調整してスクショし保存した画像をPC画面と同画質で印刷する方法 3 2022/03/31 19:11
- AJAX 自作の地図をグーグルマップのようにしたい 3 2022/11/15 11:53
- その他(AV機器・カメラ) 【大至急】写真加工に強い方、お願いします。 現在、自作のブックカバーをプリンパさんに依頼しています。 2 2023/06/07 21:30
- その他(OS) Windowsで大量の画像サイズを半自動で変更する方法 6 2023/02/17 08:45
- X(旧Twitter) ツィッターの画像表示について 1 2023/08/17 09:28
このQ&Aを見た人はこんなQ&Aも見ています
-
MFC - ダイアログボックスのPictureControlへの画像表示
C言語・C++・C#
-
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
画面を強制的に再描画させる方法
C言語・C++・C#
-
-
4
LoadImage関数について(VC++)
C言語・C++・C#
-
5
CStaticコントロールの静的イメージ描画
C言語・C++・C#
-
6
MFCでbitmapを背景にしてstaticテキストを透過させる方法
C言語・C++・C#
-
7
ボタンの表示の色、フォントを変更したい
C言語・C++・C#
-
8
エディットボックスのフォントを変えたい
C言語・C++・C#
-
9
ビットマップを表示させる(MFC)
C言語・C++・C#
-
10
CImageのファイル名を指定して保存
C言語・C++・C#
-
11
CStringのFindで文字列検索を行いたいのですが
C言語・C++・C#
-
12
エディットボックスの入力制限について
C言語・C++・C#
-
13
MFCで画像を表示させているのですが、透過表示する方法がわかりません。
C言語・C++・C#
-
14
エディットコントロールでEnter押した時の動作
C言語・C++・C#
-
15
MFCアプリのコマンドラインでパラメータを使用した起動方法
C言語・C++・C#
-
16
画像の印刷について
C言語・C++・C#
-
17
WM_SIZEを発生させる方法
C言語・C++・C#
-
18
CStringをwchar_tに変換したい
C言語・C++・C#
-
19
static 文字が上に張り付いて・・・
C言語・C++・C#
-
20
ダイアログ内コントロールの位置取得について
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
word
-
[VB.net] DataGridViewの列ヘッ...
-
c++ ダブルバッファリング、以...
-
VC++プログラムをつかったBMP画...
-
google Colabでmatplotlibの描...
-
TextBoxに文字を書いても表示さ...
-
VB6,リストボックスの特定行の...
-
VBAにGDI+を参照させる方法
-
StretchBlt関数について
-
この二つの違いは・・・?
-
CDC(LineTo)で描画した線を透過...
-
最前面に無理やりフォームを持...
-
NVIDIAのシェーダーキャッシュ
-
GetGlyphOutline() ご利用経験...
-
ダイアログベースの再描画について
-
クライアント領域を再描画させ...
-
画像の印刷について
-
逐次的なグラフ表示の方法
-
ピクチャーコントロールへの描...
-
win32api 画面のちらつき
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Minecraft 統合版(PC)の描画距...
-
[VB.net] DataGridViewの列ヘッ...
-
word
-
TextBoxに文字を書いても表示さ...
-
VB6,リストボックスの特定行の...
-
NVIDIAのシェーダーキャッシュ
-
MFCでOnPaintのタイミング
-
panelのスクロール表示について
-
VC++プログラムをつかったBMP画...
-
Labelの文字をスクロールする際...
-
UpdateData( FALSE); による文...
-
VBAにGDI+を参照させる方法
-
CStaticコントロールの静的イメ...
-
FlexGridの一部のみ表示を更新...
-
Form1 Load で実行されない。
-
VB.netでのライン描画方法がわ...
-
重いグラフィックス処理
-
InvalidateRectの使い方について
-
SHGetFileInfoでアイコンが取得...
-
OneNote 2010 文字と描画がずれる
おすすめ情報