Быстрый подсчет пикселей на двоичном изображении - встроенные неоновые ARM - iOS Dev - PullRequest
3 голосов
/ 17 января 2012

Может кто-нибудь подсказать мне быструю функцию подсчета количества белых пикселей в двоичном изображении . Мне это нужно для iOS приложения разработчика. Я работаю непосредственно с памятью изображения, определенного как

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

Это, очевидно, самая медленная из возможных функций. Я слышал, что Неон ARM присущ на iOS может использоваться для выполнения нескольких операций за 1 цикл. Может быть, это путь ??

Проблема в том, что я не очень знаком и мне не хватает времени на изучение ассемблера. Поэтому было бы здорово, если бы кто-нибудь мог опубликовать встроенный код Neon для упомянутой выше проблемы или любую другую быструю реализацию на C / C ++.

Единственный код в неоновых кодах, который я могу найти в Интернете, это код от rgb до grey http://computer -vision-talks.com / 2011/02 / а-очень-быстро bgra к полутонового-конверсионной на Iphone /

Ответы [ 2 ]

3 голосов
/ 17 января 2012

Во-первых, вы можете немного ускорить исходный код, вычленив множитель и избавившись от ветви:

 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 для белого, 0 для черного:

#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.)


Обратите внимание, что весь приведенный выше код не протестирован и может потребоваться дополнительная работа.

0 голосов
/ 17 января 2012

http://gcc.gnu.org/onlinedocs/gcc/ARM-NEON-Intrinsics.html

Раздел 6.55.3.6

Векторизованный алгоритм выполнит сравнения и поместит их в структуру для вас, но вам все равно придется пройти через каждый элемент структуры и определить, является ли он нулем или нет.

Как быстро работает этот цикл и как быстро он вам нужен? Также помните, что NEON будет работать в тех же регистрах, что и модуль с плавающей запятой, поэтому использование здесь NEON может вызвать переключение контекста FPU.

...