将 cv::cuda::GpuMat 与推力和测试推力 API 一起使用时出现问题

Posted

技术标签:

【中文标题】将 cv::cuda::GpuMat 与推力和测试推力 API 一起使用时出现问题【英文标题】:Problems when using cv::cuda::GpuMat with thrust and testing thrust API 【发布时间】:2021-03-13 17:52:15 【问题描述】:

我想将 cv::cuda::GpuMat 传递给推力函数,我发现 this function 可用于创建索引 cv::cuda::GpuMat 的推力迭代器。我在以下代码中有 2 个问题:

#include <stdio.h>
#include<io.h>
#include <stdlib.h>
#include <fstream>
#include<string>
#include<iostream>
#include <time.h>
#include <vector> 
  
#include <cuda_runtime.h>
#include "device_launch_parameters.h"

#include <thrust/host_vector.h>
#include<thrust/functional.h>
#include <thrust/device_vector.h>
#include <thrust/generate.h>
#include <thrust/sort.h>
#include <thrust/copy.h>

#include<opencv2/opencv.hpp>
#include<cudaimgproc.hpp>
#include<opencv2/cudafilters.hpp>
#include<opencv2/cudaarithm.hpp>


template<typename T>
    struct greater_than_value_pred
    
        T value;
    greater_than_value_pred(T value) : value(value) 

    __host__ __device__
        bool operator()(T v) const  return v > value; 
;

    using namespace std;


    int main()
    
        int compare_vari = 20;
    
    
        cv::cuda::GpuMat d_data_open(1, 100, CV_32SC2);
        // Thrust compatible begin and end iterators to channel 0 of this matrix
        auto idxBegin = GpuMatBeginItr<int>(d_data_open, 1);
        auto idxEnd = GpuMatEndItr<int>(d_data_open, 1);
        // Fill the index channel with a sequence of numbers from 0 to 100
        thrust::sequence(idxBegin, idxEnd);
        d_iter = thrust::find_if(idxBegin, idxEnd, greater_than_value_pred<int>(compare_vari));

        /*Use thrust::device_data to test */
        thrust::device_vector<int> d_thrust_data;
        thrust::device_vector<int>::iterator d_iter;
        thrust::sequence(d_thrust_data.begin(), d_thrust_data.end());
        d_iter = thrust::find_if(d_thrust_data.begin(), d_thrust_data.end(), greater_than_value_pred<int>(compare_vari));
        //std::cout << *d_iter << std::endl;
    

问题 1: 此代码无法遵守:d_iter = thrust::find_if(idxBegin, idxEnd, greater_than_value_pred&lt;double&gt;(compare_vari)); 使用 idxBegin 和 idxEnd 可以很好地与thrust::sequence()、sort() 等一起使用,但是当将它们应用于thrust::find_if() 时,它会提示“没有运算符'=' 与这些操作数匹配”。

问题 2:

*//std::cout << *d_iter << std::endl;*

我想通过上面的代码检查结果,但是在调试时它说 abort() 已被调用。我想知道 d_iter 是否在设备内存中,如果是,我需要将其复制到主机内存中吗?但是我不知道如何将迭代器复制到主机内存中。

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

问题 2:

*//std::cout d_iter 我想通过上面的代码检查结果,但是在调试时它说 abort() 已被调用。我想知道 d_iter 是否在设备内存中,如果是,我需要将其复制到主机内存中吗?但是我不知道如何将迭代器复制到主机内存中。

(您不想将 迭代器 复制到主机内存,您希望将 迭代器指向的内容 复制到主机内存。)

这里的问题是您没有为有问题的device_vector 提供任何实际大小:

    thrust::device_vector<int> d_thrust_data;

创建一个没有分配的空向量。因此,没有引用该向量的迭代器将指向任何有效的内容,因为没有与该向量关联的分配。如果我们修改为:

    thrust::device_vector<int> d_thrust_data(22);

我们现在已经创建了一个包含 22 个元素的向量,然后您的其余代码(包括您的 std::cout ... 语句)将是明智的。 (21 或更大也很重要,因为您的 find_if 正在寻找值 20 的元素。)

以下代码解决了上述问题,并且对我来说似乎可以正确编译和运行:

$ cat t100.cu
#include <stdio.h>
#include <stdlib.h>

#include <thrust/host_vector.h>
#include <thrust/functional.h>
#include <thrust/device_vector.h>
#include <thrust/generate.h>
#include <thrust/sort.h>
#include <thrust/copy.h>


template<typename T>
    struct greater_than_value_pred
    
        T value;
    greater_than_value_pred(T value) : value(value) 

    __host__ __device__
        bool operator()(T v) const  return v > value; 
;

    using namespace std;


    int main()
    
        int compare_vari = 20;

        /*Use thrust::device_data to test */
        thrust::device_vector<int> d_thrust_data(22);
        thrust::device_vector<int>::iterator d_iter;
        thrust::sequence(d_thrust_data.begin(), d_thrust_data.end());
        d_iter = thrust::find_if(d_thrust_data.begin(), d_thrust_data.end(), greater_than_value_pred<int>(compare_vari));
        std::cout << *d_iter << std::endl;
    
$ nvcc -o t100 t100.cu
$ ./t100
21
$

【讨论】:

感谢您的帮助。很抱歉,我发现我在问题 1 中输入了错误的代码,d_iter = thrust::find_if(d_thrust_data.begin(), d_thrust_data.end(), greater_than_value_pred(compare_vari)) can compile。它是d_iter = thrust::find_if(idxBegin, idxEnd, greater_than_value_pred&lt;double&gt;(compare_vari)); 无法编译。我在linkhere 中使用的 idxBegin 和 idxEnd 在使用thrust::find_if() 时出错。我改变了我的帖子。 您是否尝试将谓词类型从 double 更改为 int 是的,我按照你的帖子改了类型,问题2就解决了。 我的意思是你把这个:d_iter = thrust::find_if(idxBegin, idxEnd, greater_than_value_pred&lt;double&gt;(compare_vari)); 改成这个:d_iter = thrust::find_if(idxBegin, idxEnd, greater_than_value_pred&lt;int&gt;(compare_vari)); 是的,我已经改成这个并试过了,但它无法编译并出现错误 no operator '=' 与这些操作数匹配。

以上是关于将 cv::cuda::GpuMat 与推力和测试推力 API 一起使用时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

如何根据 cmak 在 qt creator 中使用 opencv Cuda

将推力与 printf / cout 一起使用

cuda 推力::for_each 与推力::counting_iterator

推力::设备向量使用推力::替换或推力::转换与自定义函子/谓词

如何使用推力和 CUDA 流将内存从主机异步复制到设备

如何将向量传递给基于推力的 odeint 观察者的构造函数,以便可以在函子中读取它