android optimization opencv arm neon

android - Prueba de cv:: umbral optimizado para NEON() en dispositivos móviles



optimization opencv (0)

He estado escribiendo algunas optimizaciones para la función de umbral de OpenCV, para dispositivos ARM (teléfonos móviles). Debería funcionar tanto en Android como en iPhone.

Sin embargo, no tengo un dispositivo para probarlo, por lo que estoy buscando voluntarios para darme un poco de ayuda. Si eso te motiva más, planeo enviarlo a OpenCV para integrarlo en el repositorio principal.

Me interesaría la corrección de los códigos, y si resulta que funciona según lo previsto, algunas estadísticas para el rendimiento original / optimizado. No te olvides de mirar todos los escenarios.

Entonces, aquí está el código. Para ejecutarlo, pega en opencv/modules/imgproc/src/thresh.cpp , en la línea 228 (a partir de 2.4.2) - justo debajo del bloque SSE, y recompila OpenCV.

Además, agregue esta línea en la parte superior del archivo

#include <arm_neon.h>

Cuerpo del código principal:

#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