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
* 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?
精彩评论