Click here to Skip to main content
15,887,683 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi, I would like know, how open and modify big picture files, I need replace color in some pixels but when I try to open big files (they are images from maps, and the size is 300 or more Mb), I get a "out of memory" error.

My code is:
Private Sub BMW_Filtrar_DoWork(ByVal sender As System.Object, _
                                   ByVal e As System.ComponentModel.DoWorkEventArgs) _
                                   Handles BMW_Filtrar.DoWork
        Dim Archivo_Local As FileInfo = CType(e.Argument, FileInfo)
        If Archivo_Local.Exists = False Then Exit Sub

        Dim FSB As System.IO.FileStream
        FSB = New FileStream(Archivo_Local.FullName, FileMode.Open, FileAccess.Read)
        Dim L_Bitmap As Bitmap = Image.FromStream(FSB)
        Dim i, j, Cont1, Cont2, Cont3, Cont4 As Integer
        Dim Color_Px As System.Drawing.Color

        '--- BUSCAR FILAS EN BLANCO PARTE SUPERIOR E INFERIOR ---
        Dim Flag1 = False, Flag2 As Boolean = False
        For i = 0 To L_Bitmap.Height - 1 Step 1
            'COL CYCLE
            For j = 0 To L_Bitmap.Width - 1 Step 1


                Color_Px = L_Bitmap.GetPixel(j, i)
'REPLACE COLOR PIXEL
                With Color_Px
                    If .R >= 128 Or .G > 180 Then L_Bitmap.SetPixel(j, i, Color.White)
                    If .G <= 130 And .B <= 100 Then L_Bitmap.SetPixel(j, i, Color.White)
                End With

            Next 'FIN CICLO COLUMNAS
        Next

        L_Bitmap.Save(Archivo_Local.Directory.FullName & "\Archivo.tif")
Salir:
        Try
            L_Bitmap.Dispose()
            L_Bitmap = Nothing
            FSB.Close()
        Catch ex As Exception

        End Try
    End Sub


Thanks in advance for any help.

My best regards,

Freddy Coal
Posted
Comments
Philippe Mori 25-Aug-11 19:14pm    
Well since your original file is compressed, it might take far more memory for the uncompressed image. You might have an idea from the task manager on how much memory you use and for more precise information there are memory profiler. Neverthless, in task manager, you would probably see that the memory will go in the GB range...

As other has suggested, maybe using a library that manipulate image would make sense.

Finally, I think that the approach of using GetPixel might be relatively slow for large images...

The on-disk file size may be 300MB, but the Bitmap object in memory may be much larger, depending on the dimensions of the image and the color depth.

You don't mention what this size is, so it's impossible to say for sure.
 
Share this answer
 
Comments
dox22 25-Aug-11 11:47am    
Of course is more larger in memory, the question is how work with all the image or part of the image like when you read a txt file in blocks.

the image is a tiff, 24 bit, 11949x8805 pixels, I can´t resize the image because is a georeference image, and each pixel belongs to a geographic coordinate.

Thanks anyway for your answer :)
Dave Kreskowiak 25-Aug-11 13:18pm    
The TIFF is going to get converted to a 32bbp bitmap in memory. That puts your image at over 400MB in size, which is actually in memory twice.

TIFF support in GDI and GDI+ is also a bit screwy. The TIFF files may not be compessed in a compatible format. I would suggest finding a library to handle TIFF files instead of using the GDI+ based objects in .NET.
have you run your code under the debugger? BTW, I'd put the try/catch block around all your code in the interest of "best practice".
 
Share this answer
 
Comments
dox22 25-Aug-11 11:48am    
Yes, I run the code in the debugger and in release, but I get the same error "OUT OF MEMORY". do you know how work with images in blocks?
Philippe Mori 25-Aug-11 19:07pm    
Well, effectivelly the try/catch as written is not particulary useful as if there would be a problem it would probably happen in the other part of the function. In that case, I would think that a try/finally would be more appropriate (does VB has an using as C#?).
I'll try to help with this, although the biggest image on my machine is a 2800x1400 .jpg (2mb). I've not worked much with .tif images and have never worked with images used in mapping. There are however a few things you can try (if you haven't already) to work with blocks from a larger image.

First, isolate your working image from the original. To do this, create an empty bitmap of the same physical dimensions as the disk image. Create a graphics object from that empty image. Next, load the original from disk and draw it in the previously-created graphics object. Then dispose of the copy of the original you just loaded, so there is no link between your program and the disk image.

From the image you've just created (call it the "working image"), create yet another image from a rectangular section of the working image. This would be the block you wish to process in some way. Perform the desired changes on this new image, and then draw it back to the working image (using the graphics object again).

Once all desired changes are made, you can then overwrite the original or write it out to a new file. The code below demonstrates the steps to get the copy of the original and then get a block selection from that copy. Once you've made your changes, you can use a similar process to write the block back to your working image, and then write the working image back to disk. You shouldn't run into any memory errors this way.

VB
'get original image
Dim original As Bitmap = Bitmap.FromFile("bigimage.tif")

'create working image
Dim workingImage As New Bitmap(original.Width, original.Height)
Dim g As Graphics = Graphics.FromImage(workingImage)
g.DrawImage(original, 0, 0, original.Width, original.Height)

'dump the original
original.Dispose()

'now get the block to process
'this assumes you want to process a 300x300 area of the original
Dim block As New Bitmap(300, 300)

'this rectangle assumes you wish to grab a 300x300 section
'of the original, starting at point 100x100
Dim selRect As New Rectangle(100, 100, 300, 300)

'this rect represents the dimensions of your block image
'and the coords where you'll draw from the working image
Dim drawRect As New Rectangle(0, 0, 300, 300)

'now get the block
Dim blockGraphics As Graphics = Graphics.FromImage(block)
blockGraphics.DrawImage(workingImage, drawRect, selRect, GraphicsUnit.Pixel)


'your code to process the image goes here
'
'

'then use a similar code block to write the
'block image back to the working image
'lastly, write the working image to disk.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900