2013-03-19 5 views
0

Я хотел бы знать, возможно ли с помощью неоновых векторов уменьшить изображение на 3? Я пытаюсь написать алгоритм для этого на бумаге, но, похоже, это невозможно. Поскольку, когда вы получаете, например, 8 байт, вы не можете получить 3 * 3 пикселя, для завершения операции понижающей дискретизации не будет достаточно пикселей. В соответствии с уменьшением размера на 2: Explaining ARM Neon Image Sampling Я думаю о загрузке 16bytes, затем 8bytes из одной строки, затем назначить их 32-байтовому вектору, а затем обработать его 24 байтами этого вектора?алгоритм для downsample изображение 3 с помощью Neon

Update: Я написал пример код в соответствии с ответом, но я получаю ошибку сегментации в vst1_u8 ...

inline void downsample3dOnePass(uint8_t* src, uint8_t *dst, int srcWidth) 
{ 

    // make sure rows/cols dividable by 8 
    int rows = ((srcWidth>>3)<<3); 
    // 8 pixels per row 
    rows=rows>>3; 

    for (int r = 0; r < rows; r++) 
    { 
     // load 24 pixels (grayscale) 
     uint8x8x3_t pixels  = vld3_u8(src); 
     // first sum = d0 + d1 
     uint8x8_t firstSum  = vadd_u8 (pixels.val[0], pixels.val[1]); 
     // second sum = d1+d2; 
     uint8x8_t secondSum = vadd_u8 (firstSum, pixels.val[2]); 
     // total sum = d0+d1+d2 
     uint8x8_t totalSum  = vadd_u8(secondSum, firstSum); 
     // average = d0+d1+d2/8 ~9 for test 
     uint8x8_t totalAverage = vshr_n_u8(totalSum,3); 
     // store 8 bytes 
     vst1_u8(dst, totalAverage); 
     // move to next 3 rows 
     src+=24; 
     // move to next row 
     dst+=8; 

    } 

} 
+0

Я не знаю, что вы просите. Код в указанной ссылке обрабатывает 8 * пикселей * для каждой строки, а не 8 байтов. –

+0

@CareyGregory Я принимаю изображение в сером масштабе –

ответ

2

Для каждой строки развертки вы обработка, вы можете использовать structure loads через vld3.8. Если у вас есть начальные адреса первой, второй и третьей строке пикселей в r0..r2 затем:

vld3.8 {d0,d1,d2}, [r0] 
vld3.8 {d3,d4,d5}, [r1] 
vld3.8 {d6,d7,d8}, [r2] 

дает

  • d0 имеет байт [0,3,6,9,12,15,18,21] первой строки
  • d1 имеет байт [1,4,7,10,13,16,19,22] от первой строки
  • d2 имеет байты [2,5,8,11,14,17,20,23] первой линии
  • же для d3 .. d5 на 2-й линии и d6 .. d8 для третьего

Тогда усреднить их всех. Возможно, вы захотите расширить до 16 бит, чтобы не потерять точность.

Edit: от общего выглядит как (слева деления на девять вне):

// 
// load 3x8 bytes from three consecutive scanlines 
// 
uint8x8x3_t pixels[3] = 
    { vld3_u8(src), vld3_u8(src + srcwidth), vld3_u8(src + 2*srcwidth) }; 

// 
// expand them to 16bit so that the addition doesn't overflow 
// 
uint16x8_t wpix[9] = 
    { vmovl_u8(pixels[0].val[0]), 
     ... 
     vmovl_u8(pixels[3].val[2]) }; 

// 
// nine adds. Don't always add to wpix[0] because of possible dependencies. 
// 
wpix[0] = vaddq_u16(wpix[0], wpix[1]); 
wpix[2] = vaddq_u16(wpix[2], wpix[3]); 
wpix[4] = vaddq_u16(wpix[4], wpix[5]); 
wpix[6] = vaddq_u16(wpix[6], wpix[7]); 
wpix[0] = vaddq_u16(wpix[0], wpix[8]); 

wpix[1] = vaddq_u16(wpix[2], wpix[4]); 
wpix[3] = vaddq_u16(wpix[6], wpix[0]); 
wpix[0] = vaddq_u16(wpix[1], wpix[3]); 

[ .. divide-by-nine magic (in 16bit, aka for uint16x8_t), in wpix[0] ... ] 
// 
// truncate to 8bit and store back 
// 
vst1_u8(dst, vmovn_u16(wpix[0]); 

Успехов!

+0

Что такое инструкция для усреднения на 9? После этого я должен сохранить полученное значение из среднего? –

+2

Для этого нет никакой инструкции. Добавьте их и примерьте деление на 9. (d9 + d9 >> 3 - d9 >> 6) >> 3; уже совсем близко. –

+1

Существует эта знаменитая глава примера от восторга хакера от _division от констант, http://www.hackersdelight.org/divcMore.pdf, в которой есть пример того, как закодировать 'div9', используя только постоянные сдвиги и добавления. Это может быть сделано полностью в инструкциях NEON, если это необходимо. Код Аки является приблизительным. –