两通道 cv::Mat 对象填充了没有 for 循环的行列索引

Posted

技术标签:

【中文标题】两通道 cv::Mat 对象填充了没有 for 循环的行列索引【英文标题】:Two-channel cv::Mat object filled with row-col indexes without for cycle 【发布时间】:2016-01-28 13:22:46 【问题描述】:

我想在 OpenCV 中创建一个双通道矩阵,其值是对应的一对行和列索引。我可以通过以下方式轻松做到这一点:

for (int i = 0 ; i< img_height ; ++ i)
    for (int j = 0 ; j < img_width ; ++ j)
        src.ptr<Point2f>(i)[j] = Point2f(j,i);
    

我想知道 OpenCV 中是否有一种方法可以更快、更紧凑地初始化这样的矩阵,而不必使用这种逐元素的方法。我搜索了文档,但没有找到任何可以帮助我实现此目的的东西。

我之所以这么问,是因为我确实需要我的应用程序更快,所以我正在寻找可以对我的代码应用的任何可能的改进。

提前致谢

【问题讨论】:

没有内置函数可以做到这一点。你最终可以play with repeat。但是,我不认为这个简短的 sn-p 是一个瓶颈,即使你可以应用一些改进。你剖析过吗?多久时间?典型的图像宽度和高度? 图像尺寸为 [320x240],但稍后我将使用 [640x480]。大约需要 0.7 毫秒。当然,这不是我的瓶颈,但每一个最终的小加速都会受到赞赏。 好的。发布了答案。你能在你的机器上试试 sn-p 并检查执行时间吗?在我的机器上,这要快一点。 【参考方案1】:

对此没有内置函数。您最终可以使用 repeat 模拟 Matlab 函数 meshgrid,但在这种情况下会慢得多。

但是,您可以改进一些事情:

从内部循环中取出指向行首的指针,因为每一行的指针都是相同的。 避免创建临时对象来存储值。 我想你交换了 i 和 j。

看看这段代码:

Mat2f src(img_height, img_width);

for (int i = 0; i < img_height; ++i) 
    Vec2f* ptr = src.ptr<Vec2f>(i);
    for (int j = 0; j < img_width; ++j) 
        ptr[j][0] = i;
        ptr[j][1] = j;
    

这个 sn-p 稍微快一点(时间以毫秒为单位):

@MarcoFerro:    1.22755
@Miki:          0.818491

测试代码:

#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

int main()

    int img_height = 480;
    int img_width = 640;

    
        Mat2f src(img_height, img_width);

        double tic = double(getTickCount());
        for (int i = 0; i< img_height; ++i)
            for (int j = 0; j < img_width; ++j)
                src.ptr<Point2f>(i)[j] = Point2f(i, j);
            
        

        double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
        cout << "@MarcoFerro: \t" << toc << endl;
    
    
        Mat2f src(img_height, img_width);

        double tic = double(getTickCount());
        for (int i = 0; i < img_height; ++i) 
            Vec2f* ptr = src.ptr<Vec2f>(i);
            for (int j = 0; j < img_width; ++j) 
                ptr[j][0] = i;
                ptr[j][1] = j;
            
        

        double toc = (double(getTickCount()) - tic) * 1000.0 / getTickFrequency();
        cout << "@Miki: \t\t" << toc << endl;
    

    getchar();
    return 0;

【讨论】:

这是我的执行时间: MarcoFerro: 2.96967 @Miki: 1.73143 每次它给我不同的时间,但你的解决方案总是比我的快。我会应用你的更改。谢谢:) 最后一件事:i 和 j 是正确的,我需要它们作为 (x,y) 坐标,这就是我交换它们的原因(Point2f 也接受参数作为 x 和 y)。但无论如何,它有效,这才是最重要的 :) 再次感谢 当然,但是您说其值是对应的一对行和列索引,所以它是y和x。无论如何,只需根据需要放置索引:D

以上是关于两通道 cv::Mat 对象填充了没有 for 循环的行列索引的主要内容,如果未能解决你的问题,请参考以下文章

如何正确将 cv::Mat 转换为 CV_8UC1?

如何在不更改其他通道的情况下有效地将 cv::Mat 的给定通道设置为给定值?

open cv mat怎样将数据类型转化为double

opencv 单通道合并为多通道

opencv使用cv::Mat时,如何修改某个像素点的RGB分量

如何从函数返回多维 Mat 数组