TL;DR
我正在寻找一种方法来提取现有 CUDA 工具包示例的一部分并将其转换为 MATLAB 中的 CUDAKernel 可执行文件。
故事
为了获得非本地均值 (NLM) 2D 过滤器的短运行时实现,我偶然发现了 CUDA 工具包提供的 imageDenoising 示例,该示例实现了该过滤器的两个变体,称为 NLM 和 NLM2(或"快速 NLM")。
由于以前没有 CUDA 编码的经验,我最初试图遵循 MATLAB 关于该主题的文档,这导致了几个奇怪的错误,包括:ptx 编译、多个入口点和 C 原型中的输入数量错误。在这一点上,我意识到这不会是一个"正常工作"的案例,需要一些修补。
因此,我决定通过简单地删除imageDenoising.cu
文件的一部分并将相关.cuh
(..._nlm_kernel.cuh
或..._nlm2_kernel.cuh
)合并到.cu
中来消除多入口点问题,以便在任何给定时间获得单个入口点。令我惊讶的是,这实际上设法编译了,我终于能够创建一个没有错误的CUDAKernel
(使用命令 k = parallel.gpu.CUDAKernel('imageDenoising.ptx', 'uint8_T *, int, int, float, float');
)。
然而,这还不够,因为我错误地得出结论,第一个参数是 RGB 矩阵形式的未处理图像(即 X*Y*3 uint8
),所以我得到的结果正是输入,但在第一个 4 个元素中带有0
。
搜索了更多之后,我意识到在这样的转换过程中,还有一些我完全不知道的、关键的方面(比如需要初始化__device__
变量),在这个阶段我决定寻求帮助。
问题所在
我目前想知道如何有效地从这里继续。虽然我很想听听这种方法是否通常可以取得成果(以及是否有这个过程的完整示例在某处可用),我应该注意哪些其他陷阱,以及我可以采取哪些替代行动方案(考虑到我在 CUDA 方面的知识非常有限以及我不会雇用其他人为我做这件事), 我记住这是SO,所以我必须有一个特定的编程问题,所以这里是:
如何修改
imageDenoising.cu
,以便从中构造的 MATLABCUDAKernel
也接受未处理的图像作为输入?
注意:在我的应用程序中,输入矩阵是二维灰度double
矩阵。
相关: CudaMalloc 如何工作?
附言
一段工作代码显然是受欢迎的,但我真的宁愿"学习钓鱼"。
我最终对 CUDAKernel 采取了另一种方法,使用 .MEX
,通过执行以下操作:
- 设置外部库 OpenCV v2.4.10(不是 v3!)和 mexopencv。
- 为OpenCV的fastNlMeans编写一个小包装器函数,使用mexopencv的准则对未实现的函数进行降噪,如下所示(不包括文档):
#include "mexopencv.hpp"
using namespace cv;
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
// Check arguments
if (nlhs != 1 || nrhs<1 || ((nrhs % 2) != 1) )
mexErrMsgIdAndTxt("fastNLM:invalidArgs", "Wrong number of arguments");
// Argument vector
vector<MxArray> rhs(prhs, prhs + nrhs);
// Option processing
// Defaults:
double h = 3;
int templateWindowSize = 7;
int searchWindowSize = 21;
// Parsing input name-value pairs:
for (int i = 1; i<nrhs; i += 2) {
string key = rhs[i].toString();
if (key == "h")
h = rhs[i + 1].toDouble();
else if (key == "templateWindowSize")
templateWindowSize = rhs[i + 1].toInt();
else if (key == "searchWindowSize")
searchWindowSize = rhs[i + 1].toInt();
else
mexErrMsgIdAndTxt("mexopencv:error", "Unrecognized option");
}
// Process
Mat src(rhs[0].toMat()), dst;
fastNlMeansDenoising(src, dst, h, templateWindowSize, searchWindowSize);
// Convert cv::Mat back to mxArray*
plhs[0] = MxArray(dst);
}
- 编译它.....和中提琴 - 一个工作 CUDA 加速的 NLM 过滤器。
我的问题本身的答案可以通过比较opencvsourcesmodulesphotosrccudanlm.cu
(这是opencv2路径)与imageDenoising_nlm2_kernel.cuh
。
这个解决方案对我来说效果很好,因为对我来说,运行 NLM 过滤器比使用 CUDAKernel 更重要。
我从中学到的主要教训(我想传递给其他人)是:
在 MATLAB 中运行 CUDA 代码也可以通过 CUDAKernel 以外的方式完成,例如使用
.mex
包装器,如上所示。