我试图在16位灰阶OpenCV Mat上进行非常简单(类似LUT)的操作,这是有效的,并且不会减慢调试器的速度。
虽然有一个very detailed page in the documentation正好解决了这个问题,但它没有指出大多数这些方法仅适用于8位图像(包括完美的,优化的LUT函数)。
我尝试了以下方法:
uchar* p = mat_depth.data;
for (unsigned int i = 0; i < depth_width * depth_height * sizeof(unsigned short); ++i)
{
*p = ...;
*p++;
}
非常快,不幸的是只支持uchart(就像LUT一样)。
int i = 0;
for (int row = 0; row < depth_height; row++)
{
for (int col = 0; col < depth_width; col++)
{
i = mat_depth.at<short>(row, col);
i = ..
mat_depth.at<short>(row, col) = i;
}
}
改编自这个答案:https://stackoverflow.com/a/27225293/518169。没有为我工作,而且速度很慢。
cv::MatIterator_<ushort> it, end;
for (it = mat_depth.begin<ushort>(), end = mat_depth.end<ushort>(); it != end; ++it)
{
*it = ...;
}
运行良好,但是它使用了大量CPU并使调试器变得非常慢。
这个答案https://stackoverflow.com/a/27099697/518169指向source code of the built-in LUT function,但它只提到了高级优化技术,如IPP和OpenCL。
我正在寻找的是一个非常简单的循环,就像第一个代码一样,但对于我们来说。
您建议使用哪种方法来解决此问题?我不是在寻找极端优化,只是与.data上的单循环性能相提并论。
答案 0 :(得分:4)
OpenCV实现基于多态和模板上的运行时调度。在OpenCV版本中,模板的使用仅限于一组固定的原始数据类型。也就是说,数组元素应该具有以下类型之一:
如果你的cv::Mat
继续,你可以使用指针算术来遍历整个数据指针,你应该只使用适当的指针类型cv::Mat
。
此外,请注意cv::Mat
并不总是连续的(它可以是ROI,填充或从像素指针创建),并且使用指针迭代它们会崩溃。
示例循环:
cv::Mat cvmat16sc1 = cv::Mat::eye(10, 10, CV_16SC1);
if (cvmat16sc1.data)
{
if (!cvmat16sc1.isContinuous())
{
cvmat16sc1 = cvmat16sc1.clone();
}
short* ptr = reinterpret_cast<short*>(cvmat16sc1.data);
for (int i = 0; i < cvmat16sc1.cols * cvmat16sc1.rows; i++, ptr++)
{
if (*ptr == 1)
std::cout << i << ": " << *ptr << std::endl;
}
}
答案 1 :(得分:4)
我实施了Michael和Kornel的建议,并在发布和调试模式下对它们进行了基准测试。
代码:
cv::Mat LUT_16(cv::Mat &mat, ushort table[])
{
int limit = mat.rows * mat.cols;
ushort* p = mat.ptr<ushort>(0);
for (int i = 0; i < limit; ++i)
{
p[i] = table[p[i]];
}
return mat;
}
cv::Mat LUT_16_reinterpret_cast(cv::Mat &mat, ushort table[])
{
int limit = mat.rows * mat.cols;
ushort* ptr = reinterpret_cast<ushort*>(mat.data);
for (int i = 0; i < limit; i++, ptr++)
{
*ptr = table[*ptr];
}
return mat;
}
cv::Mat LUT_16_if(cv::Mat &mat)
{
int limit = mat.rows * mat.cols;
ushort* ptr = reinterpret_cast<ushort*>(mat.data);
for (int i = 0; i < limit; i++, ptr++)
{
if (*ptr == 0){
*ptr = 65535;
}
else{
*ptr *= 100;
}
}
return mat;
}
ushort* tablegen_zero()
{
static ushort table[65536];
for (int i = 0; i < 65536; ++i)
{
if (i == 0)
{
table[i] = 65535;
}
else
{
table[i] = i;
}
}
return table;
}
结果如下(发布/调试):
所以结论是reinterpret_cast在发布模式下的速度提高了9%,而ptr one在调试模式下的速度提高了4%。
有趣的是,直接调用if函数而不是应用LUT只会使它慢0.065 ms。
规格:流式传输640x480x16位灰度图像,Visual Studio 2013,i7 4750HQ。
答案 2 :(得分:3)
您的问题的最佳解决方案已在您提到的教程中编写,在“高效方式”一章中。您只需要用ushort替换每个uchar实例。不需要进行其他更改。