• 締切済み

DrawImageでビットマップを拡大したときの表示について

今、画像を拡大して表示する処理を作成しています。 実際の処理としては以下のような感じです。 Graphics^ g = Graphics::FromImage(picView->Image); g->InterpolationMode = Drawing2D::InterpolationMode::NearestNeighbor; g->DrawImage(imgTemp, 0, 0, nWidth * nScale, nHeight * nScale); 画像を拡大して表示すること自体はできているのですが、 拡大の基準点?がずれているような表示になるのが気になります。 たとえば、拡大前の画像が市松模様だったとして、拡大後は □□■■□□■■□□■■ □□■■□□■■□□■■ ■■□□■■□□■■□□ ■■□□■■□□■■□□ □□■■□□■■□□■■ □□■■□□■■□□■■ ■■□□■■□□■■□□ ■■□□■■□□■■□□(図1) のように表示して欲しいのですが、実際の表示は □■■□□■■□□■■ ■□□■■□□■■□□ ■□□■■□□■■□□ □■■□□■■□□■■ □■■□□■■□□■■ ■□□■■□□■■□□ ■□□■■□□■■□□(図2) のような感じで、左端と上端が半分くらいしか見えてない感じです。 (8倍に拡大したとして、4ピクセルの白、8ピクセルの黒…となっている感じです) (図1)のように表示されるにはどのようにすればいいでしょうか?

みんなの回答

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

GDI+で組んでも ドット欠けが起きるようですよ

回答No.2

 こんばんは。補足頂きました。  すんません、思いっきり的外れな事を書いてしまいました。Visual Studio 2008 C++/CLIで以下のコードで試して見ました。  見事に1ピクセル分ずれました。Graphics::DrawImage()メソッドのバグである可能性が濃厚です。  まともに等価倍率コピーが出来ないのですから、ルーペ表示的な機能を実装する上では、使い物にならないと思います。 private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { this->pictureBox1->Image = gcnew Bitmap("test.bmp"); this->pictureBox1->Image->Save("kakunin.bmp"); const int nWidth = this->pictureBox1->Image->Width; const int nHeight= this->pictureBox1->Image->Height; const int nScale = 2; Bitmap^ imgTemp = gcnew Bitmap(nWidth * nScale, nHeight * nScale, this->pictureBox1->Image->PixelFormat); Graphics^ g = Graphics::FromImage(imgTemp); g->InterpolationMode = Drawing2D::InterpolationMode::NearestNeighbor; g->DrawImage(this->pictureBox1->Image, 0, 0, nWidth * nScale, nHeight * nScale); imgTemp->Save("stretch.bmp");//此処で出力されたビットマップファイルもズレている this->pictureBox1->Image = imgTemp; this->pictureBox1->Invalidate(); }  win32 apiの出番かもしれません。以下でまともに出力されました。以下参考程度に。 #include<windows.h> #pragma comment(lib, "gdi32.lib") private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { this->pictureBox1->Image = gcnew Bitmap("test.bmp"); this->pictureBox1->Image->Save("kakunin.bmp"); const int nWidth = this->pictureBox1->Image->Width; const int nHeight= this->pictureBox1->Image->Height; const int nScale = 2; Bitmap^ imgTemp = gcnew Bitmap(nWidth * nScale, nHeight * nScale, this->pictureBox1->Image->PixelFormat); IntPtr iPtrDst = imgTemp->GetHbitmap(); IntPtr iPtrSrc = static_cast<Bitmap^>(this->pictureBox1->Image)->GetHbitmap(); HDC hDCDst = ::CreateCompatibleDC(NULL); HDC hDCSrc = ::CreateCompatibleDC(NULL); HBITMAP hBmpDst = static_cast<HBITMAP>(iPtrDst.ToPointer()); HBITMAP hBmpSrc = static_cast<HBITMAP>(iPtrSrc.ToPointer()); HGDIOBJ hBmpDstOld = ::SelectObject(hDCDst, hBmpDst); HGDIOBJ hBmpSrcOld = ::SelectObject(hDCSrc, hBmpSrc); ::StretchBlt(hDCDst, 0, 0, nWidth * nScale, nHeight * nScale, hDCSrc, 0, 0, nWidth, nHeight, SRCCOPY); ::SelectObject(hDCDst, hBmpDstOld); ::SelectObject(hDCSrc, hBmpSrcOld); ::DeleteDC(hDCDst); ::DeleteDC(hDCSrc); imgTemp = Bitmap::FromHbitmap(iPtrDst); imgTemp->Save("stretch.bmp"); ::DeleteObject(hBmpDst); ::DeleteObject(hBmpSrc); this->pictureBox1->Image = imgTemp; this->pictureBox1->Invalidate(); }

kis_red
質問者

お礼

どうもDrawImageを使う限り、この「ずれ」からは逃れられないみたいですね。 調べてみたところ、バグというよりは補間をした結果の「ずれ」みたいな感じです。 考え方の違いというか。 拡大前の座標が 0.5000~1.4999 になる範囲に 1.0000 の座標の色が拡大されている感じで。 言葉では説明しにくいんですが、  元々の画素を拡大後の座標に配置    ↓  開いた隙間を、配置した画素の色(の範囲)を広げて埋める みたいな感じですかね? それぞれの画素から滲み出した色が(混ざらないで)広がった結果、こうなった的な。 Win32APIを使う方法は今までもやったことはあるんですが、あまりC++的じゃないというか、純粋なCっぽいので避けてました。 今回はWin32APIのお世話になるのが正解なんでしょうかね。 ひとまずDrawImageはやめてWin32APIでやってみます。 ありがとうございました。

回答No.1

 こんにちは。  恐らく、  g->InterpolationMode = Drawing2D::InterpolationMode::NearestNeighbor;  辺りが原因かもしれません。  http://msdn.microsoft.com/ja-jp/library/system.drawing.drawing2d.interpolationmode(VS.80).aspx  上記の、  g->InterpolationMode = Drawing2D::InterpolationMode::Default;  又は、  g->InterpolationMode = Drawing2D::InterpolationMode::Invalid;  辺りで試されて見ては如何でしょうか。

kis_red
質問者

補足

~::Defaultなどでは拡大したときに補完をしてしまいます。 今回やりたいのは、ルーペツールなどのように「そのまま」拡大する処理なんです。 こういった処理はDrawImageではできないんでしょうか?

関連するQ&A

  • 色の変更

    また分からないことが出来ましたので、よろしくお願いいたします。 今、openFileDialogで画像を読取、その画像の黒色を白色に変更してpicutreBoxに表示するプログラムを作成しています。 [C#] Bitmap img = new Bitmap(openFileDialog.FileName); Graphics g = Graphics.FromImage(img); System.Drawing.Imaging.ColorMap[] cms = new System.Drawing.Imaging.ColorMap[] {new System.Drawing.Imaging.ColorMap(), new System.Drawing.Imaging.ColorMap()}; cms[0].OldColor = Color.Black; cms[0].NewColor = Color.White; System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes(); ia.SetRemapTable(cms); g.DrawImage(img, new Rectangle(img.Width + 10, 0, img.Width, img.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel,ia); g.Dispose(); PictureBox1.Image = img; という風に作成したのですが、色が変更されませんでした。 どこが違うのか分かられる方がいらっしゃいましたら、よろしくお願いいたします。

  • C# Picturebox 縮小・拡大時の表示方法

    下記のようなコードで、画像の拡大・縮小を行っています。 ただ画像の縮小時、PictureBox内の余分な部分について、(1)縮小前の 画像が残像のように表示されています。 また通常、画像の拡大・縮小前の画像では画像サイズがPictureBoxよりも大きいサイズの 場合、スクロールバーを表示するようにしています。 (2)でも、画像拡大時、スクロールバーが出るには出ているのですが、画像全てを 確認できません。 (1)、(2)の問題について、解決方法をご存知の方、お願いです、、、教えてください。。。 かなり、困ってます。。。。 Bitmap img = new Bitmap(pictureBox1.Image.Tag.ToString()); //PictureBox1のGraphicsオブジェクトの作成 Graphics g = pictureBox1.CreateGraphics(); //拡大・もしくは縮小 RectangleF rect = new RectangleF(0, 0, zoom * img.Width, zoom * img.Height); g.DrawImage(img, rect); //BitmapとGraphicsオブジェクトを破棄 img.Dispose(); g.Dispose();

  • (VB.net)画像の一部を切り取って,拡大・縮小したい

    内容を見ていただき,ありがとうございます。 タイトルのままですが,PictureBoxに画像を出して,その一部を切り取ったうえで拡大・縮小させるプログラムを作成しています。 今のところ,画像の一部を切り出すことはできたのですが,これを拡大・縮小させる方法をご存じないでしょうか。画像の一部を切り出すソースは以下のとおりです。 まず,フォームにピクチャボックス(PictureBox1)とコマンドボタン(Button1)を配置し,ソリューションを置いているフォルダ内のbinフォルダにWinter.jpg(WinXPのマイピクチャに入っているものです)を入れておきます。次に,Button1のコードとして,以下のものを打ち込みました。 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Bitmapオブジェクトの作成(切り取り元画像の指定) Dim bmap = New Bitmap("winter.jpg") '切り取る範囲をRectanleで指定 Dim rect As New Rectangle(10, 20, 100, 200) 'PictureBox1のGraphicsオブジェクトの作成 Dim g As Graphics = PictureBox1.CreateGraphics() '元の画像の指定部分を切り取ってPictureboxの左上隅(x,y = 0,0)に表示する.単位はピクセル. g.DrawImage(bmap, 0, 0, rect, GraphicsUnit.Pixel) 'Graphicsオブジェクトを破棄 g.Dispose() End Sub 以上です。 おそらく,DrawImageの部分を変えればいけるのではないかと思われるのですが,いかがでしょうか。ご助言よろしくお願いいたします。

  • drawimageを使いつつ背景を綺麗に表示させる方法について

    ぶしつけで申し訳ありません。 タイマー処理でdrawimageを使いキャラクターを規則的に動かしてるのですが、 drawimageにてアイテムを動かす場合には、現状g.clear(color.black)で背景を塗りつぶし 再描画する事によって動いているように見せている状況です。 ですがこの方法だとクリアした時に切れ目が出来、背景を表示させたいのにチカチカしてしまいます。 理想的な形としてはdrawimageだけを再描画出来れば背景が消えずにすむ筈なのですが 知らない構文が多すぎて出来るのか出来ないのかわからない状況です。 私が対処した方法(もちろん駄目でしたが)としては (1)g.clear(color.tranceparent) 透明色で削除 結局切れ目が出来ました (2)タイマーに背景描画処理を直書 これも気休めでぶつ切りになってしまいました このまま解決しないととてもシンプルなものになってしまい寂しいので 何とか背景を表示させたいと思っています。 詳しい方がいらっしゃいましたら教えてください。

  • C# DrawImage 物理サイズでなく、ピクセルサイズでの描画

    C# で、 Image img = new Bitmap(fileName); Point p = this.PointToClient( new Point( e.X, e.Y ) ); で画像と描画位置を決め、 e.Graphics.DrawImage(img, p); で、そこに画像を描画するのですが、写真によって、同じ1024*768ピクセルなのに、表示される大きさがばらばらです。 Graphics.DrawImage メソッド (Image, Point)の説明を読むと、「指定した位置に、指定した Image を元の物理サイズで描画します」とあり、「元の物理サイズで描画」に問題があることがわかりました。 質問ですが、「指定した位置に、指定した Image をピクセルサイズで描画」するメソッドは何でしょう?探し方が悪いのか、見つけられません。

  • VB2005 でビットの深さ8の画像を処理したい。

    VB2005を使って簡単な画像処理のツールを制作しています。 処理内容は、画像ファイル(jpg)を読み込み、画像を縦に区切って 左側と右側を別のファイルに保存する、という処理です。 縦に区切る位置(x 座標)は、自由に指定できます。 上記のような処理を「任意の解像度(0~300 dpi)、ビットの深さ 8 」 の画像で行うには、どのようにしたらよいのでしょうか。 (ビットの深さ 8 の image からは Graphics オブジェクトを  作ることができず、そのため、読み込んだ画像の解像度を  保てませんでした。) ビットの深さが 24 の画像は、以下のようにして問題なく動きました。 "scanfile01.jpg" は、 解像度 300dpi / ビットの深さ 24 / 縦1500 × 横1200 ピクセル の画像ファイルです。 --------------- private sub splitImage()  '画像(src)の読み込み  Dim fs As New IO.FileStream("scanfile01.jpg", _     IO.FileMode.Open)  Dim src As Image = Image.FromStream(fs, False, False)  Dim srcG As Graphics = Graphics.FromImage(src) '解像度の取得用  'src を分割する位置(x座標)  '(横幅1500 の scanfile01.jpg を左右半分に分ける)  Dim cutx As Integer = 750   'src の左側を格納する Bitmap を新規作成  '(src の解像度を引き継ぐ)  Dim destLeft As Image = New Bitmap(cutx, src.Height, srcG)  Dim rect As New Rectangle(0, 0, cutx, src.Height)  Dim destLeftG As Graphics = Graphics.FromImage(destLeft)  Dim rect As New Rectangle(0, 0, cutx, src.Height)  destLeftG.DrawImage(src, 0, 0, rect, GraphicsUnit.Pixel)  'src の左側をファイルに保存  destLeft.Save("scanfile01-left.jpg" _         , System.Drawing.Imaging.ImageFormat.Jpeg)  destLeft.Dispose()  destLeftG.Dispose()  'src の右側を格納する Bitmap を新規作成  ~省略~  srcG.Dispose()  src.Dispose()  fs.Dispose() End Sub ---------------- ビットの深さ 8 の画像を読み込むと、実行時に  Dim srcG As Graphics = Graphics.FromImage(src) '解像度の取得用 の部分で「インデックス付きのピクセルから Graphics オブジェクトを作成できません」というエラーが発生します。 そこで、解像度は引き継がずに、以下のように変更してみました。 ・srcG の定義文を削除 ・destLeft の定義時に解像度は指定せず、以下のように変更   Dim destLeft As Image = New Bitmap(cutx, src.Height) すると、エラーは発生せずファイルが作成されましたが、 解像度が引き継がれずに元の画像よりずっと小さな画像になって 作成されていました。 (作成されたファイルを開くと、イメージが小さくなった分、  黒い隙間ができていました。) 300 dpi の画像を読み込んだので、VB2005 で作成される?Bitmap のデフォルトの解像度 96 dpi に変換される際にピクセル抜けが 発生して画像が小さくなったのだと思います。 ビットの深さ 8 の画像を半分に区切ってファイルに保存する方法は ないのでしょうか。また、任意の解像度でピクセル抜けが 発生しないようにしたいです。

  • 奇数の判断について・・・・・・・・

    y座標が16で割ると余り1になるようなすべてのピクセルを白(RGB成分の輝度値が255)にした画像を生成したい場合・・・・・・・・・ /* nWidth:画像の幅、nHeight:画像の高さ*/ /* x座標とy座標の値を足すと奇数になるすべてのピクセルを白(RGB成分の輝度値が255)にする画像を生成する */  for(j = 0; j < nHeight; j++)   for(k = 0; k < nWidth; k++)   if(k%16==1)     {     DllBmpSetPixelValueR(pBmpOrig, j, k, 255);     DllBmpSetPixelValueG(pBmpOrig, j, k, 255);     DllBmpSetPixelValueB(pBmpOrig, j, k, 255);    } と条件式としましては、if(k%16==1)な感じでも大丈夫でしょうか? すみませんがアドバイスお願いします。。。。。。

  • 画像処理 C言語 元画像の幅と高さ

    Cで画像処理を勉強しています。 img.nHeightやimg.nWidthのように読み込んだ元画像の幅と高さを表す変数はないのでしょうか。 教材では、幅と高さは手動で打つようになっていました。

  • C# PictureBoxへの描画を行うとメッセージボックスが表示されません。

    いつもお世話になっております。 ふと、PictureBoxに描画をしてみようかと思い Paintイベントに以下のようにして描画を行いました。   myBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);   Graphics g = Graphics.FromImage(myBitmap);   pictureBox1.Image = myBitmap;      ・      ・(g.FillRectangle(・・・);など)      ・ (myBitmapはBitmap型のグローバル変数です。) PictureBoxは、自由にサイズ変更可能なフォームに貼り付け、四方をanchorで固めています。 そのためサイズが変更されるたびに、描画するときBitmapのサイズも変更しないといけないので この処理を毎回通っています。 (その部分が何だか無駄な気がするのですが、他にいい方法が思いつきませんでした。) ところが、描画はうまくいったのですが、メッセージボックスを出すと そのメッセージボックスが一度Altキーを押さないと表示されません。 色々調べて、ダブルバッファリングというものがあると知りました。 そこでPaintイベントで最初にこの処理をし   Image image = new Bitmap(pictureBox1.Width, pictureBox1.Height);   g = Graphics.FromImage(image); gに描画し終わってから   e.Graphics.DrawImage(image, 0, 0); としてみると、今度はフォームを移動するのにも一瞬フリーズするようになってしまいました。 (あまり深くプログラミングをしたことがないので、理解しきれなくてやり方が悪いのかも知れません・・・) メッセージボックスが表示されないのは、PictureBoxの描画のため 他のコントロールの描画ができていなためだと推測しているのですが どう直していいかわかりません。 どなたか、わかる方がいましたらよろしくお願いします。 <補足> OS:Vista VisualStudio2008 .NET Framework3.5

  • iモードって自動的に拡大表示されるのですか?

    iモードってウェブページを見ると自動的に拡大表示されてしまう仕様なのでしょうか。 私の液晶は480x854の超高解像度です!! これは10ピクセルの文字なら、1行に48文字表示できる計算なのですが、実際には10文字ぐらいしか表示されません。 文字が4倍ぐらいに拡大されていると思われます。 CSSで厳密に文字サイズを指定しても無視されてしまうようです。 画像に関しては、横の長さが240ピクセルの画像が画面の横幅いっぱいに表示されています。ようは2倍に拡大されてしまっているわけです。 <IMG width="240">のように厳密に画像の横幅を指定しても無視されてしまうようです・・・。 iモード専用のHTMLタグが存在するのでしょうか。 iモードの文字を4倍、画像を2倍に拡大表示する機能を無効にしたいです。