开发者

Graphics wrong image interpolation in .Net

开发者 https://www.devze.com 2023-04-10 20:08 出处:网络
I have an simple test. When it is solved, my problem is solved too. When working with small images, the graphics interpolation does bad work.

I have an simple test. When it is solved, my problem is solved too. When working with small images, the graphics interpolation does bad work.

Please check out if you know how to fix the problem that the result image in the following code does ignore second half of image to draw. Draw something on the imag开发者_StackOverflow中文版e by using loadimage from JPG or whatever you want.

    Dim GrayImage as system.drawing.Bitmap(640,480)    
    Dim bmTmp As New System.Drawing.Bitmap(GrayImage.Width, 1)
    Using gr As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmTmp)
         gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None
         gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear
         gr.DrawImage(GrayImage, New System.Drawing.Rectangle(0, 0, bmTmp.Width, bmTmp.Height), New System.Drawing.Rectangle(0, 0, GrayImage.Width - 0, GrayImage.Height - 0), System.Drawing.GraphicsUnit.Pixel)
     End Using

     GrayImage = New System.Drawing.Bitmap(GrayImage.Width, GrayImage.Height, GrayImage.PixelFormat)
     Using gr As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(GrayImage)
         gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None
         gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor
         gr.DrawImage(bmTmp, New System.Drawing.Rectangle(0, 0, GrayImage.Width, GrayImage.Height ), New System.Drawing.Rectangle(0, 0, bmTmp.Width - 0, bmTmp.Height - 0), System.Drawing.GraphicsUnit.Pixel)
     End Using

Graphics wrong image interpolation in .Net

Download original Source here: http://www.goldengel.ch/temp/Source01%20one%20Pixel.jpg (one Pixel height image)

Graphics wrong image interpolation in .Net

The second half vertical is not drawn by using the DrawImage methode. I want to have the image as result as you see on first picture. Stretched image with source on whole content.

* DOWNLOAD* Download here full working VS2010 VB.Net demo project:

VS2010 Scaling Project with description - Timo Böhme


Please try to add:

gr.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality

to your last clause. GDI magic I guess :)

Hope this helps!


I had a similar problem which I had solved by resizing the original image. I guess this is an expected behaviour, not a bug (usual MS explanation but for this case it might be right :)). Some interpolation algorithms reqiure more than one pixel line (applies to both axes) to work correctly. If there is no second line, they may interpolate to an empty line which causes that problem above. You may change you image width/height to 2 pixels minimum or use proper interpolation methods for single line images.


As @EmirAkaydin said in his answer, your problem lies with the interpolation. I suspect his answer about it only being one pixel high, conflicting with Microsoft's resize algorithm, is correct.

I have a two step solution for you. Unless you want to write your own resize code (I didn't want to) that resizes exactly as you want, you could still use the Graphics.DrawImage function to at least resize the width of your image, but only the width. Then you can manipulate the pixel data directly and copy each that first valid line, for the entire height of the image.

You can replace your DoDemo code with the following (I don't use VB, so I'm not sure about the coding style; it does work, however):

    Call CreateSampleImage()

    'scale the image to only one single row
    Dim bm As New Bitmap(450, 1)
    Using gr As Graphics = Graphics.FromImage(bm)
        Dim RDst As New Rectangle(0, 0, bm.Width, bm.Height)
        Dim RSrc As New Rectangle(0, 0, Me.PictureBox1.Image.Width, Me.PictureBox1.Image.Height)

        gr.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
        gr.SmoothingMode = Drawing2D.SmoothingMode.None
        gr.DrawImage(Me.PictureBox1.Image, RDst, RSrc, GraphicsUnit.Pixel)
    End Using
    Me.PictureBox2.Image = bm

    'stretch now the single row image back to original width
    Dim bm2 As New Bitmap(Me.PictureBox1.Image.Width, Me.PictureBox1.Image.Height)
    Using gr As Graphics = Graphics.FromImage(bm2)
        Dim RDst As New Rectangle(0, 0, bm2.Width, 1)
        Dim RSrc As New Rectangle(0, 0, Me.PictureBox2.Image.Width, Me.PictureBox2.Image.Height)

        gr.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
        gr.SmoothingMode = Drawing2D.SmoothingMode.None
        gr.DrawImage(Me.PictureBox2.Image, RDst, RSrc, GraphicsUnit.Pixel)
    End Using

    ' use our own custom height stretch code
    Dim rrc As New Rectangle(0, 0, bm2.Width, bm2.Height)
    Dim bmd As BitmapData

    bmd = bm2.LockBits(rrc, ImageLockMode.ReadWrite, bm2.PixelFormat)

    ' stride is the width of the image in pixels
    Dim ba(bmd.Stride - 1) As Byte
    Marshal.Copy(bmd.Scan0, ba, 0, bmd.Stride)

    ' copy pixel data to each line
    For y = 1 To bmd.Height - 1
        Marshal.Copy(ba, 0, bmd.Scan0 + (y * bmd.Stride), ba.Length)
    Next

    bm2.UnlockBits(bmd)

    Me.PictureBox3.Image = bm2

EDIT:

Interestingly enough, the code @FredrikJohansson posted will work as well:

gr.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality

right before you draw the image. I'm going to leave this code and answer here, in case anyone ever wants to see it, but it looks like he answered your question in an easier way :)


Have you tried NearestNeighbor interpolation?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号