- 締切済み
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)のように表示されるにはどのようにすればいいでしょうか?
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- redfox63
- ベストアンサー率71% (1325/1856)
GDI+で組んでも ドット欠けが起きるようですよ
- machongola
- ベストアンサー率60% (434/720)
こんばんは。補足頂きました。 すんません、思いっきり的外れな事を書いてしまいました。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(); }
- machongola
- ベストアンサー率60% (434/720)
こんにちは。 恐らく、 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; 辺りで試されて見ては如何でしょうか。
補足
~::Defaultなどでは拡大したときに補完をしてしまいます。 今回やりたいのは、ルーペツールなどのように「そのまま」拡大する処理なんです。 こういった処理はDrawImageではできないんでしょうか?
お礼
どうもDrawImageを使う限り、この「ずれ」からは逃れられないみたいですね。 調べてみたところ、バグというよりは補間をした結果の「ずれ」みたいな感じです。 考え方の違いというか。 拡大前の座標が 0.5000~1.4999 になる範囲に 1.0000 の座標の色が拡大されている感じで。 言葉では説明しにくいんですが、 元々の画素を拡大後の座標に配置 ↓ 開いた隙間を、配置した画素の色(の範囲)を広げて埋める みたいな感じですかね? それぞれの画素から滲み出した色が(混ざらないで)広がった結果、こうなった的な。 Win32APIを使う方法は今までもやったことはあるんですが、あまりC++的じゃないというか、純粋なCっぽいので避けてました。 今回はWin32APIのお世話になるのが正解なんでしょうかね。 ひとまずDrawImageはやめてWin32APIでやってみます。 ありがとうございました。