|
|
Comments and Discussions
|
|
 |

|
I noticed there is no license specified for this code. Can you kindly provide license terms? Thanks.
|
|
|
|

|
Hi Christian,
I’m interested in using your Image Processing code. My employer requires we get an explicit license to use any third party code and I didn’t see any kind of license on your site. Would you be so kind as to reply to this message “Yes” indicating you are willing to grant my company and its successors the right to use your Image Processing algorithm under the BSD license set forth below.
Thanks,
Jeff Cutler-Stamm
_________________
BSD 2.0
Copyright (c) 2010, Christian Graus
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the Christian Graus nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|

|
Jeff, you may also want to check out AForge[^] (GLPL).
/ravi
|
|
|
|

|
Sorry, I just never did it. I've done it now.
Christian Graus
Driven to the arms of OSX by Vista.
Read my blog to find out how I've worked around bugs in Microsoft tools and frameworks.
|
|
|
|

|
I would like to create a bmp file 1 pixel by 1 pixel that has the same name as the file I am creating. THe issue I am having is simply the part of creating a bmp file in code. The fact that it is 1 pixel by 1 pixel means this image I really do not care for the end user to be able to see, as it's purpose is to block MS Access Splash Screen from showing when the mdb files are opening.
I can handle everything but the creation of a bmp file that is 1 pixel by 1 pixel in code. Can some one help me or point me in the direction of how to build such a bmp file in code without coping a recreated file.
|
|
|
|

|
Bitmap b = new Bitmap(1,1,ColorSpaceInfo); ? I forget how to specify the bit depth.
Christian Graus
Driven to the arms of OSX by Vista.
Read my blog to find out how I've worked around bugs in Microsoft tools and frameworks.
|
|
|
|

|
dear sir
i need a high speed method to make 4 image from one, that the first image have for example 2048*1536 pixel, and the four made is each 1024*768 , so i use the getpixel and setpixel method that is too slow :
vb.net code ::
For y = 0 To picy.Height - 1 Step 2
For x = 0 To picy.Width - 1 Step 2
pic(0).SetPixel(Int(x / 2), Int(y / 2), picy.GetPixel(x, y))
pic(1).SetPixel(Int(x / 2), Int(y / 2), picy.GetPixel(x + 1, y))
pic(2).SetPixel(Int(x / 2), Int(y / 2), picy.GetPixel(x + 1, y + 1))
pic(3).SetPixel(Int(x / 2), Int(y / 2), picy.GetPixel(x, y + 1))
Next x
Next y
please help me to find a very faster method in any languages, vc++ or vb or vc# or others , its not important i need a fast method,
thank you for attentions and cooperations.
|
|
|
|

|
Had you read my articles, you'd have found the answer to your question. All my articles use direct pixel access.
Christian Graus
Driven to the arms of OSX by Vista.
Read my blog to find out how I've worked around bugs in Microsoft tools and frameworks.
|
|
|
|

|
Bilinear Filtering is invalid for the binary image
|
|
|
|

|
What on earth are you talking about ?
Christian Graus
Driven to the arms of OSX by Vista.
Read my blog to find out how I've worked around bugs in Microsoft tools and frameworks.
|
|
|
|

|
I challenge anyone to show how to make this work in asp.net.
|
|
|
|

|
well it is done as if you are doing it with windows forms
|
|
|
|

|
How bizarre. This will work fine in ASP.NET, although it's not an ASP.NET article, and you'd need to process images on the server, then send them back to the client. I do't see any reason to do that, but it works just fine. Perhaps you just don't understand ASP.NET ?
Christian Graus
Driven to the arms of OSX by Vista.
Read my blog to find out how I've worked around bugs in Microsoft tools and frameworks.
|
|
|
|

|
As far as I can tell, this will only work for images that you resize slightly - between 50% and 100% of the original. Unless I am misunderstanding how bilinear resizing is supposed to work.
If I have an image that is 50x50 pixels in size and I want to resize it to 10x10, then each pixel in the smaller image must be the average of 25 pixels (5x5). This algorithm assumes that your "ceiling" and "floor" will never be more than 1 pixel appart.
As soon as you start resizing to less than 50% of the original size, you start dropping pixels and the one_minus_x and one_minus_y values become totally incorrect.
|
|
|
|

|
It is correct - you don't take a sample of more than 1 pixel, you calculate the exact pixel point of where the new pixel would be on the old image. You'll get a decimal value (eg: 26.675), and then you only have to take a certain percentage of the pixel on either side of it. This one stumped me too, and I thought the same as you however now I understand. I know it's 2 years ago, but maybe this will help someone else make sense of this :P
|
|
|
|

|
As someone else said, the whole point of a bilinear filter is to work out fuzzy values, where you do a resize that isn't perfect ( as 50x50 to 10x10 is, what if it was 11x11 ) ? It's used to calculate the color of an imaginary pixel that exists between two actual ones.
Christian Graus
Driven to the arms of OSX by Vista.
Read my blog to find out how I've worked around bugs in Microsoft tools and frameworks.
|
|
|
|

|
I just had an error when trying to resize a GIF and an exception was thrown because it is impossible to call SetPixel method on an indexed color image.
To fix this, just update a line in the Resize method:
b = new Bitmap(nWidth, nHeight, bTemp.PixelFormat);
You can use any PixelFormat enumeration value which doesnt stand for an indexed format.
For instance:
b = new Bitmap(nWidth, nHeight, PixelFormat.Format24bppRgb);
______________________
Mathieu Gardère
wam@mathieugardere.co.uk
|
|
|
|

|
A great Article from a great Author. Thanks Christian Graus.
I read many articles that you wrote, and they really rock!!
|
|
|
|

|
I have been struggling to use GDI+ for bilinear resizing of 16 bit greyscale bitmaps, as used often for terrain heightmaps, but have given up because it is so buggy (I understand now that MS have admitted the greyscale handling was never completed and wasn't intended to be shipped). I tried your code (adjusted for 16bit pixel data) and it worked great! 5 from me.
|
|
|
|

|
Hello, I have read your artical about GDI+ in www.codeproject.com
And I learn many from your articals.Thank you.
Now I have a question .Can you help me?
In your artical "Image Processing for Dummies with C# and GDI+ Part 5 - Displacement filters, including swirl" , there is a sphere effect .
Now I want to know how to make the concave effect, which is opposed to sphere effect. Can you help me?
niannina
|
|
|
|

|
The sphere effect, and most of these effects, where really the result of my playing with the framework I came up with, and so this does not represent my trying to write the best sphere filter in the world.
What you're talking about is texture mapping, you want to map the texture to the inside of a sphere. A google on texture mapping may give you some help in this area, also a barrel filter goes some of the way to doing something like this, that may be another term that will help you. I'm sorry not to give a more detailed answer, but right now I am really flooded with work. If you still need help in the new year, feel free to ask for more.
Christian Graus - Microsoft MVP - C++
|
|
|
|

|
Hi,
your Articles about Image Processing are very good, but
i need some help about dithering Images in C#.
I mean something like reducing Images to 1bit Bmps with
dithers like Floyd-Steinberg or Bayer 4x4...
Maybe you can do another article about dithering
Greets
LordK
|
|
|
|

|
Good idea. I didn't think anyone used that stuff anymore, I thought we were all on 24 bit displays and looking forward to HDR I'll consider doing something sometime soonish.
Christian
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
|
|
|
|
|

|
I know this post was made quite some time ago, but I thought I'd reply anyway:
Dithering is actually still necessary from time to time, even in 24 bit. For example, if your program draws a gradient and you want to avoid banding artifacts, there is no way around it, especially if the colors you are blending are very similar.
Even with 16 bit per channel and HDR, it is still an issue. For example, whenever an application displays a 16-Bit or HDR image on an 8-bit-per-channel screen (or saves an 8-bit JPEG for that matter), it should do dithering in order to get the highest quality possible. As far as I know Photoshop handles things that way.
Peter
|
|
|
|

|
Hi,
please look at the following images created by the GDI. The jpg has the quality set to 100 and is created using the getPixel setPixel method here http://www.codeproject.com/cs/media/imageprocessing4.asp
www.zona9.com/test/s.png
www.zona9.com/test/f.jpg
This is created using the save for web function of photoshop
www.zona9.com/test/p.jpg
Can someone please give me some pointers of how to create images close to the photoshop quality? Or where I can find better algorithms? I need them in JPG because they are used in flash.
Thanks
David
|
|
|
|

|
The only point of this article is to show how bilinear filters work. If you just want to resize a bitmap, just get GDI+ to do it for you on it's best filtering quality setting.
The file format is irrelevant. You always deal with BMP format images in memory, then encode them to save them.
Christian
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
|
|
|
|

|
Hi Christian, I agree with what you are saying, but I am not resizing. I am trying to add text to an image, but the quality of the text is poor. Thats why I decided to try creating a filter. You seem quite knowledgeable about filters and I thought you might know a way of improving the quality of the GDI generated JPG's.
Another quick question, I think i'm going to write a JPEG codec. Where do you find your information on algorithms etc and do you know where I can find a JPG file specification
David
|
|
|
|

|
You're going to write a JPEG codec ? Well, there already is one, called jpeglib, from memory.
The quality of the text is poor before or after you save it ? There are modes you can set in GDI+ to improve text quality, from memory.
Christian
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
|
|
|
|

|
In general, JPG isn't very good for small text, due to its algorithms' target for photographic images.
PNG is good because it doesn't use the same type of lossy image compression. (It just uses a different kind, if at all, I think)
|
|
|
|

|
Hi,
Ok, you just wrote this article to demonstrate the bilinear filtering, but I was telling myself that you should inverse your "for" loops, to bring the "y" BEFORE "x" in the looping process. That's the way image is stored in memory.
Just do :
for (int y = 0; y < b.Height; ++y)
for (int x = 0; x < b.Width; ++x)
instead of :
for (int x = 0; x < b.Width; ++x)
for (int y = 0; y < b.Height; ++y)
and so the buffer will be read in a linear way...
|
|
|
|

|
Well, seeing as I use Get/SetPixel to simplify the code, and make the bilinear filtering code clearer, how on earth would it make any difference ?
Christian
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
|
|
|
|

|
Well, this way, put a Sleep(50); in your loop and see the process doing his job...
|
|
|
|

|
I'm not sure what you're trying to say ? GetPixel is slow, I note that in the article, and all my other articles do not use it for that reason. I also note in this article that I used it to simplify the other code, to make the code that does the filtering stand out. Because of this, the order in which I iterate through pixels is totally irrelevant, it will always be the same speed, and slower than direct pixel access.
Christian
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
|
|
|
|

|
The order is actually relevant...
GetPixel is slow because it has out of bounds protection code. Accessing images against scanline order is slow because of the way modern processors work. They read a chunk of memory (slow) into a cache close to the CPU (fast). Next time you try to read from memory your computer first looks in the cache. If it finds the memory address cached it doesn't have to access the slow memory, thus everything becomes a lot faster. Depending on the size of the cache (typically between 512kb and 2mb for different level caches) they can fit more or less data into it. If you read in scanorder (row-by-row) you guarantee that the cache needs to be refreshed the least number of times. When you read against scanorder (column-by-column) it can happen that the cache needs to be refreshed every couple of pixels. This is very bad for performance.
For a demo article it might not matter much, but it is always good practice to keep these things in mind, and, all other things being equal (as you said: why should it matter), do it row-by-row instead.
|
|
|
|

|
Should this code handle downsizing of images correctly? I don't think it does...let me explain:
If you (for example) want to rescale an image from 640*480 to 320*240, nXFactor and nYFactor are both 2. They have no fractional part. This leads to fraction_x and fraction_y to be always 0 and one_minus_x and _y to be always 1. This way, only b1 counts for the color components and that means: no filtering at all. Am i right? I've implemented your algorithm in Java and that's exactly the problem i'm getting. But i really don't know what to do to handle this problem.
|
|
|
|

|
This code was written to show how bilinear filters work, and not to replace the resizing that GDI+ does by itself. You obviously want to make a fraction value of .5 when downsizing to an exact factor as you are. The code as it is written will probably not do that, but it should not be hard to change.
Christian
I have several lifelong friends that are New Yorkers but I have always gravitated toward the weirdo's. - Richard Stringer
|
|
|
|

|
Thanks for the quick reply. That's what i came up with too, but it's still not what i want. But after some more thinking, i ralized that bilinear filtering is not the way to go in this case. I've compared it Java's way of resampling images and i wanted to achieve the same at a faster speed and i thought they were using simple bilinear...but they don't...
|
|
|
|

|
Hi Christian
Thanks for this great series of articles on GDI+. As a result of these articles I quickly learnt the mechanics of GDI+ (which is new to me, as is C#). I am now happily applying my newfound GDI+ skills. I've used them for a bit of rapid prototyping.
Thanks,
William Irwin
Are your IE6 web page printouts cut off on the right hand side? - Get PrintPunk.
|
|
|
|

|
Hi Christian,
What books, if any, have you used to learn about GDI+?
Jon Sagara
If you've ever watched 6-year-olds playing soccer, that's what the mainstream media is like.
-- Jon Stewart
My Articles
|
|
|
|

|
No, I learned mostly by experimentation and by reading the SDK docs ( which at the time mostly said 'to be added later' ). Charles Petzold has a book on Windows programming for C#, which is about 50% GDI+ information. I'd say that's a good place to look.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|

|
SetPixel errors if you attempt to resize an image with an indexed pixel format. I found the following a decent work around that avoids the System Exception.
Otherwise great code!
public static Bitmap BMPResize(Bitmap b, int nWidth, int nHeight, bool bBilinear)
{
Bitmap bTemp = (Bitmap)b.Clone();
System.Drawing.Imaging.PixelFormat pxlFormat = bTemp.PixelFormat;
if (bTemp.PixelFormat.ToString().EndsWith("Indexed"))
{
//Coverts Format1bppIndexed, Format4bppIndexed,
//and Format8bppIndexed to Format16bppRgb555
pxlFormat=Imaging.PixelFormat.Format16bppRgb555;
}
b = new Bitmap(nWidth, nHeight,pxlFormat);
Rezizing code............
}
|
|
|
|

|
Thanks - I never bothered to investigate this as I never used any indexed formats, and I didn't think anyone else would still use them either
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|

|
I think there's a small mistake in your description of the bilinear filter, although the way its implemented in the code sample is correct. You write that to get the pixel value for column 26.875 "we would multiply the values of column 26 by .875, and the values of column 27 by .125 ".
As your code shows I think it should be "we would multiply the values of column 27 by .875, and the values of column 26 by .125". Obviously for a pixel value such as 26.999 we would almost want to be getting 100% of pixel 27 not 26.
Alan Benn
|
|
|
|

|
Yeah, you're absolutely right. I need to find the time to go through all these articles, to look for errors like this one and correct them.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|

|
Hi, this is a great article. BUT.. When I compare the results to the same image resized with GDI+, the output isn't the same, even when they both use Bilinear interpolation. I'm trying to make a VB6 app compatible with my .NET app that has been out there for over a year, and uses GDI+ to resize.. Any ideas on how I can tune your algorithm to more closely match the native GDI+ one?
Thanks,
Mike.
|
|
|
|

|
Mike .. wrote:
Any ideas on how I can tune your algorithm to more closely match the native GDI+ one?
No, I have no idea what the difference is, BUT the fact that there is a difference does not make either of the two wrong. Are they completely, visibly different ? Does GDI+ do bicubic ? Just wondering if you're really seeing a bicubic and comparing it to a bilinear.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|

|
Yes, I'm using .NET and have the interpolation set to bilinear. The resulting images look approx. the same until you do a pixel-by-pixel comparison. For instance, if I resize a picture of a square, one might have the edge in a different column than the other, in addition to having the colors averaged differently. I was hoping you might have some insight into other ways MSFT might be implementing their bilinear interpolation, since the don't seem to document internals..
Thanks,
Mike
|
|
|
|

|
Mike .. wrote:
I was hoping you might have some insight into other ways MSFT might be implementing their bilinear interpolation, since the don't seem to document internals..
I don't work for Microsoft, so really I have as much chance of working it out as you do. It sounds to me like thier rounding off of values is weighted in some way.
Mike .. wrote:
The resulting images look approx. the same until you do a pixel-by-pixel comparison.
Are people likely to do a pixel by pixel comparison in the case of the VB6 app you're working on ? If so, I guess you could scour the web for more bilinear filtering algorithms and try a few...
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|

|
I am using C# and GDI+ to develop some W/L filter program. Do you know any faster way except direct pixel access?
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
The fourth installment covers how to write a filter that resizes an image, and uses bilinear filtering
| Type | Article |
| Licence | CPOL |
| First Posted | 14 Apr 2002 |
| Views | 376,320 |
| Downloads | 3,384 |
| Bookmarked | 168 times |
|
|