我有一个平面的字节RGB值数组R1 G1 B1 R2 G2 B2 R3 G3 B3 ... Rn Gn Bn
。所以我的数据看起来像:
char imageData[WIDTH * HEIGHT * 3];
但我想将WIDTH * HEIGHT数组传递给现有的C库,该C库需要这个数据的单个平面。这将只是R值的序列(或只是G,或只是B)。
分配新数组并复制数据(duh)很容易。但是图像非常大。如果它不是一个C库,而是采用某种迭代接口来精细化“切片”遍历,那就太棒了。但我无法编辑我正在调用的代码......它需要一个指向顺序内存块的普通旧指针。
但是我对这个数组有写访问权限。创建一个将其分类为彩色平面的例程是可行的。我还需要一个可以反转的反向转换,但根据定义,将它分类为平面的相同方法可以应用于取消它。
我可以(有效地)将此数组转换为R1 R2 R3 ... Rn G1 G2 G3 ... Gn B1 B2 B3 ... Bn
然后再返回?任何非天真的算法?
答案 0 :(得分:1)
本文"A Simple In-Place Algorithm for In-Shuffle"描述了如何转置2 * N的矩阵并给出了如何在其他情况下进行的提示,因此3 * N也可能。 This answer to other question表明确实有可能。
或者使用将每个值写入其转置位置的算法,然后对该位置的值执行相同的操作,依此类推,直到连接循环。在位向量中标记处理的值。并继续,直到这个向量都是1。
这两种算法都不是缓存友好的。可能一些聪明的使用PREFETCH指令可以改善这一点。
修改强>
C ++,RGB到单平面,未优化:
#include <iostream>
#include <bitset>
#include <vector>
enum {N = 8};
void transpose(std::vector<char>& a)
{
std::bitset<3*N> b;
for (int i = 1; i < 3*N; ++i)
{
if (b[i])
continue;
int ptr = i;
int next;
char nextVal = a[i];
do {
next = ptr/3 + N*(ptr%3);
char prevVal = nextVal;
nextVal = a[next];
a[next] = prevVal;
ptr = next;
b[ptr] = true;
}
while (ptr != i);
}
}
int main()
{
std::vector<char> a(3*N);
for (int i = 0; i != 3*N; ++i)
a[i] = i;
transpose(a);
for (int i = 0; i != 3*N; ++i)
std::cout << (int)a[i] << std::endl;
return 0;
}
我的初衷是使用大小为WIDTH HEIGHT的位向量,这会产生WIDTH HEIGHT / 8的开销。但是总是有可能牺牲空间的速度。位向量可以是大小WIDTH或HEIGHT或任何期望值,甚至是0.技巧是保持指向单元的指针,在此之前所有值都被转置。位向量用于从该指针开始的单元格。在全部为1之后,将其移动到下一个位置,然后执行除实际数据移动之外的所有算法步骤。并且位向量已准备好继续转置。该变体是O(N ^ 2)而不是O(N)。
<强> EDIT2:强>
PREFITCH优化并不难实现:只需计算索引,调用PREFETCH,并将索引放入队列(ringbuffer),然后从队列中获取索引并移动数据。
<强> EDIT3:强>
其他算法的想法,即O(1)大小,O(N * log(N))时间,是缓存友好的并且可能比“循环”算法更快(对于图像大小<1Gb):
答案 1 :(得分:1)
如果你只需要一架飞机,这似乎很容易。如果你需要全部3,你可能会有更好的算法运气。
void PlanarizeR(char * imageData, int width, int height)
{
char *in = imageData;
int pixelCount = width * height;
for (int i = 0; i < pixelCount; ++i, in+=3)
std::swap(*in, imageData[i])
}
将循环从高到低向后运行以反转过程应该不会太难。
答案 2 :(得分:0)
char *imageData = malloc (WIDTH * HEIGHT * 3 * sizeof(char));
此功能执行此操作R1 R2 R3 ... Rn G1 G2 G3 ... Gn B1 B2 B3 ... Bn ,,
char *toRGB(char *imageData, int WIDTH, int HEIGHT){
int len = WIDTH * HEIGHT;
char *RGB = malloc (len * sizeof(char));
int i, j = 0,flag = 0;
for(i=0 ; i<=len ; i++, j+=3){
if(j<len)
RGB[i] = imageData[j];
else{
switch(flag){
case 0: j=-2; flag=1; break; // j=-2 the next iteration will start at j=1
case 1: j=-1; break; // j=-1 the next iteration will start at j=2
}
}
}
return RGB;
}