CUDA小白 - NPP(4) 图像处理 Data Exchange and Initialization(1)

news2025/4/7 16:00:39

cuda小白
原始API链接 NPP

GPU架构近些年也有不少的变化,具体的可以参考别的博主的介绍,都比较详细。还有一些cuda中的专有名词的含义,可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》

常见的NppStatus,可以看这里。

如有问题,请指出,谢谢

Image Set Operations

当前模块主要功能是set图像中的像素值,主要分为三个大类:将ROI区域内的所有像素设置为一个特殊的值(Set),mask赋值(Masked Set),以及单通道赋值(Channel Set)。
三个大类分别以一个三通道的uint8_t为例子简单介绍一下。

// ROI区域内的三通道设置为aValue
NppStatus nppiSet_8u_C3R(const Npp8u aValue[3],
					 	 Npp8u *pDst,
						 int nDstStep,
						 NppiSize oSizeROI);
// 通过mask控制ROI区域内的那些像素会被set
NppStatus nppiSet_8u_C3MR(const Npp8u aValue[3],
						  Npp8u *pDst,
						  int nDstStep,
						  NppiSize oSizeROI,
						  const Npp8u *pMask,
						  int nMaskStep);	
// 通过pointer的起始位置区别,选择某通道设置为固定值
NppStatus nppiSet_8u_C3CR(Npp8u nValue,
						  Npp8u *pDst,
						  int nDstStep,
						  NppiSize oSizeROI);
code
#include <iostream>
#include <cuda_runtime.h>
#include <npp.h>
#include <opencv2/opencv.hpp>

#define CUDA_FREE(ptr) { if (ptr != nullptr) { cudaFree(ptr); ptr = nullptr; } }

int main() {
  std::string directory = "../";

  // =============== load image ===============
  cv::Mat image_dog = cv::imread(directory + "dog.png");
  int image_width = image_dog.cols;
  int image_height = image_dog.rows;
  int image_size = image_width * image_height;

  // =============== device memory ===============
  uint8_t *out_ptr1, *out_ptr2, *out_ptr3;
  cudaMalloc((void**)&out_ptr1, image_size * 3 * sizeof(uint8_t));
  cudaMalloc((void**)&out_ptr2, image_size * 3 * sizeof(uint8_t));
  cudaMalloc((void**)&out_ptr3, image_size * 3 * sizeof(uint8_t));
  cudaMemcpy(out_ptr1, image_dog.data, image_size * 3 * sizeof(uint8_t), cudaMemcpyHostToDevice);
  cudaMemcpy(out_ptr2, image_dog.data, image_size * 3 * sizeof(uint8_t), cudaMemcpyHostToDevice);
  cudaMemcpy(out_ptr3, image_dog.data, image_size * 3 * sizeof(uint8_t), cudaMemcpyHostToDevice);

  cv::Mat mask = cv::Mat::zeros(image_height, image_width, CV_8UC1);
  cv::Mat mask1 = cv::Mat::ones(image_height * 3 / 4, image_width * 3 / 4, CV_8UC1);
  cv::Rect rc1 = cv::Rect(image_width / 4, image_height / 4, image_width * 3 / 4, image_height * 3 / 4);
  mask1.copyTo(mask(rc1));

  uint8_t *gpu_mask;
  cudaMalloc((void**)&gpu_mask, image_size * sizeof(uint8_t));
  cudaMemcpy(gpu_mask, mask.data, image_size * sizeof(uint8_t), cudaMemcpyHostToDevice);

  NppiSize roi1, roi2;
  roi1.width = image_width;
  roi1.height = image_height;
  roi2.width = image_width / 2;
  roi2.height = image_height / 2;

  cv::Mat out_image = cv::Mat::zeros(image_height, image_width, CV_8UC3);
  NppStatus status;
  // =============== nppiSet_8u_C3R ===============
  uint8_t value[3] = { 255, 0, 0 };
  status = nppiSet_8u_C3R(value, out_ptr1, image_width * 3, roi1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiSet_8u_C3R failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr1, image_size * 3, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "set.jpg", out_image);

  // =============== nppiSet_8u_C3R ===============
  uint8_t value2[3] = { 0, 0, 255 };
  status = nppiSet_8u_C3MR(value2, out_ptr2, image_width * 3, roi1, gpu_mask, image_width);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiSet_8u_C3MR failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr2, image_size * 3, cudaMemcpyD![请添加图片描述](https://img-blog.csdnimg.cn/9da721ce7d4649839ef40228bb3937e1.png)
eviceToHost);
  cv::imwrite(directory + "set_mask.jpg", out_image);
  
  // green
  status = nppiSet_8u_C3CR(255, out_ptr3 + image_width * 3 * 200 + 1, image_width * 3, roi1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiSet_8u_C3CR failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr3, image_size * 3, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "set_channel.jpg", out_image);


  // free
  CUDA_FREE(out_ptr1)
  CUDA_FREE(out_ptr2)
  CUDA_FREE(out_ptr3)
}
make
cmake_minimum_required(VERSION 3.20)
project(test)

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

find_package(CUDA REQUIRED)
include_directories(${CUDA_INCLUDE_DIRS})
file(GLOB CUDA_LIBS "/usr/local/cuda/lib64/*.so")

add_executable(test test.cpp)
target_link_libraries(test
                      ${OpenCV_LIBS}
                      ${CUDA_LIBS}
)
result

请添加图片描述
注意:

  1. mask使用的是单通道的,仅表示那些像素需要进行set,那些不需要
  2. 通道的set,通过指针来表示是针对那个通道进行转换。输入指针表示开始set的起始位置,对于三通道的图像而言,则是隔两个set一次。

Image Copy Operations

除了比较常见的copy操作(copy,masked copy,channel copy)之外,还有一些planar和packed之间的来回拷贝,拷贝的同时伴随着border,以及Copy Sub-pixel(没接触过)

// 单纯的拷贝
NppStatus nppiCopy_8u_C3R(const Npp8u *pSrc,
						  int nSrcStep,
						  Npp8u *pDst,
						  int nDstStep,
						  NppiSize oSizeROI);	
// 依据mask有选择性的进行拷贝
NppStatus nppiCopy_8u_C3MR(const Npp8u *pSrc,
						   int nSrcStep,
						   Npp8u *pDst,
						   int nDstStep,
						   NppiSize oSizeROI,
						   const Npp8u *pMask,
						   int nMaskStep);	
// Channel Copy, 将一个多通道的某个通道拷贝到另外一个多通道图像的某一个channel
NppStatus nppiCopy_8u_C3CR(const Npp8u *pSrc,
						   int nSrcStep,
						   Npp8u *pDst,
						   int nDstStep,
						   NppiSize oSizeROI);	
// Extract Channel Copy, 将一个多通道的某个通道拷贝到另外一个单通道的图像
NppStatus nppiCopy_8u_C3C1R(const Npp8u * pSrc,
						    int nSrcStep,
							Npp8u *pDst,
							int nDstStep,
							NppiSize oSizeROI);	
// Insert Channel Copy, 一个单通道的图像拷贝到多通道中的某一个通道
NppStatus nppiCopy_8u_C1C3R(const Npp8u * pSrc,
							int nSrcStep,
							Npp8u * pDst,
							int nDstStep,
							NppiSize oSizeROI);
// 剩下的接口平时接触较少,所以暂时不做详细介绍
code
#include <iostream>
#include <cuda_runtime.h>
#include <npp.h>
#include <opencv2/opencv.hpp>

#define CUDA_FREE(ptr) { if (ptr != nullptr) { cudaFree(ptr); ptr = nullptr; } }

int main() {
  std::string directory = "../";

  // =============== load image ===============
  cv::Mat image_dog = cv::imread(directory + "dog.png");
  cv::Mat image_dog_gray;
  cv::cvtColor(image_dog, image_dog_gray, CV_RGB2GRAY);

  int image_width = image_dog.cols;
  int image_height = image_dog.rows;
  int image_size = image_width * image_height;

  // =============== device memory ===============
  uint8_t *in_image, *in_img_gray;
  cudaMalloc((void**)&in_image, image_size * 3 * sizeof(uint8_t));
  cudaMalloc((void**)&in_img_gray, image_size * sizeof(uint8_t));
  cudaMemcpy(in_image, image_dog.data, image_size * 3 * sizeof(uint8_t), cudaMemcpyHostToDevice);
  cudaMemcpy(in_img_gray, image_dog_gray.data, image_size * sizeof(uint8_t), cudaMemcpyHostToDevice);

  uint8_t *out_ptr1, *out_ptr2, *out_ptr3, *out_ptr4, *out_ptr5;
  cudaMalloc((void**)&out_ptr1, image_size * 3 * sizeof(uint8_t));  // 三通道
  cudaMalloc((void**)&out_ptr2, image_size * 3 * sizeof(uint8_t));  // 三通道
  cudaMalloc((void**)&out_ptr3, image_size * 3 * sizeof(uint8_t));  // 三通道
  cudaMalloc((void**)&out_ptr4, image_size * sizeof(uint8_t));  // 单通道
  cudaMalloc((void**)&out_ptr5, image_size * 3 * sizeof(uint8_t));  // 三通道

  // mask
  cv::Mat mask = cv::Mat::zeros(image_height, image_width, CV_8UC1);
  cv::Mat mask1 = cv::Mat::ones(image_height * 3 / 4, image_width * 3 / 4, CV_8UC1);
  cv::Rect rc1 = cv::Rect(image_width / 4, image_height / 4, image_width * 3 / 4, image_height * 3 / 4);
  mask1.copyTo(mask(rc1));

  uint8_t *gpu_mask;
  cudaMalloc((void**)&gpu_mask, image_size * sizeof(uint8_t));
  cudaMemcpy(gpu_mask, mask.data, image_size * sizeof(uint8_t), cudaMemcpyHostToDevice);

  NppiSize roi1, roi2;
  roi1.width = image_width;
  roi1.height = image_height;
  roi2.width = image_width / 2;
  roi2.height = image_height / 2;

  cv::Mat out_image = cv::Mat::zeros(image_height, image_width, CV_8UC3);
  cv::Mat out_single = cv::Mat::zeros(image_height, image_width, CV_8UC1);
  NppStatus status;
  // =============== nppiCopy_8u_C3R ===============
  status = nppiCopy_8u_C3R(in_image, image_width * 3, out_ptr1, image_width * 3, roi1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiCopy_8u_C3R failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr1, image_size * 3, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "copy.jpg", out_image);

  // =============== nppiCopy_8u_C3MR ===============
  status = nppiCopy_8u_C3MR(in_image, image_width * 3, out_ptr2, image_width * 3, roi1, gpu_mask, image_width);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiCopy_8u_C3MR failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr2, image_size * 3, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "copy_mask.jpg", out_image);
  
  // =============== nppiCopy_8u_C3CR ===============
  status = nppiCopy_8u_C3CR(in_image, image_width * 3, out_ptr3, image_width * 3, roi1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiCopy_8u_C3CR failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr3, image_size * 3, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "copy_channel.jpg", out_image);

  // =============== nppiCopy_8u_C3C1R ===============
  status = nppiCopy_8u_C3C1R(in_image, image_width * 3, out_ptr4, image_width, roi1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiCopy_8u_C3C1R failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_single.data, out_ptr4, image_size, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "copy_channel_extract.jpg", out_single);

  // =============== nppiCopy_8u_C1C3R ===============
  status = nppiCopy_8u_C1C3R(in_img_gray, image_width, out_ptr5, image_width * 3, roi1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiCopy_8u_C1C3R failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr5, image_size * 3, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "copy_channel_insert.jpg", out_image);

  // free
  CUDA_FREE(in_image)
  CUDA_FREE(in_img_gray)
  CUDA_FREE(out_ptr1)
  CUDA_FREE(out_ptr2)
  CUDA_FREE(out_ptr3)
  CUDA_FREE(out_ptr4)
  CUDA_FREE(out_ptr5)
}
make
cmake_minimum_required(VERSION 3.20)
project(test)

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

find_package(CUDA REQUIRED)
include_directories(${CUDA_INCLUDE_DIRS})
file(GLOB CUDA_LIBS "/usr/local/cuda/lib64/*.so")

add_executable(test test.cpp)
target_link_libraries(test
                      ${OpenCV_LIBS}
                      ${CUDA_LIBS}
)
result

请添加图片描述
注意:

  1. 由于提取三个通道进行copy,存图的时候只有单个通道,因此呈现出来的结果是灰色的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/981327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT 初识多线程

1.QThread线程基础 QThread是Qt线程中有一个公共的抽象类&#xff0c;所有的线程类都是从QThread抽象类中派生的&#xff0c;需要实现QThread中的虚函数run(),通过start()函数来调用run函数。 void run&#xff08;&#xff09;函数是线程体函数&#xff0c;用于定义线程的功能…

借助CIFAR10模型结构理解卷积神经网络及Sequential的使用

CIFAR10模型搭建 CIFAR10模型结构 0. input : 332x32&#xff0c;3通道32x32的图片 --> 特征图(Feature maps) : 3232x32即经过32个35x5的卷积层&#xff0c;输出尺寸没有变化&#xff08;有x个特征图即有x个卷积核。卷积核的通道数与输入的通道数相等&#xff0c;即35x5&am…

01-从JDK源码级别剖析JVM类加载机制

1. 类加载运行全过程 当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把主类加载到JVM。 public class Math {public static final int initData 666;public static User user new User();public int compute() { //一个方法对应一块栈帧…

整理mongodb文档:事务(一)

个人博客 整理mongodb文档:事务(一) 原文链接&#xff0c;个人博客 求关注&#xff0c;本文主要讲下怎么在mongose下使用事务&#xff0c;建议电脑端看 文章概叙 本文的开发环境为Nodejs&#xff0c;在‘单机模式’讲解最基本的事务概念。并没有涉及分片以及集群&#xff0…

《向量数据库指南》——AI原生向量数据库Milvus Cloud 2.3新功能

New Feature Upsert 功能 支持用户通过 upsert 接口更新或插入数据。已知限制,自增 id 不支持 upsert;upsert 是内部实现是 delete + insert所以性能上会有一定损耗,如果明确知道是写入数据的场景请继续使用 insert。 Range Search 功能 支持用户通过输入参数指定 search 的…

TortoiseGit设置作者信息和用户名、密码存储

前言 Git 客户端每次与服务器交互&#xff0c;都需要输入密码&#xff0c;但是我们可以配置保存密码&#xff0c;只需要输入一次&#xff0c;就不再需要输入密码。 操作说明 在任意文件夹下&#xff0c;空白处&#xff0c;鼠标右键点击 在弹出菜单中按照下图点击 依次点击下…

LLVM 与代码混淆技术

项目源码 什么是 LLVM LLVM 计划启动于2000年&#xff0c;开始由美国 UIUC 大学的 Chris Lattner 博士主持开展&#xff0c;后来 Apple 也加入其中。最初的目的是开发一套提供中间代码和编译基础设施的虚拟系统。 LLVM 命名最早源自于底层虚拟机&#xff08;Low Level Virtu…

LEARN GIT

概念 基础概念 本地电脑 代码区&#xff1a;工作区间&#xff0c;放代码的地方 暂存区&#xff1a;git所管理的暂存区域 本地仓库&#xff1a;git所管理的本机的硬盘区域 远程电脑 远程仓库&#xff1a;github、gitee 代码提交管理的过程 代码区------->暂存区-------&…

关于 RK3568的linux系统killed用户应用进程(用户现象为崩溃) 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/132710642 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

模拟Proactor模式实现 I/O 处理单元

编写main.cpp 1.socket通信 服务器应用程序可以通过读取和写入 Socket 对象 来监听来自客户端的请求并向客户端返回响应 #define MAX_FD 65536 // 最大的文件描述符个数 #define MAX_EVENT_NUMBER 10000 // 监听的最大的事件数量 // 添加信号捕捉 void addsig(int sig, …

【MySQL】索引 详解

索引 详解 一. 概念二. 作用三. 使用场景四. 操作五. 索引背后的数据结构B-树B树聚簇索引与非聚簇索引 一. 概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各…

机器学习的特征工程

字典特征提取 def dict_demo():"""字典特征提取:return:"""data [{city: 北京, temperature: 100}, {city: 上海, temperature: 60}, {city: 深圳, temperature: 30}]# data [{city:[北京,上海,深圳]},{temperature:["100","6…

《机器人学一(Robotics(1))》_台大林沛群 第 5 周【机械手臂 轨迹规划】 Quiz 5

我又行了&#xff01;&#x1f923; 求解的 位置 可能会有 变动&#xff0c;根据求得的A填写相应值即可。注意看题目。 coursera链接 文章目录 第1题 Cartesian space求解 题1-3 的 Python 代码 第2题第3题第4题 Joint space求解 题4-6 的 Python 代码 第5题第6题其它可参考代…

leetcode 88:合并两个有序数组 。 双指针解法

题目 算法 双指针 code var merge function(nums1, m, nums2, n) {// 其实就是一个nums1数组从后向前的降序重排&#xff0c;从最后开始&#xff0c;比较nums1有效位置和nums2当前位置数的大小&#xff0c;依次填入&#xff0c;nums2最后若有剩余&#xff0c;则再多一步从后…

9、补充视频

改进后的dijkstra算法 利用小根堆 将小根堆特定位置更改,再改成小根堆 nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight + distance);//改进后的dijkstra算法 //从head出发,所有head能到达的节点,生成到达每个节点的最小路径记录并返回 public static HashMap<No…

Bytebase 和 GitLab 签署 Technology Partner 技术合作伙伴协议

Bytebase 和 GitLab 签署技术合作伙伴协议&#xff0c;携手为开发者提供流畅的数据库协作开发和管理体验。 GitLab 是世界领先的开源 AI 驱动 DevSecOps 平台&#xff0c;旨在帮助开发者团队更好协作、更高效交付软件。Bytebase 是一款为 DevOps 团队准备的数据库 CI/CD 工具&a…

一文讲解Linux内核内存管理架构

内存管理子系统可能是linux内核中最为复杂的一个子系统&#xff0c;其支持的功能需求众多&#xff0c;如页面映射、页面分配、页面回收、页面交换、冷热页面、紧急页面、页面碎片管理、页面缓存、页面统计等&#xff0c;而且对性能也有很高的要求。本文从内存管理硬件架构、地址…

上海控安携汽车网络安全新研产品出席AUTOSEMO“恒以致远,共创共赢”主题研讨会

8月31日&#xff0c;AUTOSEMO“恒以致远&#xff0c;共创共赢”主题研讨会在天津成功召开。本次大会由中国汽车工业协会软件分会中国汽车基础软件生态标委会&#xff08;简称&#xff1a;AUTOSEMO&#xff09;与天津市西青区人民政府联合主办。现场汇聚了100余位来自产学研政企…

单片机-LED介绍

简介 LED 即发光二极管。它具有单向导电性&#xff0c;通过 5mA 左右电流即可发光 电流 越大&#xff0c;其亮度越强&#xff0c;但若电流过大&#xff0c;会烧毁二极管&#xff0c;一般我们控制在 3 mA-20mA 之间&#xff0c;通常我们会在 LED 管脚上串联一个电阻&#xff0c…

unity 控制Dropdown的Arrow箭头变化

Dropdown打开下拉菜单会以“Template”为模板创建一个Dropdown List&#xff0c;在“Template”上添加一个脚本在Start()中执行下拉框打开时的操作&#xff0c;在OnDestroy()中执行下拉框收起时的操作即可。 效果代码如下用于控制Arrow旋转可以根据自己的想法进行修改&#xff…