Подтвердить что ты не робот

Тестирование NEON-оптимизированного cv:: threshold() на мобильном устройстве

Я писал некоторые оптимизации для пороговой функции OpenCV, для устройств ARM (мобильные телефоны). Он должен работать как на Android, так и на iPhone.

Однако у меня нет устройства для тестирования, поэтому я ищу добровольцев, чтобы немного помочь. Если это мотивирует вас больше, я планирую отправить его в OpenCV для интеграции в основной репозиторий.

Меня интересовала бы правильность кода, и если это будет работать, как предполагалось, некоторые статистические данные для исходной/оптимизированной производительности. Не забудьте просмотреть все сценарии.

Итак, вот код. Чтобы запустить его, введите opencv/modules/imgproc/src/thresh.cpp в строке 228 (начиная с 2.4.2) - чуть ниже блока SSE и перекомпилируйте OpenCV.

Также добавьте эту строку в начало файла

#include <arm_neon.h>

Тело основного кода:

#define CV_USE_NEON 1
#if CV_USE_NEON
    //if( checkHardwareSupport(CV_CPU_ARM_NEON) )
    if( true )
    {
        uint8x16_t thresh_u = vdupq_n_u8(thresh);
        uint8x16_t maxval_ = vdupq_n_u8(maxval);

        j_scalar = roi.width & -8;

        for( i = 0; i < roi.height; i++ )
        {
            const uchar* src = (const uchar*)(_src.data + _src.step*i);
            uchar* dst = (uchar*)(_dst.data + _dst.step*i);

            switch( type )
            {
            case THRESH_BINARY:
                for( j = 0; j <= roi.width - 32; j += 32 )
                {
                    uint8x16_t v0, v1;
                    v0 = vld1q_u8 ( src + j );
                    v1 = vld1q_u8 ( src + j + 16 );
                    v0 = vcgtq_u8 ( v0, thresh_u );
                    v1 = vcgtq_u8 ( v1, thresh_u );
                    v0 = vandq_u8 ( v0, maxval_ );
                    v1 = vandq_u8 ( v1, maxval_ );
                    vst1q_u8 ( dst + j, v0 );
                    vst1q_u8 ( dst + j + 16, v1 );
                }


                for( ; j <= roi.width - 8; j += 8 )
                {
                    uint8x8_t v2;
                    v2 = vld1_u8( src + j );
                    v2 = vcgt_u8 ( v2, vget_low_s8 ( thresh_u ) );
                    v2 = vand_u8 ( v2, vget_low_s8 ( maxval_ ) );
                    vst1_u8 ( dst + j, v2 );                    
                }
                break;

            case THRESH_BINARY_INV:         
                for( j = 0; j <= roi.width - 32; j += 32 )
                {
                    uint8x16_t v0, v1;
                    v0 = vld1q_u8 ( src + j );
                    v1 = vld1q_u8 ( src + j + 16 );
                    v0 = vcleq_u8 ( v0, thresh_u );
                    v1 = vcleq_u8 ( v1, thresh_u );
                    v0 = vandq_u8 ( v0, maxval_ );
                    v1 = vandq_u8 ( v1, maxval_ );
                    vst1q_u8 ( dst + j, v0 );
                    vst1q_u8 ( dst + j + 16, v1 );
                }


                for( ; j <= roi.width - 8; j += 8 )
                {
                    uint8x8_t v2;
                    v2 = vld1_u8( src + j );
                    v2 = vcle_u8 ( v2, vget_low_s8 ( thresh_u ) );
                    v2 = vand_u8 ( v2, vget_low_s8 ( maxval_ ) );
                    vst1_u8 ( dst + j, v2 );                    
                }
                break;

            case THRESH_TRUNC:
                for( j = 0; j <= roi.width - 32; j += 32 )
                {
                    uint8x16_t v0, v1;
                    v0 = vld1q_u8 ( src + j );
                    v1 = vld1q_u8 ( src + j + 16 );
                    v0 = vminq_u8 ( v0, thresh_u );
                    v1 = vminq_u8 ( v1, thresh_u );                 
                    vst1q_u8 ( dst + j, v0 );
                    vst1q_u8 ( dst + j + 16, v1 );
                }


                for( ; j <= roi.width - 8; j += 8 )
                {
                    uint8x8_t v2;
                    v2 = vld1_u8( src + j );
                    v2 = vmin_u8  ( v2, vget_low_s8 ( thresh_u ) );                 
                    vst1_u8 ( dst + j, v2 );                    
                }
                break;

            case THRESH_TOZERO:         
                for( j = 0; j <= roi.width - 32; j += 32 )
                {
                    uint8x16_t v0, v1;
                    v0 = vld1q_u8 ( src + j );
                    v1 = vld1q_u8 ( src + j + 16 );             
                    v0 = vandq_u8 ( vcgtq_u8 ( v0, thresh_u ), vmaxq_u8 ( v0, thresh_u ) );
                    v1 = vandq_u8 ( vcgtq_u8 ( v1, thresh_u ), vmaxq_u8 ( v1, thresh_u ) );
                    vst1q_u8 ( dst + j, v0 );
                    vst1q_u8 ( dst + j + 16, v1 );
                }


                for( ; j <= roi.width - 8; j += 8 )
                {
                    uint8x8_t v2;
                    v2 = vld1_u8 ( src + j );                    
                    v2 = vand_u8 ( vcgt_u8 ( v2, vget_low_s8(thresh_u) ), vmax_u8 ( v2, vget_low_s8(thresh_u) ) );
                    vst1_u8 ( dst + j, v2 );                    
                }
                break;

            case THRESH_TOZERO_INV:
                for( j = 0; j <= roi.width - 32; j += 32 )
                {
                    uint8x16_t v0, v1;
                    v0 = vld1q_u8 ( src + j );
                    v1 = vld1q_u8 ( src + j + 16 );             
                    v0 = vandq_u8 ( vcleq_u8 ( v0, thresh_u ), vminq_u8 ( v0, thresh_u ) );
                    v1 = vandq_u8 ( vcleq_u8 ( v1, thresh_u ), vminq_u8 ( v1, thresh_u ) );
                    vst1q_u8 ( dst + j, v0 );
                    vst1q_u8 ( dst + j + 16, v1 );
                }


                for( ; j <= roi.width - 8; j += 8 )
                {
                    uint8x8_t v2;
                    v2 = vld1_u8 ( src + j );                    
                    v2 = vand_u8 ( vcle_u8 ( v2, vget_low_s8(thresh_u) ), vmin_u8 ( v2, vget_low_s8(thresh_u) ) );
                    vst1_u8 ( dst + j, v2 );                    
                }
                break;
            }
        }
    }
#endif
4b9b3361