Image processing 利用霓虹灯对图像进行下采样的算法

Image processing 利用霓虹灯对图像进行下采样的算法,image-processing,assembly,arm,neon,Image Processing,Assembly,Arm,Neon,我想知道是否可以使用霓虹灯矢量将图像的采样减少3? 我正试图在纸上写一个算法,但这似乎是不可能的。因为当你得到例如8个字节时,你不能得到3*3像素,没有足够的像素来完成下采样操作。根据下样本2: 我考虑从一行加载16字节,然后8字节,然后将它们分配给32字节的向量,然后处理该向量的24字节 更新: 我已经根据答案编写了一个示例代码,但是我在vst1_u8中发现了一个分段错误 inline void downsample3dOnePass( uint8_t* src, uint8_t *dst,

我想知道是否可以使用霓虹灯矢量将图像的采样减少3? 我正试图在纸上写一个算法,但这似乎是不可能的。因为当你得到例如8个字节时,你不能得到3*3像素,没有足够的像素来完成下采样操作。根据下样本2: 我考虑从一行加载16字节,然后8字节,然后将它们分配给32字节的向量,然后处理该向量的24字节

更新: 我已经根据答案编写了一个示例代码,但是我在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;

    }

}
inline void downsample3dOnePass(uint8_t*src、uint8_t*dst、int srcWidth)
{
//确保行/列可以除以8
int行=((srcWidth>>3)3;
对于(int r=0;r
对于您处理的每条扫描线,您可以通过
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
    ,第三行的
    d6
    d8
然后将它们全部平均。为了不降低精度,您可能需要扩展到16位

编辑:总数看起来有点像(左除以九):


祝你好运!

我不知道你在问什么。你提供的链接中的代码是每行处理8个像素,而不是8个字节。@CareyGregory我假设的是灰度图像,求9的平均值的指令是什么?之后我应该存储平均值的结果值?没有一条指令可以这样做。将它们相加并逼近用9除法(d9+d9>>3-d9>>6)>>3;已经很接近了。在《黑客对常数除法的喜爱》中有一个著名的例子章节,其中有一个例子,说明了如何只使用常数移位和加法来编写
div9
。如果必要的话,这可以完全用霓虹灯指令来完成。Aki的代码就是这一点的近似值。@FrankH。我已经将我的问题更新为n电子战代码,根据你的answer@Ahmed:您的
vst
内部指令中的分段错误意味着目标(
dst
)指针无效。您能否在调试器中运行它并获取寄存器状态以及精确的
PC
值/错误指令?
//
// 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]);