
はじめまして質問させて頂きたい事がございます。
VC++ 2005 MFCを使用しております。
ビットマップ画像からCImageを作成し、
GetBits()を使用してポインタから直接RGB値を取得したと考えております。
MSDNには
------------------------------------------
取得したポインタと GetPitch の戻り値を使用すると、
イメージ内のピクセルを個別に指定して変更できます。
------------------------------------------
と書いてありますが、よく分かりませんでした。
ためしに4*4ピクセルのビットマップ画像をLoadして
以下のように実装してみました。
----------------------------------------------
//ピッチ取得
int pit = m_image.GetPitch();
//バイト数取得
int byt = m_image.GetBPP();
//ポインタ取得
int* rgb;
rgb = (int*)m_image.GetBits();
CString str;
str.Format(_T("%d, "), GetRValue(rgb[0]));
::TRACE(str);
str.Format(_T("%d, "), GetGValue(rgb[0]));
::TRACE(str);
str.Format(_T("%d, "), GetBValue(rgb[0]));
::TRACE(str);
----------------------------------------------
ピッチがマイナスで戻ってきたので
左下隅を起点とする逆方向 (下から上) にrgb[0]からはいってると
解釈したのですが、正常な値(画像ソフトの値)が取得できませんでした。
どなたかお詳しい方がおりましたら
ご教授お願いいたします。
お手数ではございますが
サンプルコードを記載していただけるとありがたいです。
以上になります。
ご回答よろしくお願いいたします。
A 回答 (3件)
- 最新から表示
- 回答順に表示
No.3
- 回答日時:
確かに 配列の添え字がマイナスになるのは精神衛生上良くないかもしれません
しかし考えてみてください
GetBitsで取得したポインタと関連があるのはGetPitchとGetBPPの2つです
この2つのデータを使ってボトムアップ/トップダウンの2種類の処理を1種類のコードでやるとすれば先の回答のようにならざるを得ないかと思います
またもともとこの領域を確保するのには アドレスの小さいほうの指示と大きさだと思います
コレが一般的ですし末尾を指示して前方の領域を確保なんてのは聞いたことないですからね
このGetBitsで確保した領域を取得すあたりにブレークポイントを置いてデバッグウィンドウのメモリーを表示させます
アドレスが表示されているコンボボックスに pStart[enter]と入力します
するとGetBitsで取得した領域のデータが表示されると思います
このウィンドウをスクロールさせて 16進データ以外の部分があることに気づきませんか?
コレは現在デバッグ中のアプリで管理していない領域を示しています
ポインタを使って アクセスする場合どの範囲までアクセス可能なのかは プログラマの裁量によります
コレで範囲指定を間違えると 例外が発生してアプリが落ちます
与えられたデータからアクセスを考えると -になるのも仕方がないと考えます
データの仕様に基づくアクセス方法なのです
逆の考え方をすれば nPitchがマイナスなら pStartを先に逆算しておいて x,yを加算していく(nPitchの符号も反転させて)といったことも可能ですよね
ただ2度手間になりますけど ・・・
redfox63 様
ご回答ありがとうございます。
GetBitsが21のポインタを返してきて
21以前の値が前方の領域に確保から仕方ないのですね。
>末尾を指示して前方の領域を確保なんてのは聞いたことないですからね
CImage GetBitsの仕様として解釈して宜しいということですよね。
>逆の考え方をすれば nPitchがマイナスなら pStartを先に
>逆算しておいて x,yを加算していく(nPitchの符号も反転させて)
>といったことも可能ですよね
>ただ2度手間になりますけど ・・・
これも考えました。確かに2度手間ですね。
管理しやすいですけど。
-------------
1, 2, 3, 4, 5
6, 7, 8, 9, 10
11,12,13,14,15
16,17,18,19,20
21,22,23,24,25
--------------
No.2
- 回答日時:
BYTE* pStart = m_image.GetBits();
int nPitch = m_image.GetPitch();
int nBPP = m_image.GetBPP();
// BYTEが8bitだから ビット深度を8で除算
int offset = nBPP / 8;
BYTE RGB{3];
for( y=0; y < m_image.Height; y++ ) {
for ( x = 0; x < nPitch / offset; x++ ) {
RGB[0] = pStart[ nPitch * y + x * offset + 0 );
RGB[1] = pStart[ nPitch * y + x * offset + 1 );
RGB[2] = pStart[ nPitch * y + x * offset + 2 );
}
}
といった具合で上手くいきませんか ...
xループの最初は nPitch*yが0になる x*offsetも0 +0だから pStart[0]
2回目は nPitch*yは0 x*offsetが3 +0だから pStart[3]
といった具合に xループは増加していき
yループはnPictchにより 増加または減少でアクセスできると思いますよ
ビットマップが ボトムアップなのかトップダウンなのかでGetBits()が返す位置が変ると思います
トップダウンなら1の位置
ボトムアップなら21に位置
こうすれば X軸方向は単純に増加、Y方向はnPitchの符号で増減といった単純化が出来ます
redfox63 様
ご丁寧な回答ありがとうございます。
理解できました。
C言語はあまり詳しくないので初歩的な質問で申し訳ないのですが、
配列の要素数にマイナスでアクセスすることは問題ないのでしょうか?
ポインタを移動させるだけなので問題ないと思うのですが
buf[-100]などの表記に疑問を感じましたので。
先ほどの座標の21から1にアクセスするには
結果的にはbuf[0 - xxx]になると思います。
最終的には左上を原点とした(左上が(0,0))
位置から指定座標のRGB取得したいため、
たとえば(1, 1)の値の場合、先ほどの「7」の位置になり
pStart[0]からマイナスのアクセスになります。(pStart[0 -xxx])
このような仕様でメモリを確保しているのだから
仕方ないのでしょうか?
左上を原点(左上が(0,0))
pStart[0]からメモリに確保されているバイト数分
ポインタをデクリメントして本来の(左上の)開始座標の
別途ポインタを作成し、そこからインクリメントしてアクセスしていった方が宜しいのでしょうか?
最後の質問にしたいと思います。
よろしくお願いいたします。
No.1
- 回答日時:
もしかして ビットの深さが 24とかじゃないですか?
コレだと 3バイトで一組なので 32ビットのintではうまくないですよ
BYTE型のポインタでアクセスしないとダメなように思います
BYTE* rgb = (BYTE*)m_image.GetBits();
rgb[0], rgb[1], rgb[2] で RGBの各要素にアクセス
右隣は rgb[3], rgb[4], rgb[5] 感じで
次の行は
rgb[nPitch+0],rgb[nPitch+1],rgb[nPitch+2]
だと思いますよ ・・・
redfox63 様
ご回答ありがとうございます。
教えていただいたとおり
BYTE型のポインタにしてメモリを確認したとこと、
正常に値が入っていることを確認できました。
RGBは逆順で、BGRの順で格納されるのですね。
追記で質問させていただきたいことがあるのですが、
仮に5*5ピクセルの場合
ピッチが[-16](3バイト * 5ピクセル + 1)でしたので、
元のBMP画像の座標を以下のよう定義した場合
-------------
1, 2, 3, 4, 5
6, 7, 8, 9, 10
11,12,13,14,15
16,17,18,19,20
21,22,23,24,25
--------------
GetBits()の戻り値は
21のB値になると思うのですが(以下pStart)、
1~25のすべてのRGB値を取得するためには
pStartからそれぞれ計算して
元座標の21未満はpStartからマイナス分アクセスし、
21以上はpStartからプラス分アクセスすればいいことになりますが、
この取得方法は一般的なのでしょか?
なにか気をつけなければいけないようなことが
あったら教えていただきたく思います。
以上です。
ご教授よろしくお願いいたします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# str[j++]の意味 2 2022/08/30 16:20
- オープンソース Python openpyxlを使用したセル番地の使用について 1 2023/08/03 22:05
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# C#テキストボックスの文字を配列にいれてその後表示する 4 2022/07/17 04:47
- Visual Basic(VBA) VBAの繰り返し処理について教えてください。 3 2022/08/02 13:21
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- Visual Basic(VBA) エクセル VBA 条件付き書式 簡略化したい 2 2022/06/02 17:46
このQ&Aを見た人はこんなQ&Aも見ています
-
RGBのバイナリデータをCImageにコピー
C言語・C++・C#
-
CStaticコントロールの静的イメージ描画
C言語・C++・C#
-
CStringのFindで文字列検索を行いたいのですが
C言語・C++・C#
-
-
4
CImageクラスの使用について
C言語・C++・C#
-
5
CStringからchar*への型変換について教えてください。
C言語・C++・C#
-
6
画面を強制的に再描画させる方法
C言語・C++・C#
-
7
CStringの文字列検索&抜き出しについて
C言語・C++・C#
-
8
CStringをwchar_tに変換したい
C言語・C++・C#
-
9
エディットコントロールの色の変更方法
C言語・C++・C#
-
10
CImage::ReleaseDC()のエラーで困っています。
C言語・C++・C#
-
11
MFCで画像を表示させているのですが、透過表示する方法がわかりません。
C言語・C++・C#
-
12
CString から LPCTSTRの型に変換
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語特有の文法や概念について
-
ポインタのsizeofについて
-
ポインタ定義は必要なんですか?
-
マクロ,クラス
-
ファイルポインタのヘッダーフ...
-
C言語のvoid型ポインタ変数につ...
-
連結リスト 要素の入れ替え
-
配列3個へのポインタを返す関数
-
[C言語] NULLは必ず0(番地)です...
-
ポインタのミスでOS壊れるの...
-
structをポインタ宣言時の領域
-
C言語の練習
-
sprintf 初歩的な質問
-
gccでMAKEINTRESOURCEするとdif...
-
init関数の意味
-
関数のパラメタ(C++)
-
戻り値で構造体を返すことは可...
-
引数のポインタ変数をローカル...
-
プログラミング C++
-
#include <stdio.h> #include <...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
セグメントエラー
-
C言語のポインタに直接アドレス...
-
init関数の意味
-
Run-Time Check Failure #3とい...
-
戻り値で構造体を返すことは可...
-
ExcelVBAでのkernel32(64bit)
-
アプリを32bitから64bit移行
-
参照型で受け取った引数をポイ...
-
fopne で失敗する原因
-
PASCALとFARの意味
-
LPSTR型の初期化について
-
CWnd::EnableWindow()の扱い方
-
ポインタについて
-
プーさんのマウスポインタを教...
-
連結リスト 要素の入れ替え
-
ハンドルはポインタか
-
C++で関数ポインタから関数名を...
-
自作DLLの引数について、ポイン...
-
NULLポインタが0でない処理系と...
-
TCHAR文字列内の検索について
おすすめ情報