BMP 8-bit praca na pikselach

0

Witam!

Mam do napisania program, który będzie edytował zdjęcia (m. in. rozjaśnianie, kontrast, negatyw, histogram etc.). Na 24-bitowych plikach BMP szło dość gładko. Kłopot natomiast pojawił się, gdy chciałem to samo zrobić na plikach czarno-białych (BMP 8-bit). Poniżej zamieszczam fragment kodu, który obsługuje mi zmianę kolorowego obrazka na negatyw i prosiłbym o podobne rozwiązanie tylko w odniesieniu do 8-bitowego pliku:


            PixelFormat formatObrazka = (obrazekOryginal.PixelFormat == PixelFormat.Format8bppIndexed) ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb;        //określenie formatu obrazka

            obrazek = new Bitmap(obrazek.Width, obrazek.Height, formatObrazka);

            BitmapData daneWyjsciowe = obrazek.LockBits(new Rectangle(0, 0, obrazek.Width, obrazek.Height), ImageLockMode.ReadWrite, formatObrazka);         //Blokowanie bitmapy w pamięci, pierwsze dwa argumenty to początek i koniec obrazka,
                                                                                                                                                                    //kolejne to sposób dostępu i format.
            BitmapData daneWejsciowe = obrazekOryginal.LockBits(new Rectangle(0, 0, obrazek.Width, obrazek.Height), ImageLockMode.ReadOnly, formatObrazka);

            unsafe   
            {
                byte* wskWyjsciowy = (byte*)daneWyjsciowe.Scan0;                //wskaźnik na początek danych w pamięci 
                byte* wskWejsciowy = (byte*)daneWejsciowe.Scan0;

                int nOffset = daneWejsciowe.Stride - obrazek.Width; 

switch (RT) {
                    case trans.NEGATYW:

                        for (int y = 0; y < obrazek.Height; y++)
                        {
                            for (int x = 0; x < obrazek.Width; x++)
                            {
                                wskWyjsciowy[0] = (byte)(255 - wskWejsciowy[0]);
                                wskWyjsciowy[1] = (byte)(255 - wskWejsciowy[1]);
                                wskWyjsciowy[2] = (byte)(255 - wskWejsciowy[2]);

                                wskWejsciowy += 3; wskWyjsciowy += 3;
                            }
                            wskWejsciowy += nOffset; wskWyjsciowy += nOffset;
                        }
                        break;

.....

}

Dwa słowa na temat powyższego kodu: wskWejsciowy i wskWyjsciowy to wskaźniki do obrazów, jeden oryginalny, drugi tworzony w programie. nOffset to fragment lini, w której nie ma już wartości pikseli, a są dodatkowe dane (w zasadzie nie wiem jakie, jak ktoś mi powie to będę wdzięczny).

Z początku myślałem, że wystarczy stworzyć nowy obiekt klasy Bitmap (ten, na którym będą nakładane poprawki) w formacie Format8bppIndexed i działać cały czas na wskWyjsciowe[0] (zwiększając w pętli wskWyjsciowy zawsze o jeden, ale to nie działa tak jak powinno, ale być może coś źle zrobiłem, więc jak komuś to działa w ten sposób, to chętnie posłucham kilku dobrych rad.

Od razu chciałem zaznaczyć, że metody getPixel i setPixel zupełnie mnie nie satysfakcjonują, bo strasznie wolno działają.

Za wszelką pomoc z góry dziękuję :)

P.S.: W części kodu zaznaczonego kropkami są inne algorytmy edytujące, zamknięcie trybu unsafe i zwolnienie zablokowanych plików, ale to wszystko działa na 24-bitowych dokumentach bmp, więc nie zamieszczałem tego, żeby niepotrzebnie nie gmatwać kodu

1

W BMP 8-bitowym zapisane są indeksy kolorów w palecie, a nie bezpośrednio wartości kolorów. Żeby zrobić negatyw musisz zmodyfikować paletę, a danych wcale nie musisz ruszać.

0

Hmm... to co mówisz brzmi sensownie, a dałoby radę napisać fragment przykładowego kodu, albo chociaż pseudokodu, bo i tak nie bardzo wiem jak się do tych danych odwoływać i jak je przeglądać forami.

Dzięki za pomoc!

0

Tak sobie patrzę, ale chyba nadal nie wiem jak się za to zabrać, więc może pokusisz się o jakiś prosty przykład (np. z negatywem), bo nadal nie wiem jak przy pomocy tej palety zmienić jasność obrazu czy wyeliminować szumy? :)

1

W zasadzie C# nie znam, ale spróbuję

ColorPalette palette = obrazek.Palette;
for (int i = 0; i < palette.Entries.Length; i++)
   palette.Entries[i] = Color.fromArbg(~palette.Entries[i].toArgb());
obrazek.Palette = palette;
0

Spróbowałem ten kod, który podałeś i co prawda trochę mi się już rozjaśniło, bo zrozumiałem na czym polega paleta itp i generalnie to co napisałeś ma sens, ale kłopot w tym, że paleta ma 4 kanały (w tym alpha) i jego też "odwracasz" przez co obrazek staje się przezroczysty. A więc jak modyfikować tylko poszczególne kanały (A, R, G, B)? - tak wiem, że dla 8-biotowego formatu R, G, B będzie po prostu miało taką samą wartość.

I masz małą literówkę: FromArgb, a nie fromArgb

0

Dla negatywu to będzie tak:

ColorPalette palette = obrazek.Palette;
for (int i = 0; i < palette.Entries.Length; i++)
   palette.Entries[i] = Color.FromArgb(palette.Entries[i].ToArgb()^0xFFFFFF);
obrazek.Palette = palette;

Z rozjaśnianiem będzie podobnie.
A jeśli chodzi o usuwanie szumów to musisz po prostu pamiętać, że masz możliwość użycia tylko bardzo ograniczonego zestawu kolorów.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0