2013-03-12 8 views
5

Mam obraz 8-bitowy. Dla każdego piksela muszę ustalić jego pozycję porządkową w bieżącym wierszu. Na przykład, jeżeli rząd jest:Potrzebujesz pomocy wektoryzacji tego kodu

32 128 16 64, 

następnie trzeba Rezultatem

1 3 0 2, 

od 32 jest 1. Najwyższa wartość rzędu 128 jest 3 pod najwyżej 16 jest 0TH najwyższym i 64 jest 2. najwyżej.

Muszę powtórzyć powyższą procedurę dla wszystkich wierszy obrazu. Oto kod non-wektorowy:

for (int curr = 0; curr < new_height; ++curr) 
{ 
    vector<pair<unsigned char, char> > ordered; 
    for (char i = 0; i < 4; ++i) 
    { 
     unsigned char val = luma24.at<unsigned char>(curr, i); 
     ordered.push_back(pair<unsigned char, char>(val, i)); 
    } 
    sort(ordered.begin(), ordered.end(), cmpfun); 
    for (int i = 0; i < 4; ++i) 
     signature.at<char>(curr, ordered[i].second) = i; 
} 

luma24 jest obraz 8-bitowy Czytam od i ma new_height wiersze i 4 kolumny. signature to podpisany obraz tego samego rozmiaru (zignoruj ​​różnicę w znaku na razie, ponieważ nie jest to istotne) - tam przechowuję wynik. cmpfun to trywialna funkcja komparatora.

Próbowałem wektorować powyższy kod i dostał to:

Mat ordinal; 
luma24.convertTo(ordinal, CV_16UC1, 256, 0); 
Mat sorted = ordinal.clone(); 
for (int i = 0; i < 4; ++i) 
    ordinal(Range::all(), Range(i, i+1)) += i; 
cv::sort(ordinal, sorted, CV_SORT_EVERY_ROW | CV_SORT_ASCENDING); 
bitwise_and(sorted, Scalar(0x00ff), ordinal); 
Mat ordinal8; 
ordinal.convertTo(ordinal8, CV_8SC1, 1, 0); 
ordinal8.copyTo(signature(Range::all(), Range(0, 4))); 

musiałem spakować wartość 8-bitowego i 8-bitowa liczba porządkowa w pojedynczym kanale 16-bitowej, ponieważ nie wykonuje OpenCV sortowanie dla obrazów wielokanałowych. To jest prawie to, czego potrzebuję, ale nie całkiem. Dla przykładu wejście, to daje mi:

2 0 3 1 

ponieważ najniższa wartość jest w 2 kolumnie, obok najniższy jest w kolumnie 0th itp Jak mogę iść o przekształcenie tego do wyniku muszę bez dostęp do każdego piksela indywidualnie?

Zasadniczo, muszę jakoś wektorować to:

uint8_t x[] = {2, 0, 3, 1}; 
uint8_t y[4]; 
for (uint8_t i = 0; i < 4; ++i) 
    y[x[i]] = i; 

gdzie x jest wynikiem pośredniego mój aktualny kod vectorized daje mi i y jest wynikiem chcę.

Czy można to zrobić?

+0

Tylko dla wyjaśnienia (nie mam jeszcze odpowiedzi) - Co chcesz zrobić, jeśli masz wiele pikseli o tej samej wartości? Czy wszystkie powinny być takie same porządkowe? –

+0

Nie na temat: Co za zbieg okoliczności, właśnie w dniu, w którym czytałem samouczek [ffmpeg tutorial] (https://github.com/mpenkov/ffmpeg-tutorial) kod źródłowy dublowany na github. Url przestał działać, więc poszedłem do twojego profilu, na wypadek, gdybyś zmienił nazwę, ale domyślam się, że go usunąłeś, i od razu rozpoznałem twojego awatara przez przypadek. –

+0

W tej formie jest prawie niemożliwe. Jakie są ograniczenia? na przykład czy x [] ma zawsze szerokość 4 elementów? czy powinien to być uint8_t? –

Odpowiedz

0

Wierzę, że to załatwi sprawę za Ciebie. Nie wymaga przydziałów ani stosów lub rodzajów, ale zakłada, że ​​twój zakres wynosi 0-255 (np. Uint8). Większe założenie: Będzie działał tylko jeśli masz szerokie rzędy. Jeśli mają naprawdę 4 piksele szerokości, to i < 256 jest trochę brzydka. Są sposoby, aby odejść, ale zakładam, że 4 piksele to tylko "np." dla prostoty.

void processRow (int* rowpos, uint8_t* pixelsForRow, int w) { 
    uint32_t i, pv, v=0, hist[256]={0}; 
    for (i=0; i<w; i++)  hist[pixelsForRow[i]]++; 
    for (i=0; i<256; i++) {pv=hist[i]; hist[i]=v; v+=pv;} 
    for (i=0; i<w; i++)  rowpos[i] = hist[pixelsForRow[i]]++; 
} 

OK - jak to działa?
linia 1 w tej funkcji deklaruje i opróżnia tabelę histogramów.
linia 2 oblicza histogram.
linia 3 zmienia ją w sortowanie zliczane - i dlatego hist używa większego rozmiaru elementu niż uint8
linia 4 stosuje posortowaną pozycję.

Istnieją 2 lewy; Po pierwsze, w wierszu 3 histogramy są "przesunięte o 1 indeks", tak że pierwszą wartością jest zawsze "0", a cokolwiek by to nie było, a druga wartość byłaby tym, czym byłby pierwszy licznik, i tak dalej. Drugą lewą jest "++" w linii 4 - zawsze zapewnia, że ​​wartość porządkowa jest unikalna.

Pozwala wypróbować na swoim wejściu:
[32 128 16 64]
wiersz 2: [0 ... 1 .... 1 ... 1 ... 1 ... 0] na indeksach [0, 16, 32, 64, 128, 255] odpowiednio
wiersz 3: [0 ... 0 ... 1 .... 2 ... 3 ... 0] w indeksach [0, 16 , 32, 64, 128, 255], odpowiednio
linia 4: [1, 3, 0, 2] ... wygląda prawo

Pozwala spróbować go w nieco inny wkład:
[32 128 16 32]
wiersz 2: [0 ... 1 ... 2 .... 0 ... 1 ... 0] na indeksach [0, 16, 32, 64, 128, 255] odpowiednio
wiersz 3: [0 ... 0 .... 1 .... 3 ... 3. ..0] na indeksach [0, 16, 32, 64, 128, 255] odpowiednio
wiersz 4: [1, 3, 0, 2] ... doskonały


ale nie jestem całkiem pewien jeśli spełnia twoje potrzeby wektoryzacji - :)

0

Innym sposobem, jaki mogę wymyślić, jest: Dla każdego wiersza utwórz drzewo wyszukiwania binarnego. W trakcie przejścia na zamówienie możemy uzyskać rangę każdego piksela.

Każdy element węzła jest strukturą

// Members of struct explained here. 
// row_pos: stores position of that pixel in that row. 
//  we populate this while creating binary search tree. 
// 
// rank: stores its rank in that row.() 
// while doing in-order traversal, we come to know rank of that pixel. At that point only, we update that pixel location with its rank. 

typedef struct node 
{ 
    int row_pos, rank; 
    node *left, *right; // left and right nodes. 
}; 

sekwencję etapów w każdym rzędzie może być:

a) O (d) utworzenie poszukiwania binarnego drzewa przez przechowywanie pozycji każdego piksela również w węźle.

b) O (w): Rozpocznij kolejność w kolejności. Dla każdego węzła wypełnij położenie piksela tego węzła rangą (liczenie rozpoczyna się od pierwszego węzła jako 0).