DrawImageを使った画像の拡大について

タグの編集
投稿者 反る戸  (社会人) 投稿日時 2010/2/9 03:39:42
DrawImageを使って、画像の一部を拡大し、それを敷き詰めて別の画像
を作成しようと思ったのですが、うまくいきません。

 次のような画像があるとします。本当はもう少し大きいのですが、説明
の都合で、6×3ピクセルの大きさで、赤(r)と緑(g)のピクセルが交互に
並んでいるとします。
rgrgrg
grgrgr
rgrgrg

 これを縦横2倍18×6ピクセルにした場合、補間を最低品質にすれば、
以下のようになると期待します。
rrggrrggrrgg
rrggrrggrrgg
ggrrggrrggrr
ggrrggrrggrr
rrggrrggrrgg
rrggrrggrrgg

 ところが実際には次のように右端と下端は何も描画してくれません。
0というのは描画しない、又は、透明で描画しているということです。
rggrrggrrgg0
grrggrrggrr0
grrggrrggrr0
rggrrggrrgg0
rggrrggrrgg0
000000000000

 これを調べる為に以下のようなプログラムを実行してみました。2倍の
場合、上記のような描画になり、2倍+1ピクセルに拡大すると、当初に
期待したような描画になります。しかし、うまくいくのは2倍だけで3倍
になると、2倍でも、2倍+1でもうまくいきません。うまくいかないと
いうのは、3×3の四角が交互に並んだような画像にならないということ
です。

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim imgWid As Integer = Me.PictureBox1.Width
        Dim imgHei As Integer = Me.PictureBox1.Height
        Dim mag As Integer = 2  ' 拡大率
        Dim gr2 As Graphics
        Dim gr3 As Graphics
        Dim gr4 As Graphics
        Dim rect1 As Rectangle = New Rectangle(0, 0, imgwid, imghei)
        Dim rect2 As Rectangle = New Rectangle(0, 0, imgWid, imgHei)
        Dim rect3 As Rectangle = New Rectangle(0, 0, mag * imgWid, mag * imgHei)
        Dim rect4 As Rectangle = New Rectangle(0, 0, mag * imgWid + 1, mag * imgHei + 1)

        Me.PictureBox1.Image = Image.FromFile("..\..\..\RedGreen.png")
        Me.PictureBox2.Image = New Bitmap(imgwid, imghei)
        Me.PictureBox3.Image = New Bitmap(mag * imgWid, mag * imgHei)
        Me.PictureBox4.Image = New Bitmap(mag * imgWid, mag * imgHei)
        gr2 = Graphics.FromImage(Me.PictureBox2.Image)
        gr3 = Graphics.FromImage(Me.PictureBox3.Image)
        gr4 = Graphics.FromImage(Me.PictureBox4.Image)
        gr2.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        gr3.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        gr4.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        gr2.DrawImage(Me.PictureBox1.Image, rect2, rect1, GraphicsUnit.Pixel)
        gr3.DrawImage(Me.PictureBox1.Image, rect3, rect1, GraphicsUnit.Pixel)
        gr4.DrawImage(Me.PictureBox1.Image, rect4, rect1, GraphicsUnit.Pixel)
    End Sub
End Class

 DrawImageの使い方について、私が何か勘違いをしているのか、それ
とも、他の方法を使うべきなのか、ご教示いただければ幸いです。
投稿者 (削除されました)  () 投稿日時 2010/2/9 04:25:14
(削除されました)
投稿者 cupid  (社会人) 投稿日時 2010/2/9 20:10:05
画像を、画素レベルである規則に従って拡大したい場合、
DrawImageを使うのが適切かどうか疑問です。
画素イメージをデータテーブルに展開して、次に拡大テーブルを定義して、
アドレス(インデックス)を計算して、値を写す方法も考えられますね。

ImageDataの取得は、やや面倒な手続きが必要だから、小さい画像なら、
GetPixelを使えば良いですよ。埋め込みはSetPixelですね。
200×200ぐらいまでなら、十分実用になると思います。
投稿者 YuO  (社会人) 投稿日時 2010/2/9 21:10:28
0.5ピクセル分ずれている,という話でしょうか。
座標系はピクセルの左上を指定するが,拡大時のピクセルの色はピクセルの中央(0.5, 0.5)を参照する為にずれが起きる,というものです。

GraphicsのPixelOffsetModeプロパティを,Halfに設定してみてはどうでしょうか。

MSDN: Graphics.PixelOffsetMode プロパティ (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/system.drawing.graphics.pixeloffsetmode.aspx
MSDN: PixelOffsetMode 列挙体 (System.Drawing.Drawing2D)
http://msdn.microsoft.com/ja-jp/library/system.drawing.drawing2d.pixeloffsetmode.aspx
投稿者 反る戸  (社会人) 投稿日時 2010/2/10 03:55:02
cupidさん、レスありがとうございます。
GetPixelとSetPixelは最後の手段としては考えております。

YuOさん、レスありがとうございます。
>GraphicsのPixelOffsetModeプロパティを,Halfに設定してみてはどうでしょうか。
 うまくいきました。2倍でも3倍でも期待通りの拡大が行われます。よもや、こんな
プロパティがあるとは思いもよりませんでした。
 本当にありがとうございました。
投稿者 (削除されました)  () 投稿日時 2010/2/10 07:36:55
(削除されました)