Wie konvertieren Sie ein byte-array in eine Bitmap-Instanz (.NET)?
Arbeite ich mit Kameras (in diesem Fall schwarz-weiß) in VB.NET. Die API der Kameras ist in C++ und der Hersteller bietet Wrapper. Typisch ist in diesen Fällen das Bild zurück, wie eine Byte
array. In meinem speziellen Fall sind es 8 bit pro pixel, es gibt also keine Lust bitpacking rückgängig zu machen.
War ich baff.NET hat so wenig Unterstützung für diese Art der Sache. Online-Suche, fand ich verschiedene Themen, aber es hilft nicht, dass in vielen Fällen haben Menschen ein byte-array entsprechend Bild Daten (Lesen Sie ein Bild-Datei in ein byte-array und dann haben .NET interpretieren Sie das array als eine Datei mit header und allem).
In diesem Fall muss ich ein array konvertieren von raw-pixel-Werte vor allem in etwas kann ich die Anzeige auf dem Bildschirm.
Scheint es nicht zu sein, eine integrierte Möglichkeit, dies zu tun, weil die 8 bit /Pixel-format eingebaut .NET indiziert ist (braucht eine palette), aber es scheint nicht, dass die Einstellung der Farbpalette unterstützt wird. Wieder, dies hat mich wirklich überrascht. Diese ist das vielversprechendste Thema, die ich gefunden.
Also die einzige Möglichkeit, die ich gefunden, dies zu tun ist, erstellen Sie eine Bitmap
und dann kopieren Sie die pixel-Werte, pixel für pixel. In meinem Fall eine 8 MPixel Bild nahm mehrere Sekunden auf die Schnellste i7 beim Einsatz SetPixel
.
Die alternative, die ich gefunden, um mit SetPixel
ist LockBits
, die dann gibt Ihnen Zugang zu den (unmanaged) array von bytes, stellt das Bild. Es scheint verschwenderisch, weil ich zum Bearbeiten des array .NETZ und kopieren Sie Sie dann zurück zu unmananaged Raum. Ich bin schon kopieren die ursprünglichen Bild Daten einmal (also das original kann wiederverwendet oder verworfen werden, indem der rest von dem, was vor sich geht), so zwar wesentlich schneller als mit SetPixel
dies scheint immer noch verschwenderisch.
Hier ist der VB-code habe ich:
Public Function GetBitmap(ByRef TheBitmap As System.Drawing.Bitmap) As Integer
Dim ImageData() As Byte
Dim TheWidth, TheHeight As Integer
'I've omitted the code here (too specific for this question) which allocates
'ImageData and then uses Array.Copy to store a copy of the pixel values
'in it. It also assigns the proper values to TheWidth and TheHeight.
TheBitmap = New System.Drawing.Bitmap(TheWidth, TheHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
Dim TheData As System.Drawing.Imaging.BitmapData = TheBitmap.LockBits(
New System.Drawing.Rectangle(0, 0, TheWidth, TheHeight), Drawing.Imaging.ImageLockMode.ReadWrite, TheBitmap.PixelFormat)
Dim Image24(Math.Abs(TheData.Stride) * TheHeight) As Byte
'Then we have two choices: to do it in parallel or not. I tried both; the sequential version is commented out below.
System.Threading.Tasks.Parallel.For(0, ImageData.Length, Sub(i)
Image24(i * 3 + 0) = ImageData(i)
Image24(i * 3 + 1) = ImageData(i)
Image24(i * 3 + 2) = ImageData(i)
End Sub)
'Dim i As Integer
'For i = 0 To ImageData.Length - 1
' Image24(i * 3 + 0) = ImageData(i)
' Image24(i * 3 + 1) = ImageData(i)
' Image24(i * 3 + 2) = ImageData(i)
'Next
System.Runtime.InteropServices.Marshal.Copy(Image24, 0, TheData.Scan0, Image24.Length)
TheBitmap.UnlockBits(TheData)
'The above based on
'http://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.aspx
Return 1
End Function
Für eine 8-MPixel-Bild der sequenziellen version verbraucht etwa 220 Millisekunden von der Erstellung TheBitmap
bis zu (und einschließlich) der Aufruf zu TheBitmap.UnlockBits()
. Die parallele version ist viel mehr inkonsistent, aber im Bereich zwischen 60 und 80 Millisekunden. Bedenkt, dass ich bin, den Erwerb von vier Kameras gleichzeitig und streaming zur Festplatte mit viel Zeit zu ersparen, das ist ziemlich enttäuschend. Die API kommt mit Beispiel-code in C++ können die Anzeige von vier Kameras gleichzeitig bei voller Bildrate (17 fps). Es nie sich mit Bitmap
natürlich, da GDI greift auf arrays von raw-pixel Werte.
In der Zusammenfassung, ich muss über das verwaltete/nicht verwaltete Hindernis einfach, weil es keinen direkten Weg, um ein array von pixel-Werten und "Zeug" in eine Bitmap
Instanz. In diesem Fall bin ich auch kopieren Sie die pixel-Werte in ein 24bpp Bitmap
weil ich kann "set" die palette in einem indizierten Bild also 8 bit /Pixel ist nicht sinnvoll, format für die Anzeige.
Gibt es keinen besseren Weg?
InformationsquelleAutor pelesl | 2012-04-18
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erstellen Sie eine gültigen bitmap-header, und preappend es um die byte-array. Sie müssen nur manuell erstellen 56-128 bytes of data.
Zweite, einen stream erstellen, der aus einem byte-array.
Nächsten, erstellen Sie ein Bild oder bitmap-Klasse Bild.FromStream()/Bitmap.FromStream()
Wäre ich mir nicht vorstellen, dass es irgendeine Art von raw-imaging-Funktionen .Net. Es ist so dringend benötigte Informationen für ein Bild, es würde einen extrem langen Parameterliste für eine Methode zu akzeptieren, die rohen bytes und erstellen Sie eine vorstellen (ist es eine bitmap, jpeg, gif, png, etc, und alle zusätzlichen Daten jedes von diesen erfordert, um Sie zu einem gültigen Bild) würde es keinen Sinn machen.
Einen Versuch ist es Wert, vor allem, wenn es lassen Sie mich voranstellen eines bitmap-header mit einer Graustufen-palette, damit ich nicht haben, kopieren Sie die pixel-Werte 3 mal um 24 bpp.
Dies war die Antwort. Auch die Neuerstellung der Kopfzeile jeder Zeit und kopieren der array mehr als einmal ist es bei bis zu 10 Millisekunden.
Ein weiteres update: ich hatte um einen Anruf zu System.GC.Collect() in die Funktion, erzeugt die bitmap. Ansonsten immense Mengen an Speicher verbraucht (bis 15 GB), bevor der garbage collector laufen würde, was eine lange pause (und den Verlust von frames), wenn Sie schließlich doch. Wenn der GC läuft die Zeit springt wieder zurück bis zu etwas in der Größenordnung von 100 ms, aber es hält keine langen Pausen und den Verlust von frames auftreten.
Ich Frage mich, ob Sie wiederverwenden konnte, Ihr ein array/bitmap anstelle von neu es jedes mal, als würde überschreibt die aktuellen Daten im Speicher und benötigen keine garbage collection überhaupt. Ich weiß nicht genug darüber, wie das zu tun, nur, dass es besser wiederverwenden die Zuweisung von mehr Speicher als für das neue Objekt beim freigeben von Speicher, für alte Gegenstände. Nur so ein Gedanke 🙂
InformationsquelleAutor Erik Philips
Versuchen, diese
Natürlich kannst du das. RTM msdn.microsoft.com/ru-ru/library/bb383973.aspx
InformationsquelleAutor Cheburek
Scheint, wie Sie alle Ihre Kameras sind von gleichen Typ, sodass die Bilder-Daten. Ich weiß nicht, ob das möglich ist in deinem Fall aber könnte Sie erstellen Sie eine diese "volle bitmap" aus jedem Bild und dann nur mit header als Vorlage (da wird es gleich für alle Bilder).
InformationsquelleAutor Petr Abdulin