cuda上使用remap函数
在使用opencv中的remap函数时,发现运行时间太长了,如果使用视频流进行重映射时根本不能实时,因此只能加速
1.使用opencv里的cv::cuda::remap函数
cv::cuda::remap函数头文件是#include <opencv2/cudawarping.hpp>,编译opencv时需要用cuda进行编译
//1.重映射矩阵转成cuda处理的数据格式//map_x,map_y是重映射表,数据类型是CV_32FC1cv::cuda::GpuMat m_mapx = ::cv::cuda::GpuMat(map_x);cv::cuda::GpuMat m_mapy = ::cv::cuda::GpuMat(map_y);//2.原图像转成cuda处理的数据格式cv::cuda::GpuMat src(img);//3.计算结果cv::cuda::GpuMat gpuMat2;cv::cuda::remap(src, gpuMat2, m_mapx, m_mapy, cv::INTER_LINEAR);//4.结果转成Matcv::Mat dstimage; gpuMat2.download(dstimage);
示例
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/cudawarping.hpp>using namespace cv;int main(int argc, char** argv)
{Mat img = imread("image.jpg", IMREAD_COLOR);if (img.empty()){std::cout << "Could not open the input image" << std::endl;exit(1);}int in_width = img.cols;int in_height = img.rows;Mat map_x(in_height, in_width, CV_32FC1);Mat map_y(in_height, in_width, CV_32FC1);// 创建重映射映射表for (int y = 0; y < in_height; y++) {for (int x = 0; x < in_width; x++) {map_x.at<float>(y, x) = (x + 20) / (float)in_width * in_width;map_y.at<float>(y, x) = y / (float)in_height * in_height;}}cv::cuda::GpuMat m_mapx = ::cv::cuda::GpuMat(map_x);cv::cuda::GpuMat m_mapy = ::cv::cuda::GpuMat(map_y);cv::cuda::GpuMat gpuMat1(img);double time0 = static_cast<double>(cv::getTickCount());//记录起始时间cv::cuda::GpuMat gpuMat2;cv::cuda::remap(gpuMat1, gpuMat2, m_mapx, m_mapy, cv::INTER_LINEAR);cv::Mat GPUimage;gpuMat2.download(GPUimage); time0 = ((double)cv::getTickCount() - time0) / cv::getTickFrequency();std::cout << "GPU运行remap函数的时间为:" << time0 * 1000 << "ms" << std::endl;double time1 = static_cast<double>(cv::getTickCount());//记录起始时间cv::Mat CPUimage;cv::remap(img, CPUimage, map_x, map_y, cv::INTER_LINEAR);time1 = ((double)cv::getTickCount() - time1) / cv::getTickFrequency();std::cout << "CPU运行remap函数的时间为:" << time1 * 1000 << "ms" << std::endl;return 0;
}
经过实际运行,在我电脑上速度快了15倍左右
2.在cuda上重写remap函数
这是在csdn上看到的一篇文章上写的代码,在我的实际应用中变换的结果是错误的,由于我实际的应用时,我的图像输入尺寸和输出尺寸是不相同的,因此运行错误,但是在输入输出是相同尺寸时是正确的,因为使用了cv::cuda::remap,我也没修改这个程序。
建立.cu文件,可以生成静态库使用,也可以不生成使用
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda_runtime_api.h>
#include <stdio.h>
#include <math.h>__global__ void remap_kernel(const unsigned char* src, int src_width, int src_height,unsigned char* dst, int dst_width, int dst_height,const float* map_x, const float* map_y)
{int x = threadIdx.x + blockIdx.x * blockDim.x;int y = threadIdx.y + blockIdx.y * blockDim.y;if (x < dst_width && y < dst_height) {int index = (y * dst_width + x) * 3;float src_x = map_x[index / 3];float src_y = map_y[index / 3];if (src_x >= 0 && src_x < src_width - 1 && src_y >= 0 && src_y < src_height - 1) {int x0 = floorf(src_x);int y0 = floorf(src_y);int x1 = x0 + 1;int y1 = y0 + 1;float tx = src_x - x0;float ty = src_y - y0;int src_index00 = (y0 * src_width + x0) * 3;int src_index10 = (y0 * src_width + x1) * 3;int src_index01 = (y1 * src_width + x0) * 3;int src_index11 = (y1 * src_width + x1) * 3;for (int i = 0; i < 3; i++) {float value00 = src[src_index00 + i];float value10 = src[src_index10 + i];float value01 = src[src_index01 + i];float value11 = src[src_index11 + i];float value0 = value00 * (1.0f - tx) + value10 * tx;float value1 = value01 * (1.0f - tx) + value11 * tx;float value = value0 * (1.0f - ty) + value1 * ty;dst[index + i] = static_cast<unsigned char>(value);}}}
}extern "C" void remap_gpu(const unsigned char* in, int in_width, int in_height,unsigned char* out, int out_width, int out_height,const float* map_x, const float* map_y) {unsigned char* d_in, * d_out;float* d_map_x, * d_map_y;cudaMalloc((void**)&d_in, in_width * in_height * 3);cudaMalloc((void**)&d_out, out_width * out_height * 3);cudaMalloc((void**)&d_map_x, out_width * out_height * sizeof(float));cudaMalloc((void**)&d_map_y, out_width * out_height * sizeof(float));cudaMemcpy(d_in, in, in_width * in_height * 3, cudaMemcpyHostToDevice);cudaMemcpy(d_map_x, map_x, out_width * out_height * sizeof(float), cudaMemcpyHostToDevice);cudaMemcpy(d_map_y, map_y, out_width * out_height * sizeof(float), cudaMemcpyHostToDevice);dim3 block(32, 32, 1);dim3 grid((out_width + block.x - 1) / block.x, (out_height + block.y - 1) / block.y, 1);remap_kernel << <grid, block >> > (d_in, in_width, in_height, d_out, out_width, out_height, d_map_x, d_map_y);cudaMemcpy(out, d_out, out_width * out_height * 3, cudaMemcpyDeviceToHost);cudaFree(d_in);cudaFree(d_out);cudaFree(d_map_x);cudaFree(d_map_y);
}
重新新建一个.cpp文件
#include <iostream>
#include <opencv2/opencv.hpp>using namespace cv;extern "C" void remap_gpu(const unsigned char* in, int in_width, int in_height,unsigned char* out, int out_width, int out_height,const float* map_x, const float* map_y);int main(int argc, char** argv)
{cv::Mat img = imread("image.jpg", IMREAD_COLOR);if (img.empty()) {std::cout << "Could not open the input image" << std::endl;exit(1);}int in_width = img.cols;int in_height = img.rows;cv::Mat map_x(in_height, in_width, CV_32FC1);cv::Mat map_y(in_height, in_width, CV_32FC1);// 创建重映射映射表for (int y = 0; y < in_height; y++) {for (int x = 0; x < in_width; x++) {map_x.at<float>(y, x) = (x + 20) / (float)in_width * in_width;map_y.at<float>(y, x) = y / (float)in_height * in_height;}}double time0 = static_cast<double>(cv::getTickCount());//记录起始时间cv::Mat CPUimage;remap(img, CPUimage, map_x, map_y, cv::INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));time0 = ((double)cv::getTickCount() - time0) / cv::getTickFrequency();std::cout << "CPU 运行remap函数时间为:" << time0 * 1000 << "ms" << std::endl;int out_width = in_width;int out_height = in_height; unsigned char* out = (unsigned char*)malloc(out_width * out_height * 3);double time1 = static_cast<double>(cv::getTickCount());//记录起始时间unsigned char* in = (unsigned char*)img.data;remap_gpu(in, in_width, in_height, out, out_width, out_height, (float*)map_x.data, (float*)map_y.data);cv::Mat GPUimage(out_height, out_width, CV_8UC3, out);time1 = ((double)cv::getTickCount() - time1) / cv::getTickFrequency();std::cout << "GPU 运行remap函数时间为:" << time1 * 1000 << "ms" << std::endl;free(out);return 0;
}
只运行一帧时cpu上运行的remap较快,运行多帧时,GPU上运行的remap函数要比CPU上运行快5倍左右
总结
如果自己编译的opencv带cuda,最好还是使用cv::cuda::remap函数,耗时较少
相关文章:
cuda上使用remap函数
在使用opencv中的remap函数时,发现运行时间太长了,如果使用视频流进行重映射时根本不能实时,因此只能加速 1.使用opencv里的cv::cuda::remap函数 cv::cuda::remap函数头文件是#include <opencv2/cudawarping.hpp>,编译ope…...
【JaveWeb教程】(18) MySQL数据库开发之 MySQL数据库设计-DDL 如何查询、创建、使用、删除数据库数据表 详细代码示例讲解
目录 2. 数据库设计-DDL2.1 项目开发流程2.2 数据库操作2.2.1 查询数据库2.2.2 创建数据库2.2.3 使用数据库2.2.4 删除数据库 2.3 图形化工具2.3.1 介绍2.3.2 安装2.3.3 使用2.2.3.1 连接数据库2.2.3.2 操作数据库 2.3 表操作2.3.1 创建2.3.1.1 语法2.3.1.2 约束2.3.1.3 数据类…...
ElasticSearch学习笔记-SpringBoot整合Elasticsearch7
项目最近需要接入Elasticsearch7,顺带记录下笔记。 Elasticsearch依赖包版本 <properties><elasticsearch.version>7.9.3</elasticsearch.version><elasticsearch.rest.version>7.9.3</elasticsearch.rest.version> </propertie…...
[足式机器人]Part2 Dr. CAN学习笔记 - Ch02动态系统建模与分析
本文仅供学习使用 本文参考: B站:DR_CAN Dr. CAN学习笔记 - Ch02动态系统建模与分析 1. 课程介绍2. 电路系统建模、基尔霍夫定律3. 流体系统建模4. 拉普拉斯变换(Laplace)传递函数、微分方程4.1 Laplace Transform 拉式变换4.2 收…...
【一周年创作总结】人生是远方的无尽旷野呀
那一眼瞥见的伟大的灵魂,却似模糊的你和我 文章目录 📒各个阶段的experience🔎大一寒假🔎大一下学期🔎大一暑假🔎大二上学期(现在) 🍔相遇CSDN🛸自媒体&#…...
金融帝国实验室(Capitalism Lab)V10版本游戏平衡性优化与改进
即将推出的V10版本中的各种游戏平衡性优化与改进: ————————————— 一、当玩家被提议收购一家即将破产的公司时,显示商业秘密。 当一家公司濒临破产,玩家被提议收购该公司时,如果玩家有兴趣评估该公司,则无…...
[SpringBoot]接口的多实现:选择性注入SpringBoot接口的实现类
最近在项目中遇到两种情况,准备写个博客记录一下。 情况说明:Service层一个接口是否可以存在多个具体实现,此时应该如何调用Service(的具体实现)? 其实之前的项目中也遇到过这种情况,只不过我采…...
北京大学 wlw机器学习2022春季期末试题分析
北京大学 wlw机器学习2022春季期末试题分析 前言新的开始第一题第二题第三题 前言 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 新的开始 第…...
前端文件下载方法(包含get和post)
export const downloadFileWithIframe (url, name) > {const iframe document.createElement(iframe);iframe.style.display none; // 防止影响页面iframe.style.height 0; // 防止影响页面iframe.name name;iframe.src url;document.body.appendChild(iframe); // 这…...
高性能、可扩展、支持二次开发的企业电子招标采购系统源码
在数字化时代,企业需要借助先进的数字化技术来提高工程管理效率和质量。招投标管理系统作为企业内部业务项目管理的重要应用平台,涵盖了门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理等…...
2645. 构造有效字符串的最少插入数
Problem: 2645. 构造有效字符串的最少插入数 文章目录 解题思路解决方法复杂度分析代码实现 解题思路 解决此问题需要确定如何以最小的插入次数构造一个有效的字符串。首先,我们需要确定开头的差距,然后决定中间的补足,最后决定末尾的差距。…...
C#,快速排序算法(Quick Sort)的非递归实现与数据可视化
排序算法是编程的基础。 常见的四种排序算法是:简单选择排序、冒泡排序、插入排序和快速排序。其中的快速排序的优势明显,一般使用递归方式实现,但遇到数据量大的情况则无法适用。实际工程中一般使用“非递归”方式实现。 快速排序(Quick Sor…...
【操作系统xv6】学习记录2 -RISC-V Architecture
说明:看完这节,不会让你称为汇编程序员,知识操作系统的前置。 ref:https://binhack.readthedocs.io/zh/latest/assembly/mips.html https://www.bilibili.com/video/BV1w94y1a7i8/?p7 MIPS MIPS的意思是 “无内部互锁流水级的微…...
C++力扣题目111--二叉树的最小深度
力扣题目链接(opens new window) 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7], 返回它的最小深度 2 思路 看完了这篇104.二…...
【图像拼接】源码精读:Adaptive As-Natural-As-Possible Image Stitching(AANAP/ANAP)
第一次来请先看这篇文章:【图像拼接(Image Stitching)】关于【图像拼接论文源码精读】专栏的相关说明,包含专栏内文章结构说明、源码阅读顺序、培养代码能力、如何创新等(不定期更新) 【图像拼接论文源码精读】专栏文章目录 【源码精读】As-Projective-As-Possible Imag…...
解决docker run报错:Error response from daemon: No command specified.
将docker镜像export/import之后,对新的镜像执行docker run时报错: docker: Error response from daemon: No command specified. 解决方法: 方案1: 查看容器的command: docker ps --no-trunc 在docker run命令上增加…...
算法第十二天-最大整除子集
最大整除子集 题目要求 解题思路 来自[宫水三叶] 根据题意:对于符合要求的[整除子集]中的任意两个值,必然满足[较大数]是[较小数]的倍数 数据范围是 1 0 3 10^3 103,我们不可能采取获取所有子集,再检查子集是否合法的暴力搜解法…...
简单易懂的PyTorch 损失函数:优化机器学习模型的关键
目录 torch.nn子模块Loss Functions详解 nn.L1Loss 用途 用法 使用技巧 注意事项 代码示例 nn.MSELoss 用途 用法 使用技巧 注意事项 代码示例 nn.CrossEntropyLoss 用途 用法 使用技巧 注意事项 代码示例 使用类别索引 使用类别概率 nn.CTCLoss 用途 …...
Kubernetes/k8s的存储卷/数据卷
k8s的存储卷/数据卷 容器内的目录和宿主机的目录挂载 容器在系统上的生命周期是短暂的,delete,k8s用控制创建的pod,delete相当于重启,容器的状态也会回复到初始状态 一旦回到初始状态,所有的后天编辑的文件都会消失…...
【漏洞复现】锐捷RG-UAC统一上网行为管理系统信息泄露漏洞
Nx01 产品简介 锐捷网络成立于2000年1月,原名实达网络,2003年更名,自成立以来,一直扎根行业,深入场景进行解决方案设计和创新,并利用云计算、SDN、移动互联、大数据、物联网、AI等新技术为各行业用户提供场…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
【Ftrace 专栏】Ftrace 参考博文
ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...
