首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在OpenCV中循环16位Mat像素的有效方法

在OpenCV中循环16位Mat像素的有效方法
EN

Stack Overflow用户
提问于 2015-02-10 03:41:54
回答 3查看 5.9K关注 0票数 5

我试图在一个16位灰度的OpenCV Mat上进行非常简单的(LUT样的)操作,这是有效的,不会减慢调试器的速度。

虽然有一个文档中非常详细的一页解决了这个问题,但是它没有指出大多数方法只能在8位图像上可用(包括完美的优化的LUT函数)。

我尝试了以下方法:

代码语言:javascript
运行
复制
uchar* p = mat_depth.data;
for (unsigned int i = 0; i < depth_width * depth_height * sizeof(unsigned short); ++i)
{
    *p = ...;
    *p++;
}

非常快,不幸的是只支持uchart (就像LUT)。

代码语言:javascript
运行
复制
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。对我不管用,而且很慢。

代码语言:javascript
运行
复制
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内置LUT函数的源代码指出的,但是它只提到了高级优化技术,比如IPP和OpenCL。

我要找的是一个非常简单的循环,就像第一个代码,但是对于ushorts来说。

你建议用什么方法来解决这个问题?我并不是在寻找极端的优化,只是一些与.data上的单循环性能相当的东西。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-02-11 01:13:16

我实现了Michael和Kornel的建议,并在发布模式和调试模式中对它们进行了基准测试。

代码:

代码语言:javascript
运行
复制
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;
}

结果如下(发布/调试):

  • LUT_16: 0.202 ms / 0.773 ms
  • LUT_16_reinterpret_cast:0.184 ms / 0.801 ms
  • LUT_16_if: 0.249毫秒/ 0.860毫秒

因此,reinterpret_cast在发布模式下的速度要快9%,而在调试模式下要快4%。

同样有趣的是,直接调用if函数而不是应用LUT只会使它慢0.065 ms。

规范:流媒体640x480x16位灰度图像,Visual,2013年,i7 4750 i7。

票数 5
EN

Stack Overflow用户

发布于 2015-02-10 08:47:52

OpenCV实现基于多态和对模板的运行时调度。在OpenCV版本中,模板的使用仅限于一组固定的原始数据类型。也就是说,数组元素应该具有以下类型之一:

  • 8位无符号整数(uchar)
  • 8位有符号整数(schar)
  • 16位无符号整数(ushort)
  • 16位有符号整数(短)
  • 32位有符号整数(int)
  • 32位浮点数(浮点数)
  • 64位浮点数(双)
  • 由几个元素组成的元组,其中所有元素都具有相同的类型(上面的一种)。

如果您的cv::Mat继续,您可以使用指针算法来遍历整个数据指针,并且您应该只对您的cv::Mat使用适当的指针类型。此外,请记住,cv::Mat并不总是连续的(可以是ROI、填充或由像素指针创建的),并且使用指针迭代它们会崩溃。

一个示例循环:

代码语言:javascript
运行
复制
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;
    }
}
票数 4
EN

Stack Overflow用户

发布于 2015-02-10 07:21:49

您的问题的最佳解决方案已经写在您提到的教程中,在题为“高效方式”的章节中。你所需要的就是用ushort来替换uchar的每一个实例。不需要进行其他修改。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28423701

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档