Hallo liebe Gemeinde,
ich arbeite momentan an einem Projekt von meiner Arbeit aus, bei dem ich ein 8-Bit Graustufenbild in ein 24-Bit RGB umwandeln muss, um es "künstlich" blau oder grün einzufärben.
Da ich das Bild von der Kamera als byte-Pixel-Array zurück bekomme war mein bisheriger Ansatz ein 3x so langes byte-Array anzulegen und den Grauwert über eine Schleife an die jeweilige Stelle (grün/blau) einzutragen, daraus eine BitmapSource zu erzeugen und es anschließend als Image auf der GUI anzuzeigen.
Es geht jetzt vor allem um den Live-View, also das schnelle hintereinander grabben der Bilder. Ein Bild ist 1920x1200 Pixel x 3-Bit pro Pixel. In einer Schleife dauert das auf der Zielplattform zu lang (10fps).
Gibt es einen schnellen und ressourcensparenden Ansatz, den ich weiter verfolgen könnte?
Grüße und danke schon mal im Voraus.
Das erklärt noch nicht, wozu du ein 24Bit-Bild brauchst. Was hindert dich denn, mit Graustufen zu arbeiten, anstatt das umständlich umzurechnen?
LaTino
"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)
Naja wie gesagt, das Live-Bild soll ja dann eingefärbt sein, statt in Graustufen angezeigt zu werden.
Hab im Anhang mal Beispielbilder, einmal Graustufen (so wie es von der Kamera kommt) und einmal grün gefärbt (so wie es am Ende angezeigt werden soll).
Hi,
mal für den Fall, dass du wirklich 24bpp brauchen solltest - was genau dauert denn eigentlich zu lange? Sicher die Konvertierung?
Falls dem so wäre - probier mal AForge.Imaging - damit geht GrayScale to 24bpp-RGB (ohne Coloring) so:
var filter = new GrayscaleToRGB();
var rgb = filter.Apply(img);
Alternativ kannst du auch direkt mal folgendes Beispiel anschauen:
https://gist.github.com/xinmyname/1602389
LG
Der Tipp ist gut, aber das habe ich schon probiert 😁
Problem dabei ist, dass die Funktion nur ein Bitmap frisst und ich von der Kamera aber ein byte[] zurück bekomme (und ich unter WPF arbeite und da ja "eigentlich" kein Bitmap verfügbar ist).
Achso und ja die Konvertierung ist der Zeitfresser
Bitte verwende kein Rar/Zip-Upload bei nur zwei Bilder.
Beachte bitte [Hinweis] Wie poste ich richtig? Punkt 6.1
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hi robbb26,
bitte nimm dir erstmal die Zeit und einen Profiler, um das Problem genauer einzugrenzen, und diese Frage zu beantworten:
mal für den Fall, dass du wirklich 24bpp brauchen solltest - was genau dauert denn eigentlich zu lange? Sicher die Konvertierung?
Wir wissen ja nicht, was genau bei dir zu lange dauert, und können daher auch nur raten.
Weeks of programming can save you hours of planning
So nochmal von vorn:
Von der Kamera bekomme ich das Bild als byte-Array. IGrabResult ist ein Interface von der Kamera-DLL, das die Bilder hält.
byte[] grabResult = IGrabResult.PixelData as byte[];
grabResult ist ein 1920 * 1200 großes Array mit den Graustufen-Werten (8-Bit).
Jetzt erzeuge ich ein 3x so langes Array für 24-Bit RGB und ersetze den jeweiligen Grün- bzw. Blau-Wert durch den Graustufen-Wert aus dem alten Array.
byte[] RGB = new byte[1920 * 1200 * 3];
int StartIndex = 0;
// für Grün
for (int Index = 1; Index < RGB.Length; Index += 3)
{
RGB[Index] = grabResult[StartIndex];
StartIndex++;
}
// für Blau
for (int Index = 2; Index < RGB.Length; Index += 3)
{
RGB[Index] = grabResult[StartIndex];
StartIndex++;
}
Da diese Schleife knapp 7 Mio durchlaufen werden muss, 10 Bilder pro Sekunde von der Kamera gegrabbt werden und der Zielrechner ein relativ langsamer Atom ist, dauert der Vorgang des künstlichen Einfärbens halt sehr lange.
Gibt es Möglichkeiten diesen Vorgang zu beschleunigen?
Hallo robbb26,
ich würde dies mit einer lookup table lösen:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RGB24
{
public byte B;
public byte G;
public byte R;
public RGB24(byte value)
{
B = value;
G = value;
R = value;
}
}
public class ImageConverter
{
private RGB24[] _lut;
public ImageConverter()
{
_lut = new RGB24[256];
for (int i = 0; i < _lut.Length; i++)
{
_lut[i] = new RGB24((byte)i);
}
}
public unsafe byte[] ToRGB24(byte[] data)
{
byte[] result = new byte[data.Length * 3];
fixed (byte* bptr = result)
{
RGB24* ptr = (RGB24*)bptr;
for (int i = 0; i < data.Length; i++)
{
ptr[i] = _lut[data[i]];
}
}
return result;
}
}
Grüße
spooky
Danke erstmal für deine Antwort Spook.
Bin jetzt erst dazu gekommen, dein Snippet auszuprobieren. Es funktioniert auch soweit und ist auch fast doppelt so schnell, wie meine Lösung.
ABER 😄 : Deine Methode schreibt in dem result-Array den Grausutufen-Wert in alle drei Kanäle (RGB)
So sollte es aussehen (beispielhaft): {0, 78, 0, 0 215, 0, 0, 124, 0, ... }
So sieht es momentan aus: {78, 78, 78, 215, 215 ,215, 124, 124, 124, ...}
Hast du dafür noch eine Lösung?
Kannst du nicht programmieren? Tipp: RGB24-Konstruktor ändern.
Hallo robbb26,
bei mir funktioniert es (siehe screenshot).
grüße
spooky
Spook: robbb26 möchte aber eben kein Graubild (also R = G = B), sondern nur ein Farbwert davon gesetzt (und die anderen beiden dann 0) 😉
Hallo Th69,
dann ist deine Antwort natürlich richtig. 👍
Grüße
spooky