Laden...

Schnelle Konvertierung von Grayscale zu RGB (WPF)

Erstellt von robbb26 vor 6 Jahren Letzter Beitrag vor 6 Jahren 4.059 Views
R
robbb26 Themenstarter:in
6 Beiträge seit 2017
vor 6 Jahren
Schnelle Konvertierung von Grayscale zu RGB (WPF)

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.

3.003 Beiträge seit 2006
vor 6 Jahren

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)

R
robbb26 Themenstarter:in
6 Beiträge seit 2017
vor 6 Jahren

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).

1.029 Beiträge seit 2010
vor 6 Jahren

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

R
robbb26 Themenstarter:in
6 Beiträge seit 2017
vor 6 Jahren

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

16.806 Beiträge seit 2008
vor 6 Jahren

Bitte verwende kein Rar/Zip-Upload bei nur zwei Bilder.
Beachte bitte [Hinweis] Wie poste ich richtig? Punkt 6.1

5.657 Beiträge seit 2006
vor 6 Jahren

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

R
robbb26 Themenstarter:in
6 Beiträge seit 2017
vor 6 Jahren

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?

S
248 Beiträge seit 2008
vor 6 Jahren

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

R
robbb26 Themenstarter:in
6 Beiträge seit 2017
vor 6 Jahren

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?

S
248 Beiträge seit 2008
vor 6 Jahren

Hallo robbb26,

bei mir funktioniert es (siehe screenshot).

grüße
spooky

4.931 Beiträge seit 2008
vor 6 Jahren

Spook: robbb26 möchte aber eben kein Graubild (also R = G = B), sondern nur ein Farbwert davon gesetzt (und die anderen beiden dann 0) 😉

S
248 Beiträge seit 2008
vor 6 Jahren

Hallo Th69,

dann ist deine Antwort natürlich richtig. 👍

Grüße
spooky

R
robbb26 Themenstarter:in
6 Beiträge seit 2017
vor 6 Jahren

Danke euch beiden!
Läuft jetzt.