对图像进行快速矢量化逐像素运算

问题描述

我想使用均方误差测量两个灰度相同尺寸图像之间的相似度。我不能使用任何不属于macOS SDK的框架(例如OpenCV,Eigen)。无需向量化即可简单实现此算法,如下所示:

vImage_Buffer imgA;
vImage_Buffer imgB;

NSUInteger mse = 0;

unsigned char *pxlsA = (unsigned char *)imgA.data;
unsigned char *pxlsB = (unsigned char *)imgB.data;

for (size_t i = 0; i < imgA.height * imgA.width; ++i) {
    NSUInteger d = pxlsA[i] - pxlsB[i]);
    mse += d * d;
}

是否有某种方法可以更向量化地实现无循环运行?也许像这样:

mse = ((imgA - imgB) ^ 2).sum();

解决方法

该问题的答案存储在vDSP库中,该库是macOS SDK的一部分。 https://developer.apple.com/documentation/accelerate/vdsp

vDSP -对大向量执行基本的算术运算和常见的数字信号处理例程。

在我的情况下,我没有很大的向量,但是仍然。

首先,您需要将unsigned char *转换为float *,这是一个重要的时刻,我不知道如何不循环进行此操作。然后,您需要两个vDSP函数:vDSP_vsbsbmvDSP_sve

vDSP_vsbsm -将两个单精度矢量的差值乘以两个单精度矢量的第二个差值。

vDSP_sve -计算单精度向量中的值之和。

所以最终代码如下:

float *fpxlsA = (float *)malloc(imgA.height * imgA.width * sizeof(float));
float *fpxlsB = (float *)malloc(imgB.height * imgB.width * sizeof(float));
float *output = (float *)malloc(imgB.height * imgB.width * sizeof(float));

for (size_t i = 0; i < imgA.height * imgA.width; ++i) {
    fpxlsA[i] = (float)(pxlsA[i]);
    fpxlsB[i] = (float)(pxlsB[i]);
}    

vDSP_vsbsbm(fpxlsA,1,fpxlsB,fpxlsA,output,imgA.height * imgB.width);
float sum;
vDSP_sve(output,&sum,imgA.height * imgB.width);

free(output);
free(fpxlsA);
free(fpxlsB);

因此,此代码以更矢量化的形式完全实现了我想要的功能。但是结果还不够好。比较循环方法和vDSP方法的性能,如果没有任何额外的内存分配,vDSP的速度将提高两倍。但实际上,在发生额外的内存分配的情况下,循环方法会稍快一些。

,

这似乎是Mac OS的一部分:https://developer.apple.com/documentation/accelerate

,

又好又快地使用指针算法循环如下...

int d;

size_t i = imgA.height * imgA.width;

while ( i -- )
{
  d = ( int )(*pxlsA++) - ( int )(*pxlsB++);
  mse += d * d;
}

编辑

糟糕,因为这些是无符号字符,并且由于我们计算了差值,因此需要使用 signed 整数。

另一项编辑-必须在此处使用pxls...,不知道img...是什么。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...