2017-05-30 4 views
0

J'espère que quelqu'un pourra m'aider à fusionner plusieurs grandes images (PNG) en une seule. J'ai jusqu'à 30 images qui sont 20000x2000 et voudrais les fusionner. La sortie est une image qui peut être chargée dans le logiciel SIG.Fusionner de grandes images avec VB.Net

Le problème que je suis est que je suis à court de mémoire après environ la 4ème image.

Le code que j'ai ci-dessous contient essentiellement toute l'image en mémoire comme elle le fait pour l'assemblage. Est-il possible de coudre efficacement les images sans les charger toutes en mémoire, ou d'augmenter la capacité de mémoire et d'utiliser toute ma RAM et/ou ma mémoire virtuelle?

Public Function stitchAllImagesOnXAxis(imageDirectoryPath As String, outputImagePath As String) As Boolean 
    Try 
     Dim evolvingImage As Bitmap 
     Dim filenames() As String = IO.Directory.GetFiles(imageDirectoryPath) 

     For i As Integer = 0 To filenames.Count - 1 

      If Not filenames(i).EndsWith(".png") Then filenames = filenames.RemoveAt(i) 

     Next i 

     If filenames.Count = 0 Then Return False 

     Dim FS As New IO.FileStream(filenames(0), IO.FileMode.Open) 
     evolvingImage = Bitmap.FromStream(FS) 
     FS.Close() 



     For i As Integer = 1 To filenames.Count - 1 

      FS = New IO.FileStream(filenames(i), IO.FileMode.Open) 
      evolvingImage = stitchImagesOnXAxis(evolvingImage, Bitmap.FromStream(FS), 5) 
      FS.Close() 

     Next 

     evolvingImage.Save(outputImagePath, Imaging.ImageFormat.Png) 
     evolvingImage.Dispose() 

     Return True 
    Catch ex As Exception 
     Debug.WriteLine(ex.Message) 
     Return False 
    End Try 
+0

Mon idée de concaténation de blocs IDAT à partir des différents fichiers semble invalide car, si je comprends bien, les morceaux IDAT séparés sont simplement des portions d'un bloc compressé, pas des blocs compressés séparément. –

+0

Oui, j'ai essayé, mais cela a juste fait que le logiciel l'appelle corrompu ou invalide. – Ando

+0

1) Je peux créer des png avec les morceaux IDAT (ou les données à l'intérieur) concaténés sans erreur selon [pngcheck] (http://www.libpng.org/pub/png/apps/pngcheck.html, mais ils le font Avez-vous pensé à mettre à jour le CRC pour l'IHDR après avoir mis à jour la hauteur de l'image? 2) Vous pourriez avoir plus de chance de succès si vous utilisez autre chose que GDI +. –

Répondre

0
Public Function stitchAllImagesOnXAxisSO(imageDirectoryPath As String, outputImagePath As String, tolerance As Integer) As Boolean 

    Try 
     'blank 54 byte header for BMP 
     Dim headerBytes() As Byte = blankHeader() 

     'track the total width of the bmp for the header information 
     Dim totalWidth As Integer = 0 

     'the height of the BMP (assumes all images being joined are the same height) 
     Dim height As Integer = 0 

     'the files in the directory specified 
     Dim filenames() As String = IO.Directory.GetFiles(imageDirectoryPath) 

     'the filestream used to read each file 
     Dim FS As IO.FileStream 

     'a class to read the header information of the BMP files 
     Dim dynamicHeaderInfo As BMPHeaderInformation 

     'byte array to copy the bytes read to 
     Dim copyBuffer() As Byte 

     'ensure each file is a bmp file 
     For i As Integer = 1 To filenames.Count - 1 

      If Not filenames(i).EndsWith(".bmp") Then filenames = filenames.RemoveAt(i) 

     Next i 

     'if there isn't more than one image available then exit 
     If filenames.Count < 2 Then Return False 

     'if the output image exists than delete it 
     If IO.File.Exists(outputImagePath) Then IO.File.Delete(outputImagePath) 

     'and open it as new 
     Dim evolvingImageFS As New IO.FileStream(outputImagePath, IO.FileMode.OpenOrCreate) 

     'write a blank header 
     evolvingImageFS.Write(headerBytes, 0, headerBytes.Length) 

     'set the height of the overall image (all images assumed the same height) 
     dynamicHeaderInfo = New BMPHeaderInformation(filenames(0)) 
     height = dynamicHeaderInfo.width 

     'writing one row at a time from one image at a time 

     For row As Integer = 0 To height - 1 

      For i As Integer = 0 To filenames.Count - 1 

       'get the header data 
       dynamicHeaderInfo = New BMPHeaderInformation(filenames(i)) 

       'open the file 
       FS = New IO.FileStream(filenames(i), IO.FileMode.Open) 



       'each time we are looking at the first row of an image add that width to the overall width 
       If row = 0 Then totalWidth += dynamicHeaderInfo.width 

       'set the position of the stream 
       FS.Position = dynamicHeaderInfo.headerLength + (row * dynamicHeaderInfo.width * 3) + (row * dynamicHeaderInfo.rowPaddingLength) 

       'set up the byte array to read in the bytes 
       ReDim copyBuffer((dynamicHeaderInfo.width * 3) - 1) 
       FS.Read(copyBuffer, 0, dynamicHeaderInfo.width * 3) 
       'write the bytes to the new stream 
       evolvingImageFS.Write(copyBuffer, 0, dynamicHeaderInfo.width * 3) 

       'if we are at the last image and the total width is less than 500, write the trailing zeros on the row 
       If i = filenames.Count - 1 Then padRowFromStream(totalWidth, evolvingImageFS) 

       'close the stream 
       FS.Close() 
       FS.Dispose() 

      Next 

     Next 

     'set the new header information 
     setNewWidth(totalWidth, evolvingImageFS) 
     setNewheight(height, evolvingImageFS) 
     setNewImageFileSize(evolvingImageFS.Length, evolvingImageFS) 
     setNewImageAreaSize(evolvingImageFS.Length - headerBytes.Length, evolvingImageFS) 

     'close off the stream 
     evolvingImageFS.Close() 
     evolvingImageFS.Dispose() 

     Return True 
    Catch ex As Exception 
     Debug.WriteLine(ex.Message) 
     Return False 
    End Try 
End Function 

Pour les personnes intéressées, j'ai posté ma solution. Cela fonctionne bien pour moi mais aura probablement besoin de quelques ajustements pour des utilisations individuelles. Ceci est également limité par les limites théoriques des fichiers bmp étant 16^8 octets.