Question

Quelqu'un peut-il me dire une fonction rapide pour Comptez le nombre de pixels blancs dans une image binaire. J'en ai besoin pour ios App Dev. Je travaille directement sur la mémoire de l'image définie comme

  bool *imageData = (bool *) malloc(noOfPixels * sizeof(bool));

J'implémente la fonction

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

C'est évidemment la fonction la plus lente possible. j'ai entendu ça Intrinsèques néon de bras sur l'iOS peut être utilisé pour effectuer plusieurs opérations en 1 cycle. C'est peut-être la voie à suivre ??

Le problème est que je ne suis pas très familier et que je n'ai pas assez de temps pour apprendre le langage d'assemblage en ce moment. Il serait donc formidable que quelqu'un puisse publier un code intrinsique au néon pour le problème mentionné ci-dessus ou toute autre implémentation rapide en C / C ++.

Le seul code dans les intrinsèques néon que je suis en mesure de trouver en ligne est le code de RVB à Grayhttp://computer-vision-talks.com/2011/02/a-vert-fast-bgra-to-grayscale-conversion-on-iphone/

Était-ce utile?

La solution

Tout d'abord, vous pouvez accélérer un peu le code d'origine en tenant compte de la multiplication et en vous débarrassant de la branche:

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

(Cela suppose que imageData[] est vraiment binaire, c'est-à-dire que chaque élément ne peut être que 0 ou 1.)

Voici une simple implémentation au néon:

#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

(Cela suppose que imageData[] est vraiment binaire, imageWidth <= 2^19, et sizeof(bool) == 1.)


Version mise à jour pour unsigned char et des valeurs de 255 pour le blanc, 0 pour le noir:

#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

(Cela suppose que imageData[] est des valeurs de 255 pour le blanc et 0 pour le noir, et imageWidth <= 2^19.)


Notez que tout le code ci-dessus n'est pas testé et peut avoir besoin de travaux supplémentaires.

Autres conseils

http://gccc.gnu.org/onlinedocs/gcc/arm-neon-intrinsics.html

Section 6.55.3.6

L'algorithme vectorisé fera les comparaisons et les mettra dans une structure pour vous, mais vous auriez toujours besoin de passer par chaque élément de la structure et de déterminer s'il s'agit d'un zéro ou non.

À quelle vitesse cette boucle fonctionne-t-elle actuellement et à quelle vitesse en avez-vous besoin pour fonctionner? N'oubliez pas non plus que le néon fonctionnera dans les mêmes registres que l'unité de point flottante, donc l'utilisation de néon ici peut forcer un commutateur de contexte FPU.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top