Jor*_*jon 7 c++ arrays floating-point byte bytearray
如何将BYTE缓冲区(从0到255)转换为浮点缓冲区(从0.0到1.0)?当然,这两个值之间应该存在关系,例如:字节缓冲区中的0将是浮点缓冲区中的.0.f,字节缓冲区中的128将是浮点缓冲区中的.5f,字节缓冲区中的255将是1.f in浮动缓冲区.
实际上这是我的代码:
for (int y=0;y<height;y++) {
for (int x=0;x<width;x++) {
float* floatpixel = floatbuffer + (y * width + x) * 4;
BYTE* bytepixel = (bytebuffer + (y * width + x) * 4);
floatpixel[0] = bytepixel[0]/255.f;
floatpixel[1] = bytepixel[1]/255.f;
floatpixel[2] = bytepixel[2]/255.f;
floatpixel[3] = 1.0f; // A
}
}
Run Code Online (Sandbox Code Playgroud)
这很慢.我的一个朋友建议我使用转换表,但我想知道其他人是否可以给我另一种方法.
无论您是否选择使用查找表,您的代码都会在每次循环迭代中执行大量工作,而这实际上并不需要 - 这可能足以掩盖转换和乘法的成本.
声明你的指针限制,指针你只读取const.乘以1/255th而不是除以255.不要计算内循环的每次迭代中的指针,只计算初始值并递增它们.展开内循环几次.如果目标支持,请使用矢量SIMD操作.不要增加并与最大值进行比较,减量并与零进行比较.
就像是
float* restrict floatpixel = floatbuffer;
BYTE const* restrict bytepixel = bytebuffer;
for( int size = width*height; size > 0; --size )
{
floatpixel[0] = bytepixel[0]*(1.f/255.f);
floatpixel[1] = bytepixel[1]*(1.f/255.f);
floatpixel[2] = bytepixel[2]*(1.f/255.f);
floatpixel[3] = 1.0f; // A
floatpixel += 4;
bytepixel += 4;
}
Run Code Online (Sandbox Code Playgroud)
将是一个开始.
我知道这是一个老问题,但由于没有人使用IEEE浮动表示给出解决方案,所以这里有一个.
// Use three unions instead of one to avoid pipeline stalls
union { float f; uint32_t i; } t, u, v, w;
t.f = 32768.0f;
float const b = 256.f / 255.f;
for(int size = width * height; size > 0; --size)
{
u.i = t.i | bytepixel[0]; floatpixel[0] = (u.f - t.f) * b;
v.i = t.i | bytepixel[1]; floatpixel[1] = (v.f - t.f) * b;
w.i = t.i | bytepixel[2]; floatpixel[2] = (w.f - t.f) * b;
floatpixel[3] = 1.0f; // A
floatpixel += 4;
bytepixel += 4;
}
Run Code Online (Sandbox Code Playgroud)
这比更快两倍作为int
对float
我的计算机(Core 2 Duo处理器)上的转换.
这是上面代码的SSE3版本,一次执行16个浮点数.它需要bytepixel
并且floatpixel
是128位对齐的,并且总大小是4的倍数.请注意,SSE3内置int到float转换在这里没有多大帮助,因为它们无论如何都需要额外的乘法.我相信这是走向教学的最短路径,但如果你的编译器不够聪明,你可能希望手动展开和安排事情.
/* Magic values */
__m128i zero = _mm_set_epi32(0, 0, 0, 0);
__m128i magic1 = _mm_set_epi32(0xff000000, 0xff000000, 0xff000000, 0xff000000);
__m128i magic2 = _mm_set_epi32(0x47004700, 0x47004700, 0x47004700, 0x47004700);
__m128 magic3 = _mm_set_ps(32768.0f, 32768.0f, 32768.0f, 32768.0f);
__m128 magic4 = _mm_set_ps(256.0f / 255.0f, 256.0f / 255.0f, 256.0f / 255.0f, 256.0f / 255.0f);
for(int size = width * height / 4; size > 0; --size)
{
/* Load bytes in vector and force alpha value to 255 so that
* the output will be 1.0f as expected. */
__m128i in = _mm_load_si128((__m128i *)bytepixel);
in = _mm_or_si128(in, magic1);
/* Shuffle bytes into four ints ORed with 32768.0f and cast
* to float (the cast is free). */
__m128i tmplo = _mm_unpacklo_epi8(in, zero);
__m128i tmphi = _mm_unpackhi_epi8(in, zero);
__m128 in1 = _mm_castsi128_ps(_mm_unpacklo_epi16(tmplo, magic2));
__m128 in2 = _mm_castsi128_ps(_mm_unpackhi_epi16(tmplo, magic2));
__m128 in3 = _mm_castsi128_ps(_mm_unpacklo_epi16(tmphi, magic2));
__m128 in4 = _mm_castsi128_ps(_mm_unpackhi_epi16(tmphi, magic2));
/* Subtract 32768.0f and multiply by 256.0f/255.0f */
__m128 out1 = _mm_mul_ps(_mm_sub_ps(in1, magic3), magic4);
__m128 out2 = _mm_mul_ps(_mm_sub_ps(in2, magic3), magic4);
__m128 out3 = _mm_mul_ps(_mm_sub_ps(in3, magic3), magic4);
__m128 out4 = _mm_mul_ps(_mm_sub_ps(in4, magic3), magic4);
/* Store 16 floats */
_mm_store_ps(floatpixel, out1);
_mm_store_ps(floatpixel + 4, out2);
_mm_store_ps(floatpixel + 8, out3);
_mm_store_ps(floatpixel + 12, out4);
floatpixel += 16;
bytepixel += 16;
}
Run Code Online (Sandbox Code Playgroud)
编辑:使用(f + c/b) * b
而不是提高准确性f * b + c
.
编辑:添加SSE3版本.