我试图写一个更好的版本的cv::resize()的OpenCV,我来了一个交叉的代码,在这里:https://github.com/rmaz/NEON-Image-Downscaling/blob/master/ImageResize/BDPViewController.m代码是下行采样的图像2,但我不能得到的算法。我想先把这个算法转换成C语言,然后为了学习的目的对它进行修改。是否也容易将其转换为任意大小的downsample ?
函数是:
static void inline resizeRow(uint32_t *dst, uint32_t *src, uint32_t pixelsPerRow)
{
const uint32_t * rowB = src + pixelsPerRow;
// force the number of pixels per row to a multiple of 8
pixelsPerRow = 8 * (pixelsPerRow / 8);
__asm__ volatile("Lresizeloop: n" // start loop
"vld1.32 {d0-d3}, [%1]! n" // load 8 pixels from the top row
"vld1.32 {d4-d7}, [%2]! n" // load 8 pixels from the bottom row
"vhadd.u8 q0, q0, q2 n" // average the pixels vertically
"vhadd.u8 q1, q1, q3 n"
"vtrn.32 q0, q2 n" // transpose to put the horizontally adjacent pixels in different registers
"vtrn.32 q1, q3 n"
"vhadd.u8 q0, q0, q2 n" // average the pixels horizontally
"vhadd.u8 q1, q1, q3 n"
"vtrn.32 d0, d1 n" // fill the registers with pixels
"vtrn.32 d2, d3 n"
"vswp d1, d2 n"
"vst1.64 {d0-d1}, [%0]! n" // store the result
"subs %3, %3, #8 n" // subtract 8 from the pixel count
"bne Lresizeloop n" // repeat until the row is complete
: "=r"(dst), "=r"(src), "=r"(rowB), "=r"(pixelsPerRow)
: "0"(dst), "1"(src), "2"(rowB), "3"(pixelsPerRow)
: "q0", "q1", "q2", "q3", "cc"
);
}
To call it:
// downscale the image in place
for (size_t rowIndex = 0; rowIndex < height; rowIndex+=2)
{
void *sourceRow = (uint8_t *)buffer + rowIndex * bytesPerRow;
void *destRow = (uint8_t *)buffer + (rowIndex / 2) * bytesPerRow;
resizeRow(destRow, sourceRow, width);
}
算法非常简单。它从当前行读取8个像素,从下一行读取8个像素。然后使用vhadd(减半-add)指令垂直平均8个像素。然后它调换像素的位置,使水平相邻的像素对现在在单独的寄存器中(垂直排列)。然后再做另一组减半——将这些加起来取平均值。然后将结果再次转换,将它们放在原始位置并写入目的地。该算法可以重写以处理不同的积分大小的缩放,但按照所写的,它只能进行2x2到1的平均化简。下面是等价的C代码:
static void inline resizeRow(uint32_t *dst, uint32_t *src, uint32_t pixelsPerRow)
{
uint8_t * pSrc8 = (uint8_t *)src;
uint8_t * pDest8 = (uint8_t *)dst;
int stride = pixelsPerRow * sizeof(uint32_t);
int x;
int r, g, b, a;
for (x=0; x<pixelsPerRow; x++)
{
r = pSrc8[0] + pSrc8[4] + pSrc8[stride+0] + pSrc8[stride+4];
g = pSrc8[1] + pSrc8[5] + pSrc8[stride+1] + pSrc8[stride+5];
b = pSrc8[2] + pSrc8[6] + pSrc8[stride+2] + pSrc8[stride+6];
a = pSrc8[3] + pSrc8[7] + pSrc8[stride+3] + pSrc8[stride+7];
pDest8[0] = (uint8_t)((r + 2)/4); // average with rounding
pDest8[1] = (uint8_t)((g + 2)/4);
pDest8[2] = (uint8_t)((b + 2)/4);
pDest8[3] = (uint8_t)((a + 2)/4);
pSrc8 += 8; // skip forward 2 source pixels
pDest8 += 4; // skip forward 1 destination pixel
}