此代码在嵌套循环中每次运行9600次,并且必须在iPhone4S上以不到30ms的总时间运行:
vImage_Buffer source = { sourceArea.data, patchSide, patchSide, patchSide };
vImage_Buffer destination = { (uchar*)malloc(patchSide * patchSide * sizeof(uchar)), patchSide, patchSide, patchSide };
vImage_AffineTransform transform = { warpingMatrix(0,0), warpingMatrix(0,1), warpingMatrix(1,0), warpingMatrix(1,1), 0, 0 };
if (vImageAffineWarp_Planar8(&source, &destination, NULL, &transform, 0, kvImageBackgroundColorFill) != kvImageNoError)
{
NSLog(@"Error in warping!");
}
它看起来不那么快,因为10x10补丁需要大约0.0002秒。我是否忽略了一些重大的性能错误?
我想解决的问题是后向扭曲图像的匹配,这是第一步。贴片在一个点周围的64个不同位置弯曲64次,最多150个点。
答案 0 :(得分:3)
10x10是一个非常小的图像。您很容易将大部分时间花在开销/ malloc上。仪器时间跟踪应该有助于确定时间的进展。
4s上的向量ALU也是5或5s的宽度的一半,所以不能提供与标量相同的胜利。
答案 1 :(得分:1)
如果可以重用缓冲区,vimage会更快。因此,如果可能的话,在循环外声明并分配缓冲区(或相关数据)。
unsigned char *sourceData = (unsigned char*)malloc(patchSide * patchSide * sizeof(uchar));
vImage_Buffer source = {sourceData, patchSide, patchSide, patchSide};
unsigned char *destinationData = (unsigned char*)malloc(patchSide * patchSide * sizeof(uchar));
vImage_Buffer destination = {destinationData, patchSide, patchSide, patchSide};
loop{
//fill sourceData e.g. through memcpy
memcpy(sourceData, somedata, patchSide * patchSide * sizeof(uchar));
if (vImageAffineWarp_Planar8(&source, &destination, NULL, &transform, 0, kvImageBackgroundColorFill) != kvImageNoError)
{
NSLog(@"Error in warping!");
}
//destinationData contains the result
}
答案 2 :(得分:0)
在不对代码进行太多更改的情况下,可以进行两项更改来提高性能:使用vImage框架分配源/目标缓冲区并创建临时缓冲区以便在循环内重用。第三个更改可能是更改您的磁贴大小(请参阅此答案的结尾)。
vImage / Accelerate Framework文档建议使用vImageBuffer_Init
(请参阅vImage_Utilities.h
)初始化缓冲区以确保实际缓冲区为
大小并对齐以获得最佳性能
而不是自己分配内存:
vImage_Buffer buffer;
vImage_Error err = vImageBuffer_Init(&buffer, height, width, 8 * sizeof(pixel), kvImageNoFlags);
您的案例中pixel
将Pixel_8
,因为您使用的是*_Planar8
函数。请注意,完成后仍需要释放buffer.data
。
因此,您应该在循环之外初始化源和目标:
vImage_Buffer source;
vImage_Buffer destination;
vImage_Error err = vImageBuffer_Init(&source, patchSide, patchSide, 8 * sizeof(Pixel_8), kvImageNoFlags);
err = vImageBuffer_Init(&destination, patchSide, patchSide, 8 * sizeof(Pixel_8), kvImageNoFlags);
将您的数据从sourceArea.data
复制到source.data
。请注意,source.rowBytes
不太可能等于source.width
。
您还应该创建一个临时缓冲区,以便vImageAffineWarp_Planar8
可以在每次迭代时重复使用它,而不是为每次迭代分配它,因为您已将NULL
作为第三个参数传入。要确定临时缓冲区的维度,可以在操作期间完全调用该函数,但使用标记kvImageGetTempBufferSize
,因为不同的参数/标志可能需要不同的缓冲区大小(请参阅@constant kvImageGetTempBufferSize
中的vImage_Types.h
}):
size_t tempBufferSize = vImageAffineWarp_Planar8(&source, &destination, NULL, &transform, 0, kvImageBackgroundColorFill | kvImageGetTempBufferSize);
然后您将分配临时缓冲区:
void *tempBuffer = malloc(tempBufferSize);
最后在你的循环中你每次都会使用tempBuf
:
if (vImageAffineWarp_Planar8(&source, &destination, &tempBuffer, &transform, 0, kvImageBackgroundColorFill) != kvImageNoError)
{
NSLog(@"Error in warping!");
}
因此,重新上限,源,目标和tempBuf
都是在循环之前使用vImageBuffer_Init
预先分配的,其中通过调用vImageAffineWarp_Planar8
来确定所需的tempBuf大小就像你将在循环中一样,但附加标志kvImageGetTempBufferSize
。希望这会加快你的速度!
如果你的算法支持它,你可能会看到最后一件事就是处理更大的图块或图像条纹(参见Tiling / Strip Mining and Multithreading
中的vImage.h
部分)。