You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenCL版OpenCV模板匹配慢于CPU及CUDA的问题排查

OpenCL模板匹配性能远低于CPU和CUDA的问题

我正在寻找最快的模板匹配方案,意外发现OpenCL实现的速度远慢于CPU和CUDA版本。原本我会选择CUDA,但因等待新AMD显卡,只能使用OpenCL。最新计时结果:

阶段耗时(ms)
CPU293.00
GPU(CUDA)268.00
GPU(OpenCL)539.00

我疑惑是自身实现存在疏漏,还是当前使用的Nvidia Quadro K620对OpenCL优化不足?以下是相关代码:

cv::Mat img = cv::imread("path-to-source-img");
std::vector<cv::Mat> templates;
std::vector<std::string> templatePaths = {"path/template1","path/template2"};
cv::Mat template_img = cv::imread("path/template1");

void loadTemplates() {
    for (const auto& path : templatePaths) {
        templates.push_back(cv::imread(path));
    }
}

void cpu() {
    START_TIMER
    cv::Mat imgCopy = img.clone();
    std::vector<std::future<cv::Point>> futures;

    auto matchTemplate = [](const cv::Mat& img, const cv::Mat& templ) {
        cv::Mat result;
        cv::matchTemplate(img, templ, result, cv::TM_CCOEFF_NORMED);
        cv::Point maxLocPoint;
        cv::minMaxLoc(result, 0, 0, 0, &maxLocPoint);
        return maxLocPoint;
    };

    // Create a future for each template
    for (const auto& templ : templates) {
        futures.push_back(std::async(std::launch::async, matchTemplate, img, templ));
    }

    // Collect results and draw rectangles
    for (size_t i = 0; i < templates.size(); ++i) {
        cv::Point maxLocPoint = futures[i].get();
        cv::Scalar color(0, 255 * (i + 1) / templates.size(), 255 * (templates.size() - i) / templates.size());
        cv::rectangle(imgCopy, cv::Rect(maxLocPoint, cv::Point(maxLocPoint.x + templates[i].cols, maxLocPoint.y + templates[i].rows)), color, 2);
    }

    END_TIMER(cpuMatching)
    cv::imshow("Result CPU Optimized", imgCopy);
    cv::waitKey(0);
}

void gpu() {
    START_TIMER
    cv::cuda::GpuMat srcGpu(img);
    std::vector<cv::cuda::GpuMat> templatesGpu;
    std::vector<cv::cuda::GpuMat> resultsGpu(templates.size());
    std::vector<cv::cuda::Stream> streams(templates.size());

    cv::Ptr<cv::cuda::TemplateMatching> matcher = cv::cuda::createTemplateMatching(img.type(), cv::TM_CCOEFF_NORMED);

    // Upload templates to GPU and launch matching operations
    for (size_t i = 0; i < templates.size(); ++i) {
        templatesGpu.emplace_back(templates[i]);
        matcher->match(srcGpu, templatesGpu.back(), resultsGpu[i], streams[i]);
    }

    // Process results
    std::vector<cv::Point> maxLocPoints(templates.size());
    for (size_t i = 0; i < templates.size(); ++i) {
        cv::Mat result;
        resultsGpu[i].download(result, streams[i]);

        streams[i].waitForCompletion();
        cv::minMaxLoc(result, nullptr, nullptr, nullptr, &maxLocPoints[i]);
    }

    END_TIMER(gpuMatching)

    cv::Mat imgCopy = img.clone();
    for (size_t i = 0; i < templates.size(); ++i) {
        cv::Scalar color(0, 255 * (i + 1) / templates.size(), 255 * (templates.size() - i) / templates.size());
        cv::rectangle(imgCopy, cv::Rect(maxLocPoints[i], templates[i].size()), color, 2);
    }

    cv::imshow("Result GPU Stream Optimized", imgCopy);
    cv::waitKey(0);
}

// Not yet implemented to work with several templates like cpu and cuda
void gpuOpenCL() {
    START_TIMER
    // Enable OpenCL
   cv::ocl::setUseOpenCL(true);

    if (!cv::ocl::haveOpenCL()) {
        std::cout << "OpenCL is not available..." << std::endl;
        return;
    }

    // Get OpenCL device information
    cv::ocl::Context context;
    if (!context.create(cv::ocl::Device::TYPE_GPU)) {
        std::cout << "Failed creating the context..." << std::endl;
        return;
    }

    // Print the detected OpenCL devices
    std::cout << context.ndevices() << " GPU devices are detected." << std::endl;
    for (int i = 0; i < context.ndevices(); i++) {
        cv::ocl::Device device = context.device(i);
        std::cout << "Device " << i << ": " << device.name() << std::endl;
    }

    cv::ocl::Device(context.device(0));

    cv::UMat result;
    result.create(img.rows - template_img.rows + 1, img.cols - template_img.cols + 1, CV_32FC1);

    cv::matchTemplate(img, template_img, result, cv::TM_CCOEFF_NORMED);
    END_TIMER(gpuOpenCLMatching)

    double minVal, maxVal;
    cv::Point minLoc, maxLoc;
    cv::minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc);

    cv::rectangle(img, maxLoc, cv::Point(maxLoc.x + template_img.cols, maxLoc.y + template_img.rows), cv::Scalar(0, 255, 0), 2);

    cv::imshow("OpencCL GPU Result", img);
    cv::waitKey(0);
}

int main() {
    loadTemplates();
    cpu();
    gpu();
    gpuOpenCL();
    displayTimingStats();
    return 0;
}

内容的提问来源于stack exchange,提问作者Jackolix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:20:10