2013-03-12 102 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)。