CUDA小白 - NPP(3) 图像处理 Color and Sampling Conversion
cuda小白
原始API链接 NPP
GPU架构近些年也有不少的变化,具体的可以参考别的博主的介绍,都比较详细。还有一些cuda中的专有名词的含义,可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》
常见的NppStatus,可以看这里。
如有问题,请指出,谢谢
本节内容主要涉及到使用NPP进行一些图像色域变换等,类似功能的就不细说,仅针对一些常见的。由于Debayer,不同yuv之间的转换(Color Sampling Format Conversion),Gamma校正,Complement Color Key(一直不清楚这个啥)以及Color Processing(调色相关)的接触不对,后面就不介绍了,按需。
Color Model Conversion
当前模块主要涉及到的RGB,BGR,YUV,YUV420,YUV422,NV12,YCbCr,YCbCr422和YCbCr420之间的相互转换,以及批处理(分为同样ROI和不同ROI两个接口)的接口。其他还有一些未接触过的XYZ,LUV,Lab,YCC,CMYK_JPEG,HLS,HSV等与RGB或者BGR之间的转换。
本文就那比较简单的转换,以为RGB和YUV之间的相互转换为例子。
// 此处介绍的RGB和YUV都是三通道的,如果是packed的相互转换,则后缀是C3R,如果都是planar的,则后缀是P3R,反之则是P3C3R或者C3P3R。
// =========== RGB2YUV原理 ===========
// Npp32f nY = 0.299F * R + 0.587F * G + 0.114F * B;
// Npp32f nU = (0.492F * ((Npp32f)nB - nY)) + 128.0F;
// Npp32f nV = (0.877F * ((Npp32f)nR - nY)) + 128.0F;
// if (nV > 255.0F)
// nV = 255.0F;
NppStatus nppiRGBToYUV_8u_C3R(const Npp8u *pSrc,int nSrcStep,Npp8u *pDst,int nDstStep,NppiSize oSizeROI);// =========== RGB2YUV原理 ===========
// Npp32f nY = (Npp32f)Y;
// Npp32f nU = (Npp32f)U - 128.0F;
// Npp32f nV = (Npp32f)V - 128.0F;
// Npp32f nR = nY + 1.140F * nV;
// if (nR < 0.0F) nR = 0.0F;
// if (nR > 255.0F) nR = 255.0F;
// Npp32f nG = nY - 0.394F * nU - 0.581F * nV;
// if (nG < 0.0F) nG = 0.0F;
// if (nG > 255.0F) nG = 255.0F;
// Npp32f nB = nY + 2.032F * nU;
// if (nB < 0.0F) nB = 0.0F;
// if (nB > 255.0F) nB = 255.0F;
NppStatus nppiYUVToRGB_8u_C3R(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");int image_width = image_dog.cols;int image_height = image_dog.rows;int image_size = image_width * image_height * 3;// =============== device memory ===============uint8_t *in_ptr, *yuv, *out_ptr;cudaMalloc((void**)&in_ptr, image_size * sizeof(uint8_t));cudaMalloc((void**)&yuv, image_size * sizeof(uint8_t));cudaMalloc((void**)&out_ptr, image_size * sizeof(uint8_t));cudaMemcpy(in_ptr, image_dog.data, image_size, cudaMemcpyHostToDevice);NppiSize roi1, roi2;roi1.width = image_width;roi1.height = image_height;roi2.width = image_width / 2;roi2.height = image_height / 2;// =============== nppiRGBToYUV_8u_C3R ===============uint8_t *host_yuv = (uint8_t *)malloc(image_size);NppStatus status;status = nppiRGBToYUV_8u_C3R(in_ptr, image_width * 3, yuv, image_width * 3, roi1);if (status != NPP_SUCCESS) {std::cout << "[GPU] ERROR nppiRGBToYUV_8u_C3R failed, status = " << status << std::endl;return false;}cudaMemcpy(host_yuv, yuv, image_size, cudaMemcpyDeviceToHost);std::string out_yuv_file = directory + "yuv.bin";FILE *fp = fopen(out_yuv_file.c_str(), "wb");fwrite(host_yuv, image_size, 1, fp);fclose(fp);// =============== nppiYUVToRGB_8u_C3R ===============cv::Mat out_image = cv::Mat::zeros(image_height, image_width, CV_8UC3);status = nppiYUVToRGB_8u_C3R(yuv, image_width * 3, out_ptr, image_width * 3, roi2);if (status != NPP_SUCCESS) {std::cout << "[GPU] ERROR nppiYUVToRGB_8u_C3R failed, status = " << status << std::endl;return false;}cudaMemcpy(out_image.data, out_ptr, image_size, cudaMemcpyDeviceToHost);cv::imwrite(directory + "out_rgb.jpg", out_image);// freeCUDA_FREE(in_ptr)CUDA_FREE(yuv)CUDA_FREE(out_ptr)if (host_yuv != nullptr) { free(host_yuv); host_yuv = nullptr; }
}
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
yuv的结果,使用7yuv工具查看

使用转换之后的yuv,再转回RGB,在限定ROI之后的结果:

注意点:
- 可以使用7yuv进行yuv图像的查看,7yuv,下载对应的版本即可,可以体验。
- 还有一个接口是基于JPEG的,主要介绍的是JPEG的Color Conversion,由于平时接触较少,这里暂时不介绍了,按需取《JPEG Color Conversion》.
ColorToGray Conversion
当前模块也主要分为三个大方向:RGBToGray,ColorToGray和GradientColorToGray。三个大方向都只选取一个比较常见的进行介绍:
// nGray = 0.299F * R + 0.587F * G + 0.114F * B;
NppStatus nppiRGBToGray_8u_C3C1R(const Npp8u *pSrc,int nSrcStep,Npp8u *pDst,int nDstStep,NppiSize oSizeROI);
// nGray = aCoeffs[0] * R + aCoeffs[1] * G + aCoeffs[2] * B;
NppStatus nppiColorToGray_8u_C3C1R(const Npp8u *pSrc,int nSrcStep,Npp8u *pDst,int nDstStep,NppiSize oSizeROI,const Npp32f aCoeffs[3]);
// NppiNorm { max(inf) / sum(L1) / square root of sum of squares(L2) }
NppStatus nppiGradientColorToGray_8u_C3C1R(const Npp8u *pSrc,int nSrcStep,Npp8u *pDst,int nDstStep,NppiSize oSizeROI,NppiNorm eNorm);
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::cvtColor(image_dog, image_dog, CV_RGB2BGR);int image_width = image_dog.cols;int image_height = image_dog.rows;int image_size = image_width * image_height;// =============== device memory ===============uint8_t *in_ptr;cudaMalloc((void**)&in_ptr, image_size * 3 * sizeof(uint8_t));cudaMemcpy(in_ptr, image_dog.data, image_size * 3 * sizeof(uint8_t), cudaMemcpyHostToDevice);uint8_t *out_ptr1, *out_ptr2, *out_ptr3;cudaMalloc((void**)&out_ptr1, image_size * sizeof(uint8_t));cudaMalloc((void**)&out_ptr2, image_size * sizeof(uint8_t));cudaMalloc((void**)&out_ptr3, image_size * sizeof(uint8_t));NppiSize roi1, roi2;roi1.width = image_width;roi1.height = image_height;roi2.width = image_width / 2;roi2.height = image_height / 2;// =============== nppiRGBToGray_8u_C3C1R ===============cv::Mat out_image_gray = cv::Mat::zeros(image_height, image_width, CV_8UC1);NppStatus status;status = nppiRGBToGray_8u_C3C1R(in_ptr, image_width * 3, out_ptr1, image_width, roi1);if (status != NPP_SUCCESS) {std::cout << "[GPU] ERROR nppiRGBToGray_8u_C3C1R failed, status = " << status << std::endl;return false;}cudaMemcpy(out_image_gray.data, out_ptr1, image_size, cudaMemcpyDeviceToHost);cv::imwrite(directory + "rgb2gray.jpg", out_image_gray);// =============== nppiColorToGray_8u_C3C1R ===============float coeffs[3] = { 0.1f, 0.8f, 0.1f};status = nppiColorToGray_8u_C3C1R(in_ptr, image_width * 3, out_ptr2, image_width, roi1, coeffs);if (status != NPP_SUCCESS) {std::cout << "[GPU] ERROR nppiColorToGray_8u_C3C1R failed, status = " << status << std::endl;return false;}cudaMemcpy(out_image_gray.data, out_ptr2, image_size, cudaMemcpyDeviceToHost);cv::imwrite(directory + "color2rgb.jpg", out_image_gray);// =============== nppiGradientColorToGray_8u_C3C1R_Ctx ===============status = nppiGradientColorToGray_8u_C3C1R(in_ptr, image_width * 3, out_ptr3, image_width, roi1, nppiNormInf);if (status != NPP_SUCCESS) {std::cout << "[GPU] ERROR nppiGradientColorToGray_8u_C3C1R failed, status = " << status << std::endl;return false;}cudaMemcpy(out_image_gray.data, out_ptr3, image_size, cudaMemcpyDeviceToHost);cv::imwrite(directory + "gradient.jpg", out_image_gray);// freeCUDA_FREE(in_ptr)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

注意点:
- Color2Gray的接口与RGB2Gray的区别主要在于三个通道是不是比例关系。由于都是灰度图的,ColorGray的变化与直接rgb的转换结果差异性不易从肉眼看出来,但是通过不同的比例组合明显看出图像是有区别的。
相关文章:
CUDA小白 - NPP(3) 图像处理 Color and Sampling Conversion
cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化,具体的可以参考别的博主的介绍,都比较详细。还有一些cuda中的专有名词的含义,可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus…...
Android硬件通信之 串口通信
一,串口介绍 1.1 串口简介 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口; 串行接口(SerialInterface)是指数据一位一位地顺序…...
高防服务器面对DDOS攻击的威胁有何必要性
高防服务器面对DDOS攻击的威胁有何必要性?分布式拒绝服务(DDoS)攻击是一种常见而危险的网络攻击形式,它可以使目标网络服务器过载,导致服务不可用。本文将深入探讨DDoS攻击的威胁,以及高防服务器在抵御这种…...
VBA中如何将if写到一行
在VBA中,可以使用以下两种方式来编写一行if语句: 使用三元运算符: Dim result As String result "Yes" If True Else "No"在这个例子中,如果条件为真,则result变量的值为"Yes"&#…...
性能测试,python 内存分析工具 -memray
Memray是一个由彭博社开发的、开源内存剖析器;开源一个多月,已经收获了超8.4k的star,是名副其实的明星项目。今天我们就给大家来推荐这款python内存分析神器。 Memray可以跟踪python代码、本机扩展模块和python解释器本身中内存分配…...
Jmeter(二十八):beanshell的使用
Beanshell 是一种轻量级的 Java 脚本,纯 Java 编写的,能够动态的执行标准 java 语法及一些扩展脚本语法,类似于 javaScript,在工作中可能用的多的就是: Beanshell 取样器:跟Http取样器并列Beanshell前置处理器:一般放在Http请求下,在请求前处理一些数据Beanshell后置处…...
数学建模:层次分析法
🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 层次分析法 步骤描述 将问题条理化,层次化,构建出一个有层次的结构模型。层次分为三类:目标层,准则(指标)层,方案层。比…...
POI-TL制作word
本文相当于笔记,主要根据官方文档Poi-tl Documentation和poi-tl的使用(最全详解)_JavaSupeMan的博客-CSDN博客文章进行学习(上班够用) Data AllArgsConstructor NoArgsConstructor ToString EqualsAndHashCode public …...
大数据Flink(七十一):SQL的时间属性
文章目录 SQL的时间属性 一、Flink三种时间属性简介...
51单片机项目(7)——基于51单片机的温湿度测量仿真
本次做的设计,是利用DHT11传感器,测量环境的温度以及湿度,同时具备温度报警的功能:利用两个按键,设置温度阈值的加和减,当所测温度大于温度阈值的时候,蜂鸣器就会响起,进行报警提示。…...
按钮控件之1---QPushButton 标准按钮/普通按钮控件
1、父类QAbstractButton 2、QPushButton按钮,是Qt常用的控件之一,提供普通的按钮功能。 通过信号槽机制接收触发信号并执行对应动作。3、创建QPushButton 它有三个构造函数: // 空对象 QPushButton(QWidget *parent nullptr); // 指定QPus…...
Ae 效果:CC Light Rays
生成/CC Light Rays Generate/CC Light Rays CC Light Rays(CC 光线)可以创建从光源发出并能穿过图层内容的光线效果。常用于制作光线透过门窗或云层的场景,或者用于创建神奇或梦幻的氛围感。 本效果会被限制在源图层的大小范围之内。 ◆ ◆…...
MPI之通信模式(标准,缓存,同步,就绪)
MPI缓冲区 由MPI自行维护的一块内存区域,也可由用户(MPI_Bsend)自行维护;发送方 维护一块发送缓冲区; 接收方 维护一块接收缓冲区。 数据收发过程: 当发送端将数据拷贝到自身的数据缓冲区后(注意这里是拷贝,即数据到…...
面试官:说一下 MyBatis 的一级缓存和二级缓存 ?
目录 1. MyBatis 的缓存机制 2. 为什么不默认开启 MyBatis 的二级缓存 3. MyBatis 如何开启二级缓存 4. MyBatis 有哪些缓存清除策略 1. MyBatis 的缓存机制 MyBayis 中包含两级缓存:一级缓存和二级缓存 1. 一级缓存是 SqlSession 级别的,是 MyBati…...
Ajax与jQuery
目录 Ajax是一种异步无刷新的技术 Ajax的优点: 可以无需刷新页面与服务器端进行通信允许根据用户事件来更新部分页面内容 Ajax的缺点: 没有浏览历史,不能回退存在跨域问题(同源)SEO(搜索引擎优化&#x…...
色温曲线坐标轴的选取:G/R、G/B还是R/G、B/G ?
海思色温曲线坐标 Mstar色温曲线坐标 高通色温曲线坐标 联咏色温曲线坐标 查看各家白平衡调试界面,比如海思、Mstart、高通等调试资料,白平衡模块都是以R/G B/G作为坐标系的两个坐标轴,也有方案是以G/R G/B作为坐标系的两个坐标轴。 以G/R G…...
maven部署
一、下载Maven 地址:Maven – Download Apache Maven 二、解压缩,设置环境变量 tar -xvf apache-maven-3.8.8-bin.tar.gz export MAVEN_HOME/opt/apache-maven-3.8.8 export PATH$MAVEN_HOME/bin:$PATH echo $MAVEN_HOME echo $PATH mvn -v...
docker进阶作业
一、使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。 安装Docker:确保已在CentOS 7.5上安装了Docker。 拉取MySQL 5.6镜像:使用以下命令从Docker Hub上拉取MySQL 5.6镜像。 docker pull mysql:5.6 运行MySQL容器:使用以下命令…...
HTML+JavaScript+CSS DIY 分隔条splitter
一、需求分析 现在电脑的屏幕越来越大,为了利用好宽屏,我们在设计系统UI时喜欢在左侧放个菜单或选项面板,在右边显示与菜单或选项对应的内容,两者之间用分隔条splitter来间隔,并可以通过拖动分隔条splitter来动态调研…...
Oracle-day5:新增、复制建表、表结构、表数据、删除
目录 一、insert新增数据 二、复制建表 三、表结构修改 四、查看表结构、表数据处理 五、修改表数据 六、删除语句 八、练习题 一、insert新增数据 /* ---------- 一、DML 数据操作语言-------- -- 1、增加数据 insert 语法:insert into 表名 (列1,列2,…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
动态规划-1035.不相交的线-力扣(LeetCode)
一、题目解析 光看题目要求和例图,感觉这题好麻烦,直线不能相交啊,每个数字只属于一条连线啊等等,但我们结合题目所给的信息和例图的内容,这不就是最长公共子序列吗?,我们把最长公共子序列连线起…...
