2013-03-12 97 views
5

我有一個8位圖像。對於每個像素,我需要計算出當前行中的序號位置。例如,如果行是:需要幫助向量化此代碼

32 128 16 64, 

然後我需要的結果:

1 3 0 2, 

因爲32是該行中的第一最高值,128是第三最高,16是第0最高和64是第二高的。

我需要重複上述過程的圖像的所有行。這是非量化代碼:

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是8位圖像,我從閱讀,具有new_height行4列。 signature是一個相同大小的簽名圖像(因爲它不相關,所以忽略了現在的符號差異) - 這是我存儲結果的位置。 cmpfun是一個簡單的比較器功能。

我試圖向量化上面的代碼和得到這個:

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

我不得不包的8位值和8位序成單一16位信道,因爲OpenCV中不執行排序多通道圖像。這幾乎是我需要的,但並不完全。對於例如輸入,它給了我:

2 0 3 1 

以來的最低值是在第2列,次最低是在第0列,等我如何去了解這個轉換的結果,我需要不單獨訪問每個像素?

從本質上講,我需要以某種方式矢量化這樣的:

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

其中x是中間結果我目前的量化代碼給我和y是我想要的結果。

可以這樣做嗎?

+0

只是澄清(我還沒有答案) - 如果你有多個像素具有相同的值,你想要做什麼?他們都應該是相同的序數? – 2013-03-12 12:11:31

+0

偏題:偶然的一天,我正在閱讀你在github上鏡像的[ffmpeg教程](https://github.com/mpenkov/ffmpeg-tutorial)源代碼。該網址停止工作,所以我去你的個人資料,以防你重命名,但我想你刪除了它,現在我偶然認出你的頭像。 – 2013-03-12 12:12:18

+0

在這種形式下它是不可能的。有什麼限制?例如是x []總是4元素寬?應該是uint8_t嗎? – 2013-03-12 12:25:05

回答

0

我相信這會爲你做的伎倆。它不需要分配或堆棧或排序,但假設您的範圍是0-255(例如uint8)。更大的假設:如果你有寬行,它將只是表演。如果他們真的是4像素寬,那我是一個醜陋的。有辦法讓它消失,但我假設4個像素只是一個「例如」爲簡單起見。

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]]++; 
} 

好的 - 那它是如何工作的?
此函數中的第1行聲明並清空直方圖表。
第2行計算直方圖。
第3行將它變成計數排序 - 這也是爲什麼hist使用比uint8更大的元素尺寸的原因
第4行應用排序位置。

有2個技巧;首先,在第3行中,直方圖被「按1索引移位」,例如第一個值始終爲「0」,而不是第一個值,第二個值就是第一個計數的值,依此類推。 第二個技巧是第4行中的「++」 - 始終確保序號值是唯一的。第2行:[0 ... 1 .... 1 .... 1 ... 1 ... 0]在索引處輸入:
[0,16,32,64,128,255]分別爲
行3:[0 ... 0 .... 1 .... 2 ... 3 ... 0]在索引[0,16 ,32,64,128,255]分別
線4:[1,3,0,2] ...看起來向右

允許嘗試在稍微不同的輸入:
[32 128 16 32]
分別在索引[0,16,32,64,128,255]處的第2行:[0 ... 1 .... 2 .... 0 ... 1 ... 0]
第3行: [0 ... 0 .... .... 1 3 ... 3。 ..0]在索引[0,16,32,64,128,255]分別爲
第4行:[1,3,0,2] ...完美


但我不太確定如果它滿足你對矢量化的需求 - :)

0

我能想到的另一種方法是, 對於每一行,創建一個二叉搜索樹。在進行遍歷時,我們可以得到每個像素的等級。

節點中的每個元素是一個結構的步驟中的每一行是

// 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. 
}; 

序列:

一)O(W):通過存儲每個像素的位置也創建二進制搜索樹在節點中。

b)O(w):開始按順序遍歷。對於每個節點,使用rank填充該節點的像素位置(從第一個節點開始計數爲0)。