Jak zrobić wysokiej jakości skalowanie obrazu?

głosy
18

Piszę niektóre kodu do skalowania obrazu RGBA 32-bitowe w C / C ++. Pisałem kilka prób, które zostały nieco udane, ale są powolne i co najważniejsze jakość wielkości obrazu jest nie do przyjęcia.

Porównałem ten sam obraz skalowany przez OpenGL (czyli moja karta graficzna) i mój rutyny i to mil od siebie pod względem jakości. Mam Google Code Szukano, prana drzew źródłowych niczego myślałem byłoby rzucić trochę światła (SDL, Allegro, wxWidgets, CxImage, GD, ImageMagick, itd.), Ale zazwyczaj ich kod jest albo zawiłe i rozrzucone po całym miejscu lub usiane assembler i niewiele lub nie ma żadnych komentarzy. Ja również przeczytać wiele artykułów na Wikipedii i gdzie indziej, a ja po prostu nie znaleźć jasne wyjaśnienie, co muszę. Rozumiem, podstawowe pojęcia interpolacji i pobierania próbek, ale jestem stara się uzyskać prawo algorytmu. Nie chcę polegać na zewnętrznej biblioteki dla jednej rutyny i trzeba konwertować do swojego formatu obrazu i odwrotnie. Poza tym, chciałbym wiedzieć, jak zrobić to sam i tak. :)

Widziałem podobne pytanie zadane na przepełnienie stosu przed, ale to nie było naprawdę odpowiedział w ten sposób, ale mam nadzieję, że ktoś tam, kto może pomóc szturchać mnie we właściwym kierunku. Może wskazać mi niektórych artykułów lub pseudo kod ... nic mi pomóc nauczyć się i wykonać.

Oto, czego szukam:

  1. Nie assembler (piszę kod bardzo przenośny dla wielu typów procesorów).
  2. Brak uzależnienia od zewnętrznych bibliotek.
  3. Jestem zainteresowany głównie ze skalowania w dół, ale będzie też trzeba pisać skali rutynowych później.
  4. Jakość wyniku i jasności algorytmu jest najważniejsza (mogę zoptymalizować go później).

Moja rutyna zasadniczo przyjmuje następującą postać:

DrawScaled(uint32 *src, uint32 *dst, 
      src_x, src_y, src_w, src_h, 
      dst_x, dst_y, dst_w, dst_h );

Dzięki!

UPDATE: W celu wyjaśnienia, że potrzebuję czegoś bardziej zaawansowanego niż resample pole dla zmniejszenia skali, która rozmywa obraz zbyt wiele. Podejrzewam, że to, co chcę jest jakiś bicubic (lub inny), filtr, który jest nieco odwrotne do algorytmu bicubic interpolacji (czyli każdy piksel docelowy jest obliczana ze wszystkich przyczyniających pikseli źródłowych w połączeniu z algorytmem ważenia, który utrzymuje rzeczy ostre.

Przykład

Oto przykład tego, co dostaję od algorytmu wxWidgets BoxResample vs. co chcę na 256x256 bitmapy skalowany do 55x55.

  • www.free_image_hosting.net/uploads/1a25434e0b.png

I w końcu:

  • www.free_image_hosting.net/uploads/eec3065e2f.png

oryginalny obraz 256x256

Utwórz 09/12/2008 o 16:05
źródło użytkownik
W innych językach...                            


11 odpowiedzi

głosy
2

Teraz, gdy widzę oryginalnego obrazu, myślę, że OpenGL stosuje algorytm najbliższego sąsiada. Nie tylko jest to najprostszy sposób na zmianę rozmiaru, ale jest to również najszybszy. Jedynym minusem jest to, że wygląda bardzo szorstki, czy istnieje jakikolwiek szczegół w oryginalnym obrazie.

Chodzi o to, aby wziąć równomiernie rozmieszczone próbek z oryginalnego obrazu; w przypadku 55 z 256, lub w jednym z każdego 4.6545. Tuż liczby dostać piksel do wyboru.

Odpowiedział 10/12/2008 o 04:20
źródło użytkownik

głosy
2

Czy to możliwe, że OpenGL robi skalowanie w domenie wektora? Jeśli tak, to nie ma możliwości, że każdy piksel skalowanie oparte będzie blisko niej jakość. Jest to duża zaleta obrazów opartych wektorowych.

Algorytm bicubic można dostroić ostrość vs. artefaktów - Staram się znaleźć link, będę go edytować w kiedy robię.

Edit: To była praca Mitchell-Netravali że myślał, który jest wymieniony w dolnej części tego linku:

http://www.cg.tuwien.ac.at/~theussl/DA/node11.html

Można również zajrzeć do Lanczos resampling jako alternatywa do Bicubic.

Odpowiedział 09/12/2008 o 19:00
źródło użytkownik

głosy
2

Dość prosty i przyzwoity algorytm resample obrazów jest Bicubic interpolacja , Wikipedia sam ma wszystkie potrzebne informacje, aby to realizowane.

Odpowiedział 09/12/2008 o 16:21
źródło użytkownik

głosy
2

Znalazłem realizację wxWidgets dość proste do modyfikowania w miarę potrzeb. To wszystko jest C ++, więc nie ma problemów z przenoszeniem tam. Jedyną różnicą jest to, że ich realizacja współpracuje z niepodpisanych tablice Char (co uważam za najprostszy sposób na radzenie sobie z obrazami też jakichkolwiek) o kolejności bajtów RGB i składnika alfa w oddzielnej tablicy.

Jeśli odnoszą się do „src / common / image.cpp” pliku w drzewie źródłowym wxWidgets jest funkcja down-sampler, który wykorzystuje metodę próbkowania Box „wxImage :: ResampleBox” i funkcja up-skaler zwany „wxImage :: ResampleBicubic”.

Odpowiedział 09/12/2008 o 16:18
źródło użytkownik

głosy
1

Brzmi jak to, czego naprawdę mający trudności zrozumienia jest dyskretna -> ciągła -> przepływ dyskretny zaangażowany w prawidłowo resampling obrazu. Dobry raport tech, które mogłyby pomóc daje wgląd w to, że trzeba to Alvy Ray Smith Piksel jest nie małym placu .

Odpowiedział 09/12/2008 o 20:41
źródło użytkownik

głosy
1

Intel ma bibliotek IPP, które dostarczają szybkich algorytmów interpolacji zoptymalizowany dla procesorów Intel rodzinnych. To jest bardzo dobre, ale to nie jest za darmo jednak. Spójrz na poniższy link:

Intel IPP

Odpowiedział 09/12/2008 o 17:33
źródło użytkownik

głosy
1

Ogólny artykuł z naszego ukochanego gospodarza: Lepsza zmiana rozmiaru obrazu , omawiając względne zalety różnych algorytmów (i linki do innego artykułu CodeProject).

Odpowiedział 09/12/2008 o 17:12
źródło użytkownik

głosy
1

Spróbuj użyć biblioteki Generic obrazu Adobe ( http://opensource.adobe.com/wiki/display/gil/Downloads ) Jeśli chcesz coś gotowy i nie tylko algorytm.


Wyciąg z: http://www.catenary.com/howto/enlarge.html#c

Powiększyć lub zmniejszyć - C Source Code Wymaga Victor Image Processing Biblioteka dla 32-bitowego systemu Windows v 5.3 lub wyższej.


int enlarge_or_reduce(imgdes *image1)
{
   imgdes timage;
   int dx, dy, rcode, pct = 83; // 83% percent of original size

   // Allocate space for the new image
   dx = (int)(((long)(image1->endx - image1->stx + 1)) * pct / 100);
   dy = (int)(((long)(image1->endy - image1->sty + 1)) * pct / 100);
   if((rcode = allocimage(&timage, dx, dy,
      image1->bmh->biBitCount)) == NO_ERROR) {
      // Resize Image into timage
      if((rcode = resizeex(image1, &timage, 1)) == NO_ERROR) {
         // Success, free source image
         freeimage(image1);
         // Assign timage to image1
         copyimgdes(&timage, image1);
         }
      else // Error in resizing image, release timage memory
         freeimage(&timage);
      }
   return(rcode);
}

Ten przykład zmienia rozmiar obszaru obrazu i zastępuje oryginalny obraz z nowym obrazem.

Odpowiedział 09/12/2008 o 16:44
źródło użytkownik

Odpowiedział 09/12/2008 o 16:37
źródło użytkownik

głosy
0

Jako uzupełnienie, Jeremy Rudd pisał ten artykuł powyżej. Że realizuje się przesączono dwuprzebiegowe skalowania. Źródła są C #, ale wygląda na tyle jasne, że mogę portu to dać mu szansę. Znalazłem bardzo podobny kod C wczoraj, że był o wiele trudniejszy do zrozumienia (bardzo złych nazw zmiennych). Dostałem go do sortowania-of-pracy, ale to było bardzo powolne i nie dają dobre wyniki, które doprowadziły mnie do przekonania, wystąpił błąd w mojej adaptacji. Mogę mieć więcej szczęścia pisanie go od podstaw z tego jako punkt odniesienia, który postaram.

Ale biorąc pod uwagę, w jaki sposób dwie prace algorytm wprost Zastanawiam się, czy nie jest to szybszy sposób to zrobić, być może nawet w jednym przejściu?

Odpowiedział 09/12/2008 o 21:07
źródło użytkownik

głosy
0

Spójrz na ImageMagick , który wykonuje wszelkie rodzaje filtrów przeskalowania.

Odpowiedział 09/12/2008 o 18:57
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more