Efficiently resizing an image with a pixel resize
-
I know there are functions built into .NET that will resize images, but they don't do what i want. I am making an icon editor, and it needs to be able to resize images with a pixel resize. That is a type of resize where if you zoom in enough you can actually see the individual pixels of the original images, like Paint Shop Pro or Photoshop (or even paint) do. I have make an algorithm to do this, but it is unbelievably slow, and i need to make it do this almost instantly. I am using the Bitmap class and the Bitmap.GetPixle\Bitmap.SetPixle methods. Here is my algorithm:
Public Shared Function ResizePixles(ByVal image As Bitmap, ByVal factor As Integer) As Bitmap On Error Resume Next Dim rbmp As New Bitmap(image.Width \* factor, image.Height \* factor) For x As Integer = 0 To image.Width - 1 For y As Integer = 0 To image.Height - 1 Dim c As Color = image.GetPixel(x, y) For x2 As Integer = x \* factor To x \* factor + factor - 1 For y2 As Integer = y \* factor To y \* factor + factor - 1 rbmp.SetPixel(x2, y2, c) Next Next Next Next Return rbmp End Function
As you can see, i have 4 For loops in my code, which makes it very slow.
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
-
I know there are functions built into .NET that will resize images, but they don't do what i want. I am making an icon editor, and it needs to be able to resize images with a pixel resize. That is a type of resize where if you zoom in enough you can actually see the individual pixels of the original images, like Paint Shop Pro or Photoshop (or even paint) do. I have make an algorithm to do this, but it is unbelievably slow, and i need to make it do this almost instantly. I am using the Bitmap class and the Bitmap.GetPixle\Bitmap.SetPixle methods. Here is my algorithm:
Public Shared Function ResizePixles(ByVal image As Bitmap, ByVal factor As Integer) As Bitmap On Error Resume Next Dim rbmp As New Bitmap(image.Width \* factor, image.Height \* factor) For x As Integer = 0 To image.Width - 1 For y As Integer = 0 To image.Height - 1 Dim c As Color = image.GetPixel(x, y) For x2 As Integer = x \* factor To x \* factor + factor - 1 For y2 As Integer = y \* factor To y \* factor + factor - 1 rbmp.SetPixel(x2, y2, c) Next Next Next Next Return rbmp End Function
As you can see, i have 4 For loops in my code, which makes it very slow.
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
Hi, I haven't used this myself as of late, but are you aware Graphics has an InterpolationMode property, which accepts values such as NearestNeighbor, basically just duplicating pixels, not inventing new ones? If you only need to see it scaled up, use it in a Panel's OnPaint; if you really also need the new Bitmap, do Graphics.FromImage(rnmp) then Graphics.DrawImage :)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
-
Hi, I haven't used this myself as of late, but are you aware Graphics has an InterpolationMode property, which accepts values such as NearestNeighbor, basically just duplicating pixels, not inventing new ones? If you only need to see it scaled up, use it in a Panel's OnPaint; if you really also need the new Bitmap, do Graphics.FromImage(rnmp) then Graphics.DrawImage :)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
I have tried all the items in the InterpolationMode when resizing an image with a graphics class, but none produced the result i wanted. I will try with the NearestNeighbor item again, and see if i am mistaken. Also, could you (or anyone) please elaborate on what you ment by the OnPaint thing?
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
modified on Tuesday, July 15, 2008 6:49 PM
-
I have tried all the items in the InterpolationMode when resizing an image with a graphics class, but none produced the result i wanted. I will try with the NearestNeighbor item again, and see if i am mistaken. Also, could you (or anyone) please elaborate on what you ment by the OnPaint thing?
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
modified on Tuesday, July 15, 2008 6:49 PM
Hi, You did not specify how exactly it does not what you want. Three ideas: 1) I ran a little experiment, and it seems to work fine, with one proviso: the NearestNeighbour does duplicate pixels, but due to the nearest (not the left) source pixel, it will not duplicate the leftmost/topmost pixel a sufficient number of times. So to be exact, you should proceed as follows (I'll explain in one dimension): input width w1, output width wanted w2, scalefactor f=w2/w1 (use reals for scale!) split the output in three regions, with widths wa,wb,wc wa=f/2 <--- represents half an input pixel wb=(w1-1)*f wc=w2-wa-wb <--- represents half an input pixel now duplicate the leftmost pixel of input to wa, duplicate the rightmost pixel of input to wc, finally do the DrawImage scale with nearestneighbour from w1 to wb (i.e. shifted by wa) That should put every single pixel at the right spot. 2) I am pretty sure the complex copying of the edges could be handled by DrawImage itself, provided you give it appropriate parameters. 3) As an approximation you could do a two step approach: - do DrawImage with Normal InterpolationMode for the full size; - do DrawImage with NearestNeighbour InterpolationMode for a size that is half a pixel smaller on all four edges of the output image (don't modify the input sizes!) :)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
-
Hi, You did not specify how exactly it does not what you want. Three ideas: 1) I ran a little experiment, and it seems to work fine, with one proviso: the NearestNeighbour does duplicate pixels, but due to the nearest (not the left) source pixel, it will not duplicate the leftmost/topmost pixel a sufficient number of times. So to be exact, you should proceed as follows (I'll explain in one dimension): input width w1, output width wanted w2, scalefactor f=w2/w1 (use reals for scale!) split the output in three regions, with widths wa,wb,wc wa=f/2 <--- represents half an input pixel wb=(w1-1)*f wc=w2-wa-wb <--- represents half an input pixel now duplicate the leftmost pixel of input to wa, duplicate the rightmost pixel of input to wc, finally do the DrawImage scale with nearestneighbour from w1 to wb (i.e. shifted by wa) That should put every single pixel at the right spot. 2) I am pretty sure the complex copying of the edges could be handled by DrawImage itself, provided you give it appropriate parameters. 3) As an approximation you could do a two step approach: - do DrawImage with Normal InterpolationMode for the full size; - do DrawImage with NearestNeighbour InterpolationMode for a size that is half a pixel smaller on all four edges of the output image (don't modify the input sizes!) :)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
Thanks! With your help, i managed to figure it out. A while back, i posted this question on both ProgrammersHeaven.com and DreamInCode.net and i didn't get an answer on either site. Thanks so much! :-D
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
-
Thanks! With your help, i managed to figure it out. A while back, i posted this question on both ProgrammersHeaven.com and DreamInCode.net and i didn't get an answer on either site. Thanks so much! :-D
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
You're welcome. Glad to be of help. :)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
-
I have tried all the items in the InterpolationMode when resizing an image with a graphics class, but none produced the result i wanted. I will try with the NearestNeighbor item again, and see if i am mistaken. Also, could you (or anyone) please elaborate on what you ment by the OnPaint thing?
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
modified on Tuesday, July 15, 2008 6:49 PM
Hi, I once assembled a short text giving the essentials of painting: there are several steps to draw something so it becomes visible on the screen: 1. decide upon what object you want to draw; it normally is a Control (e.g. a Panel) or a Form itself. I prefer to add a Panel to a Form, then draw on the Panel. 2. create some variables (Rectangle, struct, class, whatever) that hold the parameters of your drawing. For a rectangle that could be top and left coordinate, and width+height, or just a Rectangle. etc. 3. create a Paint handler (either add your own paint handler to the Paint event, or override the OnPaint method) for that Panel, and do all your drawing in there, using the Graphics class and your variables. 4. when you want to change things, modify the variables and call Panel.Invalidate() or one of its overloads (for selective invalidation). 5. If you want to animate things, perform the move (step 4) inside the Tick handler of a Windows.Forms.Timer BTW: if you need to create some objects (Fonts, Pens, Brushes, ...) either keep them alive in class members (hence create them only once); or create them inside the Paint handler and don't forget to call Dispose() on them. :)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
-
I have tried all the items in the InterpolationMode when resizing an image with a graphics class, but none produced the result i wanted. I will try with the NearestNeighbor item again, and see if i am mistaken. Also, could you (or anyone) please elaborate on what you ment by the OnPaint thing?
if (your.Life == lifestyles.Programming) { your.Cool = true; } else { your.Cool = false; }
modified on Tuesday, July 15, 2008 6:49 PM
Hi, in my latest experiment, I came up with a really simple way of modifying nearestneighbour into copy_from_left/top; it suffices to indicate half a pixel translation, as in this C# code. The source image has size (w,h) and is translated to (x,y) and scaled up by the fraction zoomT/zoomN:
Rectangle r=new Rectangle(x, y, w\*zoomT/zoomN, h\*zoomT/zoomN); g.InterpolationMode=InterpolationMode.NearestNeighbor; g.DrawImage(image, r, -0.5f, -0.5f, w, h, GraphicsUnit.Pixel);
So instead of using the pixels 0, 1, 2, ... w-1 of the source image, I am actually using the pixels -0.5, 0.5, 1.5, ... w-1.5 which means whenever I need something in some interval (say the first -0.5 to 0.5) it will take the nearest integer, which is the middle of the translated interval, i.e. the left/top of the original interval! Can't get more simple than that. :)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|