有人能告诉我快速功能计算二进制图像中白色像素的数量。我需要 iOS app dev。我正在直接处理定义为
的图像的内存 bool *imageData = (bool *) malloc(noOfPixels * sizeof(bool));
我正在实施功能
int whiteCount = 0;
for (int q=i; q<i+windowHeight; q++)
{
for (int w=j; w<j+windowWidth; w++)
{
if (imageData[q*W + w] == 1)
whiteCount++;
}
}
这显然是最慢的功能。我在iOS上听说 ARM Neon内在函数 可用于在1个循环中进行多个操作。也许这就是要走的路?
问题在于我不是很熟悉,目前没有足够的时间学习汇编语言。因此,如果有人能够针对上述问题发布Neon内在函数代码或者在C / C ++中发布任何其他快速实现,那就太棒了。
我能在网上找到的霓虹内在函数中唯一的代码是rgb到灰色的代码 http://computer-vision-talks.com/2011/02/a-very-fast-bgra-to-grayscale-conversion-on-iphone/
答案 0 :(得分:3)
首先,你可以通过分解乘法和摆脱分支来加速原始代码:
int whiteCount = 0;
for (int q = i; q < i + windowHeight; q++)
{
const bool * const row = &imageData[q * W];
for (int w = j; w < j + windowWidth; w++)
{
whiteCount += row[w];
}
}
(这假设imageData[]
是真正的二进制,即每个元素只能是0或1。)
这是一个简单的NEON实现:
#include <arm_neon.h>
// ...
int i, w;
int whiteCount = 0;
uint32x4_t v_count = { 0 };
for (q = i; q < i + windowHeight; q++)
{
const bool * const row = &imageData[q * W];
uint16x8_t vrow_count = { 0 };
for (w = j; w <= j + windowWidth - 16; w += 16) // SIMD loop
{
uint8x16_t v = vld1q_u8(&row[j]); // load 16 x 8 bit pixels
vrow_count = vpadalq_u8(vrow_count, v); // accumulate 16 bit row counts
}
for ( ; w < j + windowWidth; ++w) // scalar clean up loop
{
whiteCount += row[j];
}
v_count = vpadalq_u16(v_count, vrow_count); // update 32 bit image counts
} // from 16 bit row counts
// add 4 x 32 bit partial counts from SIMD loop to scalar total
whiteCount += vgetq_lane_s32(v_count, 0);
whiteCount += vgetq_lane_s32(v_count, 1);
whiteCount += vgetq_lane_s32(v_count, 2);
whiteCount += vgetq_lane_s32(v_count, 3);
// total is now in whiteCount
(这假定imageData[]
是真正的二元,imageWidth <= 2^19
和sizeof(bool) == 1
。)
unsigned char
的更新版本,白色的值为255,黑色的值为<:p>
#include <arm_neon.h>
// ...
int i, w;
int whiteCount = 0;
const uint8x16_t v_mask = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
uint32x4_t v_count = { 0 };
for (q = i; q < i + windowHeight; q++)
{
const uint8_t * const row = &imageData[q * W];
uint16x8_t vrow_count = { 0 };
for (w = j; w <= j + windowWidth - 16; w += 16) // SIMD loop
{
uint8x16_t v = vld1q_u8(&row[j]); // load 16 x 8 bit pixels
v = vandq_u8(v, v_mask); // mask out all but LS bit
vrow_count = vpadalq_u8(vrow_count, v); // accumulate 16 bit row counts
}
for ( ; w < j + windowWidth; ++w) // scalar clean up loop
{
whiteCount += (row[j] == 255);
}
v_count = vpadalq_u16(v_count, vrow_count); // update 32 bit image counts
} // from 16 bit row counts
// add 4 x 32 bit partial counts from SIMD loop to scalar total
whiteCount += vgetq_lane_s32(v_count, 0);
whiteCount += vgetq_lane_s32(v_count, 1);
whiteCount += vgetq_lane_s32(v_count, 2);
whiteCount += vgetq_lane_s32(v_count, 3);
// total is now in whiteCount
(这假设imageData[]
的白色值为255,黑色的值为0,imageWidth <= 2^19
。
请注意,上述所有代码均未经过测试,可能需要进一步处理。
答案 1 :(得分:0)
http://gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html
第6.55.3.6节
矢量化算法将进行比较并将它们放在一个结构中,但是您仍然需要遍历结构的每个元素并确定它是否为零。
该循环当前运行的速度有多快以及运行速度有多快?还要记住,NEON将在与浮点单元相同的寄存器中工作,因此在这里使用NEON可能会强制进行FPU上下文切换。