嗯,这篇文章是Why is memcpy() and memmove() faster than pointer increments?
的原因我有一个带有4个通道的自定义图像结构,我喜欢将其中的3个(RGB)提取到具有3个通道的openCV cv :: MAt strcuture中。
cv::Mat GetColorImgFromFrame(Image* pimg)
{
int iHeight = pimg->m_imageInfo.m_height;
int iWidth = pimg->m_imageInfo.m_width;
cv::Mat cvmColorImg = cv::Mat::zeros(iHeight, iWidth, CV_8UC3);
int iDestStep = cvmColorImg.channels(); // 3
uchar* pucSrc = pimg->m_data;
uchar* pucDest = cvmColorImg.data;
uchar* pucDestLimit = cvmColorImg.data + iHeight*iWidth*iDestStep;
for (;pucDest < pucDestLimit;)
{
*(pucDest++) = *(pucSrc++);
*(pucDest++) = *(pucSrc++);
*(pucDest++) = *(pucSrc++);
pucSrc++;
}
return cvmColorImg;
}
用memcpy(pucDest,pucSrc,3)替换三个内部赋值似乎没什么帮助。有什么建议?
答案 0 :(得分:3)
在32位计算机上,您可以尝试使用unsigned int *
每个循环从源到目标一次复制4个字节。诀窍是保持pucDest
uchar
指针增加3.您已将最后一个字作为特殊情况处理,而不是违反最后一个字节的目标数组的数组边界。
由于复制int通常不比在大多数机器上复制char慢,我怀疑这会使你的速度增加大约3倍。
答案 1 :(得分:3)
在使用SIMD intrinsic进入“汇编程序”模式之前,您可以尝试告诉编译器源和目标指针不是别名,例如使用带有gcc或{的__restrict__
关键字{1}}使用visual studio
答案 2 :(得分:1)
扩展Doc Brown的答案,展开循环,这样你就可以为每四次读取编写三个uint32_t
个整数(uint64_t
将会获得更大的吸引力,但会更难处理)。
如果pimg->m_data
和cvmColorImg.data
未在uint32_t
边界上开始,则读取和写入整数可能会有问题。您可以通过在这些int
数据成员之前添加unsigned int
或char*
数据成员来强制执行此操作。或者你可以使用类似于Duff设备的东西。个人偏好:我只想强制对齐。它使复制代码更清晰,更简单,也许更快。填充的一些浪费字节是一个很小的成本。
通常情况下,展开的循环,你必须做一些特殊的事情来处理结束。 (Duff的设备在开始时处理奇怪的事情,所以不要在这里使用Duff的设备。)如果填充输出缓冲区的末尾使其占用4 * N字节,循环处理结束的许多问题将消失