2009-09-25 14 views
5

Moja wewnętrzna pętla zawiera obliczenia, które pokazują, że profilowanie jest problematyczne.Szybka formuła dla krzywej o wysokim kontraście

Chodzi o to, aby wziąć piksel w skali szarości x (0 < = x < = 1) i "zwiększyć jego kontrast". Kim wymagania są dość luźny, tak następujące:

  • dla x < 0,5, 0 < = f (x) < x
  • dla x> .5 X < f (x) = 1
  • <
  • C (0) = 0
  • f (x) = 1 - r (1 - x), to znaczy powinien być "symetryczny"
  • Korzystnie funkcja powinna być gładka.

Więc wykres powinien wyglądać mniej więcej tak:

Graph.

Mam dwie implementacje (ich wyniki różnią się, ale oba są conformant):

float cosContrastize(float i) { 
    return .5 - cos(x * pi)/2; 
} 

float mulContrastize(float i) { 
    if (i < .5) return i * i * 2; 
    i = 1 - i; 
    return 1 - i * i * 2; 
} 

Więc mogę zażądać albo microoptimization dla jednego z tych implementacji, czy oryginalny, szybsze formułę własną rękę.

Może któryś z was może nawet kręcić bity;)

+0

Być może moglibyśmy Ci pomóc lepiej, gdybyś mógł powiedzieć nam, z jakiego języka korzystasz (zakładam Java) i jaki jest kompilator/środowisko uruchomieniowe. –

+0

C# z kompilatorem MS i runtime, ale jestem gotów przepisać krytyczne algo w C++, jeśli uważam, że muszę ... –

+0

C# z nazwami metod CamelCased? :( – Joren

Odpowiedz

5

trywialnie można po prostu próg, ale mogę sobie wyobrazić to zbyt głupi:

return i < 0.5 ? 0.0 : 1.0; 

Skoro wspomniałeś „Zwiększanie kontrastu” Zakładam, że wartości wejściowe są wartościami luminancji. Jeśli tak, i są dyskretne (być może to wartość 8-bitowa), możesz użyć tabeli odnośników, aby zrobić to szybko.

Twój "mulContrastize" wygląda dość szybko. Jedną z optymalizacji byłoby użycie matematyki całkowitej. Powiedzmy, że twoje wartości wejściowe mogą zostać przekazane jako 8-bitowa wartość bez znaku w [0..255]. (? Ponownie, ewentualnie grzywny założenie) Można zrobić coś mniej więcej takiego ...

int mulContrastize(int i) { 
    if (i < 128) return (i * i) >> 7; 
    // The shift is really: * 2/256 
    i = 255 - i; 
    return 255 - ((i * i) >> 7); 
+0

Próg jest zbyt daleko od gładkiego, aby był przydatny w moim przypadku Są to wartości luminancji, tak, nie są wartościami dyskretnymi - są to w rzeczywistości pływaki, z dwóch powodów. OpenGL, tekstury float są najszybsze, a po drugie, zdecydowałem, że używam pływaków 0.0-1.0, aby moja matematyka była łatwa * i * szybka, ale nigdy nie myślałem o porównaniu z tabelą odnośników, zajrzę to i zobaczę, czy przewyższa on obawy dotyczące tekstur OpenGL. Implementacja, którą opublikowałeś, jest naprawdę przyjemna, ale nie tak ładna jak tabela odnośników, a mój mulContrastize jest rzeczywiście "dość szybki", ale nie w tak ciasnej wewnętrznej pętli :) –

+0

Btw, nie powinieneś t podzielić dwukrotnie przez 255 dwa razy, tylko jeden raz. Więc powinieneś przesunąć się o 7. –

+0

Ups, masz rację, to normalizuje jeden krok za daleko. Naprawię przykład. –

13

Rozważmy następujące esicy -shaped funkcje (odpowiednio przeliczone na żądanym zakresie):

screenshot


że wygenerowany powyżej postać MATLAB. Jeśli interesuje Cię kod:

x = -3:.01:3; 
plot( x, 2*(x>=0)-1, ... 
     x, erf(x), ... 
     x, tanh(x), ... 
     x, 2*normcdf(x)-1, ... 
     x, 2*(1 ./ (1 + exp(-x)))-1, ... 
     x, 2*((x-min(x))./range(x))-1 ) 
legend({'hard' 'erf' 'tanh' 'normcdf' 'logit' 'linear'}) 
+1

+1. dobra robota. –

+1

Głównym problemem PO jest szybkość. Jak przyspieszają? – tom10

+0

Dzięki, przynajmniej wiem, że teraz nazywają się "esowatą";) Wykonałem prostą implementację tanh, jest tak szybki jak ten. Reszta zajmie trochę więcej myśli i myślę, że będą wolniej, ale zobaczymy. –

4

Kawałek interpolacja może być szybka i elastyczna.Wymaga tylko kilku decyzji, po których następuje mnożenie i dodawanie, i może przybliżać dowolną krzywą. Pozwala to również uniknąć kursu, który można wprowadzić za pomocą tabel odnośników (lub dodatkowego kosztu w dwóch wyszukiwaniach, po których następuje interpolacja w celu wygładzenia tego), chociaż lut może działać idealnie dobrze dla twojej sprawy.

alt text http://i35.tinypic.com/fbeu0j.png

Z zaledwie kilku segmentów, można uzyskać całkiem dobry mecz. Tutaj będzie przebieg w gradientach , który będzie trudniejszy do wykrycia niż kurs w absolutnych kolorach.

Jak zauważa Eamon Nerbonne w komentarzach, segmentacja może być zoptymalizowana przez "wybranie [...] twoich punktów segmentacji w oparciu o coś takiego jak druga pochodna w celu zmaksymalizowania szczegółów", czyli tam, gdzie nachylenie zmienia się najbardziej. Oczywiście, w moim opublikowanym przykładzie, posiadanie trzech segmentów w środku pięciosegmentowego przypadku nie dodaje więcej szczegółów.

+2

Jeśli naprawdę czujesz się oszołomiony, możesz wybrać punkty segmentacji w oparciu o coś podobnego do drugiej pochodnej, aby zmaksymalizować szczegółowość (brak punktu w różnicowaniu segmentów w centralnym, dość prostym odcinku). –

+0

@Eamon: Dzięki za pomysł drugiej pochodnej. Wiedziałem, że jestem leniwy z punktami środkowymi, ale bardzo podoba mi się uogólnienie drugiej pochodnej. – tom10