.NET Forum / Languages / C# / January 2008
breaking up bitmap images
|
|
Thread rating:  |
Stephen.Schoenberger@gmail.com - 14 Jan 2008 15:52 GMT Hello,
I am reading in a bitmap image and storing it as a bitmap in C#. I need to perform some mathmatical operations on that image but it needs to be broken up into smaller fragments (16x16). On each of these fragments I need to perform my work, then write back the manipulated fragment to a new image. I have tried some different techniques but so far no luck. Any advice would be great!
Thanks.
Nicholas Paldino [.NET/C# MVP] - 14 Jan 2008 16:08 GMT Stephen,
It should be easy enough. First, you create a new Bitmap instance, passing 16x16 to indicate you want a 16x16 image. Once you have that, you can pass the Bitmap to the static FromImage method on the Graphics class to return a Graphics instance which will let you draw on the Bitmap. Once you have the Graphics instance, you can then call the DrawImage method on it, passing the original image, and the section of the original image you want to draw on your new, smaller image.
Then you can perform your processing.
Putting the images back together is just a matter of reversing the process. Create one image which is the size of all the smaller images, get the Graphics instance for it, and then call DrawImage on the Graphics instance, passing the smaller pieces and drawing them where appropriate.
 Signature - Nicholas Paldino [.NET/C# MVP] - mvp@spam.guard.caspershouse.com
> Hello, > [quoted text clipped - 6 lines] > > Thanks. Stephen.Schoenberger@gmail.com - 14 Jan 2008 21:33 GMT On Jan 14, 11:08 am, "Nicholas Paldino [.NET/C# MVP]" <m...@spam.guard.caspershouse.com> wrote:
> Stephen, > [quoted text clipped - 31 lines] > > > Thanks. I am a little confused on how to use the DrawImage() for the use that I need it...should I use Rectangle? Or PointF? Or another option????
Peter Duniho - 14 Jan 2008 22:30 GMT > I am a little confused on how to use the DrawImage() for the use that > I need it...should I use Rectangle? Or PointF? Or another option???? Whatever you want.
There are a lot of overloads for DrawImage(). Just find the one that suits your needs best. For example:
Bitmap[,] BitmapsFromBitmap(Bitmap bmpSrc, int cxDst, int cyDst) { int ccol = (bmpSrc.Width - 1) / cxDst + 1, crow = (bmpSrc.Height - 1) / cyDst + 1; Bitmap[,] rgbmpRet = new Bitmap[ccol][crow];
for (int irow = 0; irow < crow; irow++) { for (int icol = 0; icol < ccol; icol++) { Bitmap bmpDst = new Bitmap(cxDst, cyDst);
using (Graphics gfx = Graphics.FromImage(bmpDst)) { gfx.DrawImage(bmpSrc, 0, 0, new Rectangle(icol * cxDst, irow * cyDst, cxDst, cyDst), GraphicsUnit.Pixel); }
rgbmpRet[icol, irow] = bmpDst; } }
return rgbmpRet; }
Caveat: the above was just typed into the message...I didn't bother to try to compile or test it. The code also makes no attempt to deal bitmaps that aren't an integral multiple of the size of the sub-bitmaps; if I recall correctly, if a source that isn't an integral multiple of the destination size is used, all that will happen is that the right and/or bottom edge of the last sub-bitmaps just won't be painted (they'll be black).
Finally, the above code assumes the passed in Bitmap is at least 1x1 pixel in size.
Pete
Stephen.Schoenberger@gmail.com - 23 Jan 2008 14:04 GMT On Jan 14, 5:30 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com> wrote:
> > I am a little confused on how to use the DrawImage() for the use that > > I need it...should I use Rectangle? Or PointF? Or another option???? [quoted text clipped - 43 lines] > > Pete used your algorithm to attempt to solve this problem and upon the program ending I have over 8200 files...i thought I would have 4800 files because I am using a 1280x960 image which is broken up into 16x16 blocks resulting in a 80x60 = 4800 images. Make sense? Any further advice would be great. Here is the code that works...(your code provided was close)
int ccol = (bmpSource.Width-1)/cxDst+1; int crow = (bmpSource.Height-1)/cyDst+1;
Bitmap[,] ret = new Bitmap[ccol,crow]; for (int irow = 0; irow < crow; irow++ ) { for (int icol=0; icol < ccol; icol++) { Bitmap bmpDst = new Bitmap(cxDst, cyDst);
using (Graphics gfx = Graphics.FromImage(bmpDst)) { gfx.DrawImage(bmpSource, 0, 0, new Rectangle(icol * cxDst, irow * cyDst, cyDst, cxDst), GraphicsUnit.Pixel); } ret[icol, irow] = bmpDst;
//bmpDst.Save("bmpDst"+icol+"X"+irow+".bmp"); bmpDst.Save("bmpDst.bmp"); } }
Peter Duniho - 23 Jan 2008 17:27 GMT > used your algorithm to attempt to solve this problem and upon the > program ending I have over 8200 files...i thought I would have 4800 > files because I am using a 1280x960 image which is broken up into > 16x16 blocks resulting in a 80x60 = 4800 images. Make sense? Any > further advice would be great. Here is the code that works...(your > code provided was close) I don't see anything obviously wrong. What filenames do you get when you use the version of Save() that embeds the row and column indices in the file name? You can't have 8200 files and still have embedded indices that only range from "00X00" up to "79X59", so if in fact that loop is writing more than 4800 files (I really don't see how it could be), you should see filenames outside that range.
You should really be testing with a much small test file to start with. It's much easier to step through the entire algorithm, and to get a handle on exactly what's being written, when the number of tiles is small. I'd recommend starting with something that only generates four to six tiles. That'd give you enough to watch several iterations, but not so many that watching _all_ the iterations would take prohibitively long.
Pete
Nicholas Paldino [.NET/C# MVP] - 14 Jan 2008 22:33 GMT Stephen,
I would use the overload specified here:
http://msdn2.microsoft.com/en-us/library/ms142040.aspx
You just have to define the source and destination rectangles. The destination rectangle should be simple enough, it's just the rectangle that defines the boundary of the whole image (the 16x16 image).
 Signature - Nicholas Paldino [.NET/C# MVP] - mvp@spam.guard.caspershouse.com
> On Jan 14, 11:08 am, "Nicholas Paldino [.NET/C# MVP]" > <m...@spam.guard.caspershouse.com> wrote: [quoted text clipped - 41 lines] > I am a little confused on how to use the DrawImage() for the use that > I need it...should I use Rectangle? Or PointF? Or another option???? Stephen.Schoenberger@gmail.com - 23 Jan 2008 00:49 GMT On Jan 14, 5:33 pm, "Nicholas Paldino [.NET/C# MVP]" <m...@spam.guard.caspershouse.com> wrote:
> Stephen, > [quoted text clipped - 59 lines] > > I am a little confused on how to use the DrawImage() for the use that > > I need it...should I use Rectangle? Or PointF? Or another option???? I have started to figure this out but I have a new dilemma that has me confused. With the image I need to split it up into 16x16 sub images and SAVE the coordinates of each of those subimages (say sub image 1 goes from 0,0 to 15,15 or sub image 10 goes from 150,165 to 160,175...just arbitrary examples) perform the work on each subimage then recombine the subimages (with work performed on them) to a new output image. Any advice/help on this would be great.
Peter Duniho - 23 Jan 2008 01:28 GMT > [...] > I have started to figure this out but I have a new dilemma that has me [quoted text clipped - 4 lines] > then recombine the subimages (with work performed on them) to a new > output image. Any advice/help on this would be great. You'll either need to create a parallel data structure to contain the coordinate information or, probably better, create a new data structure that can contain both the image reference and the coordinate information. That way you can correlate the coordinates with each generated image.
As for recombining, it's pretty much the inverse of the splitting. Create a Bitmap the size you need to contain all the pieces, then iterate through the pieces drawing each one into the destination bitmap.
Pete
Kevin Spencer - 23 Jan 2008 12:16 GMT I had a similar problem. Here's how I solved it:
When saving the fragments, I simply give them a file name that contains the coordinates of the fragment,combined with the name of the original file. For example:
imageName
imageName_00 imageName_01 imageName_02
This way, I can work with multiple images and fragments from those images concurrently. You can fetch the fragments using Directory.GetFiles, and a wildcard containing the original image file name, and then parse the file names to get their coordinates.
 Signature HTH,
Kevin Spencer Chicken Salad Surgeon Microsoft MVP
> On Jan 14, 5:33 pm, "Nicholas Paldino [.NET/C# MVP]" > <m...@spam.guard.caspershouse.com> wrote: [quoted text clipped - 78 lines] > then recombine the subimages (with work performed on them) to a new > output image. Any advice/help on this would be great. Peter Duniho - 14 Jan 2008 21:22 GMT > Hello, > [quoted text clipped - 4 lines] > fragment to a new image. I have tried some different techniques but so > far no luck. Any advice would be great! In addition to what Nicholas wrote...
It sounds as though you want some sort of distributed processing to occur. Depending on exactly how you're distributing the processing, you may find it better to use LockBits to create a single chunk of data that all the processors can operate on, and give each one a specific subset to use so that they don't conflict.
In particular, if all of this is happening within a single process, the overhead of copying all of those 16x16 subsets could be enough to significantly reduce or eliminate any advantages you might have gotten from parallelizing your algorithm. Actually, it could do so even if the processing is being distributed to multiple processes or computers, but in that case the solution would be different (maybe use memory-mapped files for multiple processes...for multiple computers the only practical solution is likely to be to make the chunks of work larger than 16x16).
Pete
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|