Bitmapの切出しについて

[戻る]
Single Father 2008/07/29(火) 13:02:55
環境は、VS2005 VC++ CLIです。

ビットマップを指定した位置とサイズで切出して切出した
ビットマップを別のファイル名で保存させるにはどのよう
にすればいいでしょうか?

BitmapクラスとGraphicクラスを組み合わせて実現できると
思いますがネットでいろいろ探しましたがサンプル等があま
りなかったので・・・。

切出した画像を他のBitmapにDrawImageすることは出来たの
ですが切出した画像そのものを保存する方法が分かりません。

どなたかアドバイス宜しくお願いします。

Blue 2008/07/29(火) 13:18:16
>切出した画像を他のBitmapにDrawImageすることは出来たの
Saveメソッドが使えませんか?

Bitmap..::.Save メソッド 
http://msdn.microsoft.com/ja-jp/library/system.drawing.bitmap.save.aspx

Single Father 2008/07/29(火) 13:29:36
>Blueさん

早速のレスありがとうございます。

すみません、質問の仕方が少々甘かったです。

保存はSaveメソッドで出来そうですが元々の画像が3008×2000の
サイズがあったとしてその画像から一部4cm×4cmを切出した後に
切出した画像を4cm×4cmのまま直接保存させたいのです。

この場合、DrawImageはどこに対して行えばよいのでしょうか?

Blue 2008/07/29(火) 13:55:35
新たにBitmapインスタンスを作ればいいだけの話では?

http://msdn.microsoft.com/ja-jp/library/ms172505.aspx
の
ビットマップの一部をコピーするには
を参考に

Bitmap^ CopyBitmap(Bitmap^ source, Rectangle% part)
{
    Bitmap^ bmp = gcnew Bitmap(part.Width, part.Height);
    Graphics^ g = Graphics::FromImage(bmp);
    g->DrawImage(source, 0, 0, part, GraphicsUnit::Pixel);
    delete g;
    return bmp;
}

というメソッドを作って、呼び出し側で

Rectangle part(0, 0, 100, 100);
Bitmap^ dest = CopyBitmap(元となるBitmapのインスタンス, part);
dest->Save(L"ほげ.bmp");
delete dest;

という具合で。


>4cm×4cm
センチ単位の場合は変換が必要そう。(PC上のビットマップでセンチって・・・)

rin 2008/07/29(火) 13:56:14
セーブするときは元画像のことは忘れて

>切出した画像を他のBitmapにDrawImageすることは出来たの
この切り出し先の「他のBitmap」をセーブすればいい
「他のBitmap」を、切り出したいサイズで作成しておくのを忘れずに

Single Father 2008/07/29(火) 14:20:30
>Blueさん

Sampleクラスありがとうございます。まさにやりたいことそのもの
でした。

>4cm×4cm
>センチ単位の場合は変換が必要そう。(PC上のビットマップでセンチって・・・)

すみません(><)ピクセルの誤りでした(汗)

勉強のために質問させてください。

Rectangle% part

としているのですがCLIでは

Rectangle^ partでは駄目なのでしょうか?

確かにRectangle^ partで書くとDrawImageの引数でRectangleからfloatに変換出来ませ
んとエラーになります。

Blue 2008/07/29(火) 14:26:42
Rectangleはvalueクラスなので通常は ^ を使いません。
よって、

Bitmap^ CopyBitmap(Bitmap^ source, Rectangle part)

とすればいいです。

%をつけたのは、CopyBitmap内でpartを変更しないから参照渡しにすれば無駄なコピーが
なくなるかなと。


ちなみに、^をつける場合、呼び出し側で
Bitmap^ dest = CopyBitmap(元となるBitmapのインスタンス, %part);
、
>g->DrawImage(source, 0, 0, part, GraphicsUnit::Pixel);
g->DrawImage(source, 0, 0, *part, GraphicsUnit::Pixel);
とすることになるでしょう。

Single Father 2008/07/29(火) 15:08:49
[[解決]]
>Blueさん

>Rectangleはvalueクラスなので通常は ^ を使いません。

Valueクラスでしたか。てっきりBitmapクラスやGraphicクラスと
同じ扱いだと思っていました。勉強になりました。

>%をつけたのは、CopyBitmap内でpartを変更しないから参照渡しに
>すれば無駄なコピーがなくなるかなと。

確かに関数内部では値を変更しないので参照渡しにすれば無駄な
コピーがなくなりますね。

画像系を扱うクラスについてまだまだ知識不足なのでこれを機会に
もっといろいろと学んで行きたいと思います。

また不明点があった際は宜しくお願い致します。

Single Father 2008/07/29(火) 17:25:48
>Blueさん

たびたびすみません。

先程のクラスを使用して実装してみました。

Rectangleに渡す引数を変えるとで確かに指定した値で画像がトリミング
されて保存されますが保存された画像を確認すると画像ピクセルは指定し
たピクセルあるのですが肝心な画像が縮小表示されてしまっています。

画像を縮小せずにオリジナルのままトリミングして保存させたいのですが
何か良い方法はありますでしょうか?

Single Father 2008/07/29(火) 22:24:21
"Sample.bmp"を2000×2000で切出して"test.bmp"という名前で保存させた時
に"test.bmp"を確認するとピクセル数は2000×2000ありますが切出した画像
が左上に縮小表示されているだけになってしまっており残りの部分は描画さ
れていない状態です。

元画像の"Sample.bmp"は2500×3000ピクセルです。縮小表示されずに切出
した画像を2000×2000のオリジナルのまま表示したいのですが何か方法は
ありますでしょうか?

以下が記述したコードです。

-----------------------------------------------------------------------

Bitmap^ bitmap = gcnew Bitmap("Sample.bmp");

Rectangle part(0, 0, 2000, 2000);
Bitmap^ dest = CopyBitmap(bitmap, part);
dest->Save(L"test.bmp");
delete dest;


Bitmap^ CopyBitmap(Bitmap^ source, Rectangle% part)
{
    Bitmap^ bmp = gcnew Bitmap(part.Width, part.Height);
    Graphics^ g = Graphics::FromImage(bmp);
    g->DrawImage(source, 0, 0, part, GraphicsUnit::Pixel);
    delete g;
    return bmp;
}


------------------------------------------------------------------------

Blue 2008/07/30(水) 01:28:38
>左上に縮小表示されているだけ
本当にそうなりますか?

VC++ 2008 Expressで試しましたが再現しませんでした。
ちなみに、Sample.bmpはペイントでまず2000×2000のサイズにして任意の色で背景色を塗
りつぶして、その後2500×3000にして塗りつぶしていないところを違う色で塗りつぶした
ものをつかって試してみました。

Single Father 2008/07/30(水) 08:50:49
>Blueさん

返信ありがとうございます。

>Sample.bmpはペイントでまず2000×2000のサイズにして任意の色で背景色を塗
>りつぶして、その後2500×3000にして塗りつぶしていないところを違う色で塗り
>つぶしたものをつかって試してみました。

確かに上記の方法では2000×2000のサイズでキレイ切取られて表示されますが
実際のデジカメ等で撮影した写真で確認すると元画像より小さく見えてしまう
のですが目の錯覚ですかね?

ピクセル単位での切出しはなかなか確認する手段がなくて難しいです(><)

Blue 2008/07/30(水) 09:03:39
> 目の錯覚ですかね?
なにで確認されているのでしょうか?
ペイント等の画像サイズによってズームして表示されないソフトで確認してもそうなり
ますか?
(Windowsのビューアとかではズームして表示されたりする)

Single Father 2008/07/30(水) 09:09:58
>Blueさん

おはようございます

>ペイント等の画像サイズによってズームして表示されない
>ソフトで確認してもそうなりますか?

人物の写真なのですがペイントでも確認しましたがやはり
元画像より人物が小さく見えます。目で見て確認できるく
らい人物のサイズに違いがありました・・・。

ペイントの背景色だけだと上手く切出せているだけに謎で
すね・・・(><)

えちぜん 2008/07/30(水) 11:28:20
それぞれのBitmapのDPIが異なっているのではないでしょうか。
http://msdn.microsoft.com/ja-jp/library/ms142041(VS.80).aspx
実際に試したわけではないので間違っているかもしれません。

Single Father 2008/07/30(水) 11:50:38
>えちぜんさん

なるほど、DPIですか。もう少し調べてみます。

Single Father 2008/07/30(水) 15:03:07
いろいろ試した結果上手くいきました。

DrawImageだと画像がスケーリングされてしまうようです。

DrawImageUnscaledAndClippedメソッドでスケーリングさせないように
したところ上手く表示できました。 

http://msdn.microsoft.com/ja-jp/library/system.drawing.graphics_members.aspx

Single Father 2008/07/30(水) 15:50:20
>DrawImageUnscaledAndClippedメソッドでスケーリングさせないように
>したところ上手く表示できました。

う〜ん。出来たと思ったのにここで問題が・・・。切出し位置が0,0じゃないと
上記のメソッドは上手く行きませんでした・・・。

切出し位置を指定すると描画位置も変わってしまいました(汗)

何か他にうまい方法はないでしょうか?

Single Father 2008/07/30(水) 16:35:19
やりたいことはsample.bmp(3000×3000)があるとしたら左位置(X)と上位置(Y)
を指定しそこから縦(Height)、横(Widh)の指定したピクセルで画像を切抜き(画
像の好きな位置を切抜き出来る)切り抜いた画像をスケーリングせずにオリジナ
ルサイズのまま新規ビットマップに保存したいのです。

現在、問題になっているのは

DrawImageだと上記のことが上手く出来ているが画像がスケーリングされてしま
う。

DrawImageUnscaledAndClippedだとスケーリングせずに表示出来るが左位置(X)と
上位置(Y)の切出し位置を指定するとその位置から描画が開始されてしまう。
※X=0 y=0の左上から切出しを開始すると上手く表示される。


画像とスケーリングに詳しい方、アドバイスお願いします。

えちぜん 2008/07/30(水) 16:48:58
DrawImageで描画元の画像も、描画先も、左位置、上位置、縦、横を指定してやればいい
のではないでしょうか。
このとき、縦と横は元も先も同じ値にしておくとか。

g->DrawImage(source, 0, 0, part.Width, part.Height, part, GraphicsUnit::Pixel);

http://msdn.microsoft.com/ja-jp/library/system.drawing.graphics.drawimage
(VS.80).aspx
http://msdn.microsoft.com/ja-jp/library/x2s2a44c(VS.80).aspx

Single Father 2008/07/30(水) 17:02:15
>えちぜんさん

ありがとうございます。

>g->DrawImage(source, 0, 0, part.Width, part.Height, part,GraphicsUnit::Pixel);

パラメータの順番が異なるようです。

Graphics..::.DrawImage メソッド (Image, Rectangle, Single, Single, Single, 
Single, GraphicsUnit)

で試してみましたがやはり0,0の位置からではなく切出し開始位置からビットマップ
に描画されてしまいます。

Blue 2008/07/31(木) 09:41:33
回答ではないです。

>DrawImageUnscaledAndClipped
ですが、ちゃんと等倍で描画されています?
高さ・幅に合わせて縮小されているような。

http://msdn.microsoft.com/ja-
jp/library/system.drawing.graphics.drawimageunscaledandclipped.aspx
>指定された四角形内に収まるようにイメージをクリップします。

Blue 2008/07/31(木) 09:56:38
試してみましたが下記のコードでうまくいっているっぽいです。

Bitmap^ CopyBitmap(Bitmap^ source, Rectangle% part)
{
    Bitmap^ bmp = gcnew Bitmap(part.Width, part.Height);
    bmp->SetResolution(source->HorizontalResolution, source-
>VerticalResolution);
    Graphics^ g = Graphics::FromImage(bmp);
    g->DrawImage(source, 0, 0, part, GraphicsUnit::Pixel);

    delete g;
    return bmp;
}

System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) 
{
    Bitmap bitmap(L"Sample.bmp");

    Rectangle part(100, 100, 2000, 2000); 
    Bitmap^ dest = CopyBitmap(%bitmap, part);
    dest->Save(L"test.bmp");
    delete dest;
}

Single Father 2008/07/31(木) 11:33:40
[[解決]]
>Blueさん

>bmp->SetResolution

解像度を設定するメソッドがあったのですね!勉強になりました。

Rectangle part(0, 0, 2000, 2000);

として

Graphics..::.DrawImage(source, part,100,100, part->Width,part->Height 
,GraphicsUnit::Pixcel)

と書いても上手く表示できました。

Blueさんのコードで生成された画像と比較してみても同じだったのでこれでも
いけると思います。

古いスレッドには追加発言できません。