2017-05-30 3 views
0

Ich hoffe, jemand kann mir helfen, mehrere große Bilder (PNG) in eins zu verschmelzen. Ich habe bis zu 30 Bilder, die 20000x2000 sind und möchte sie zusammenführen. Die Ausgabe ist ein Bild, das in die GIS-Software geladen werden kann.Merge große Bilder mit VB.Net

Das Problem, das ich habe, ist ich bin nach dem 4. Bild aus dem Speicher.

Der Code, den ich unten habe, hält im Wesentlichen das gesamte Bild im Speicher, wie es das Nähen tut. Gibt es eine Möglichkeit, die Bilder effektiv zu steppen, ohne alles in den Speicher zu laden, oder die Speicherkapazität zu erhöhen und all meinen RAM und/oder virtuellen Speicher zu nutzen?

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

Meine Idee, IDAT Chunks aus den verschiedenen Dateien zu verketten, scheint ungültig zu sein, da, soweit ich jetzt verstehe, separate IDAT Chunks einfach Teile eines komprimierten Blocks sind, nicht getrennt komprimierte Blöcke. –

+0

Ja, ich habe es versucht, aber es hat die Software nur als fehlerhaft oder ungültig bezeichnet. – Ando

+0

1) Ich kann PNGs mit den IDAT-Chunks (oder den Daten darin) erstellen, die nach [pngcheck] (http://www.libpng.org/pub/png/apps/pngcheck.html) ohne Fehler verkettet sind, aber das tun sie Öffnen Sie die CRC für die IHDR nach der Aktualisierung der Bildhöhe 2) Sie haben möglicherweise eine größere Chance auf Erfolg, wenn Sie etwas anderes als GDI + verwenden. –

Antwort

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 

Für alle Interessierten ich meine Lösung gepostet haben. Dies funktioniert gut für mich, wird aber wahrscheinlich einige Optimierungen für einzelne Anwendungen benötigen. Dies wird auch durch die theoretischen Grenzen von BMP-Dateien begrenzt, die 16^8 Bytes sind.