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之后的结果:
请添加图片描述
注意点:

  1. 可以使用7yuv进行yuv图像的查看,7yuv,下载对应的版本即可,可以体验。
  2. 还有一个接口是基于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

请添加图片描述
注意点:

  1. Color2Gray的接口与RGB2Gray的区别主要在于三个通道是不是比例关系。由于都是灰度图的,ColorGray的变化与直接rgb的转换结果差异性不易从肉眼看出来,但是通过不同的比例组合明显看出图像是有区别的。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot:时间格式化的5种方法(解决后端传给前端的时间格式转换问题)推荐使用第4和第5种!

本文转载自&#xff1a;springboot&#xff1a;时间格式化的5种方法&#xff08;解决后端传给前端的时间显示不一致&#xff09;_为什么前端格式化日期了后端还要格式化_洛泞的博客-CSDN博客 时间问题演示 为了方便演示&#xff0c;我写了一个简单 Spring Boot 项目&#xff…

信息技术01--初/高中--选择真题汇总(197道题)

文章目录 1 真题 01-102 真题 11-203 真题 21-304 真题 31-405 真题 41-506 真题 51-607 真题 61-708 真题 71-809 真题 81-9010 真题 91-10011 真题 101-11012 真题 111-12013 真题 121-13014 真题 131-14015 真题 141-15016 真题 151-16017 真题 161-17018 真题 171-18019 真…

Java运行时jar时终端输出的中文日志是乱码

运行Jar时在控制台输出的中文日志全是乱码&#xff0c;这是因为cmd/bash默认的编码是GBK&#xff0c;只要把cmd的编码改成UTF-8即可 两种方式修改&#xff1a;临时修改和注册表永久修改 临时修改 只对当前的cmd页面有效&#xff0c;关闭后重新打开都会恢复成GBK, 打开cmd&am…

C盘清理 “ProgramData\Microsoft\Search“ 文件夹过大

修改索引存放位置 进入控制面板->查找方式改成大图标&#xff0c; 选择索引选项 进入高级 填写新的索引位置 删除C盘索引信息 删除C:\ProgramData\Microsoft\Search\Data\Applications 下面的文件夹 如果报索引正在使用&#xff0c;参照第一步替换索引位置。关闭索引

泊松回归和地理加权泊松回归

01 泊松回归 泊松回归(Poisson Regression)是一种广义线性模型,用于建立离散型响应变量(计数数据)与一个或多个预测变量之间的关系。它以法国数学家西蒙丹尼泊松(Simon Denis Poisson)的名字命名,适用于计算“事件发生次数”的概率,比如交通事故发生次数、产品缺陷数…

微服务-gateway鉴权

文章目录 一、前言二、gateway鉴权1、依赖配置2、编写代码3、GlobalFilter详解3.1、GlobalFilter简介3.2、GlobalFilter自定义执行顺序3.2.1、实现Order接口实现自定义执行顺序 一、前言 网关是介于客户端和服务器端之间的中间层&#xff0c;所有的外部请求都会先经过 网关这一…

Flutter:getX的学习

前言 学习教程&#xff1a;Getx教程_FlutterGetx系列实战教程 简介 getX是第三方的状态管理插件&#xff0c;不仅具有状态管理的功能&#xff0c;还具有路由管理、主题管理、国际化多语言管理、网络请求、数据验证等功能。相比其他状态管理组件&#xff0c;getX简单、功能强大…

“智越”界限,SSOT上海国际智慧办公展览会来啦

随着人工智能、大数据、云计算等技术的快速发展&#xff0c;目前物联网应用已经从概念踏进规模部署的阶段&#xff0c;场景化和规模化已成常态。传统办公室作为企业行政运营的核心场景&#xff0c;也开始受到“科技办公“移动办公”“共享办公”等非传“智慧办公”概念的影响不…

vscode远程调试php

使用vscode远程调试php的方法 1.安装remote ssh插件 2.连接服务器 可以点击左下角的绿色按钮&#xff0c;或者ctrlshiftp打开命令框输入remote ssh应该也有。 3.在服务器端vscode安装php debug插件 4.安装xdebug xdebug是用来调试php的软件&#xff0c;原本和vscode没什么关…

04、添加 com.fasterxml.jackson.dataformat -- jackson-dataformat-xml 依赖报错

Correct the classpath of your application so that it contains a single, compatible version of com.fasterxml.jackson.dataformat.xml.XmlMapper 解决&#xff1a; 改用其他版本&#xff0c;我没写版本号&#xff0c;springboot自己默认的是 2.11.4 版本 成功启动项目…

DBeaver 23.1.5 发布

导读DBeaver 是一个免费开源的通用数据库工具&#xff0c;适用于开发人员和数据库管理员。DBeaver 23.1.5 现已发布&#xff0c;更新内容如下. Data editor 重新设计了词典查看器面板 UI 空间数据类型&#xff1a;曲线几何线性化已修复 数据保存时结果选项卡关闭的问题已解决…

【LeetCode】剑指 Offer <二刷>(5)

目录 题目&#xff1a;剑指 Offer 10- II. 青蛙跳台阶问题 - 力扣&#xff08;LeetCode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 11. 旋转数组的最小数字 - 力…

超图嵌入论文阅读1:对偶机制非均匀超网络嵌入

超图嵌入论文阅读1&#xff1a;对偶机制非均匀超网络嵌入 原文&#xff1a;Nonuniform Hyper-Network Embedding with Dual Mechanism ——TOIS&#xff08;一区 CCF-A&#xff09; 背景 超边&#xff1a;每条边可以连接不确定数量的顶点 我们关注超网络的两个属性&#xff1…

打破数据孤岛!时序数据库 TDengine 与创意物联感知平台完成兼容性互认

新型物联网实现良好建设的第一要务就是打破信息孤岛&#xff0c;将数据汇聚在平台统一处理&#xff0c;实现数据共享&#xff0c;放大物联终端的行业价值&#xff0c;实现系统开放性&#xff0c;以此营造丰富的行业应用环境。在此背景下&#xff0c;物联感知平台应运而生&#…

计算机毕业设计 校园二手交易平台 Vue+SpringBoot+MySQL

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发、系统定制、远程技术指导。CSDN学院、蓝桥云课认证讲师&#xff0c;全栈领域优质创作者。 项目内容…

uni-app之android离线自定义基座

一 为什么要自定义基座 1&#xff0c;基座其实就是一个app&#xff0c;然后新开发的页面可以直接在手机上面显示&#xff0c;查看效果。 2&#xff0c;默认的基座就是uniapp帮我们打包好的基座app&#xff0c;然后我们可以进行页面的调试。 3&#xff0c;自定义基座主要用来…

【MySQL】4、MySQL备份与恢复

备份的主要目的是灾难恢复&#xff0c;备份还可以测试应用、回滚数据修改、查询历史数据、审计等 MySQL日志管理 MySQL 的日志默认保存位置为 /usr/local/mysql/data #配置文件 vim /etc/my.cnf 日志的分类 常见日志有&#xff1a; 错误日志&#xff0c;一般查询日志&…

Windows下Redis的安装和配置

文章目录 一,Redis介绍二,Redis下载三,Redis安装-解压四,Redis配置五,Redis启动和关闭(通过terminal操作)六,Redis连接七,Redis使用 一,Redis介绍 远程字典服务,一个开源的,键值对形式的在线服务框架,值支持多数据结构,本文介绍windows下Redis的安装,配置相关,官网默认下载的是…

SpringCloud(十)——ElasticSearch简单了解(三)数据聚合和自动补全

文章目录 1. 数据聚合1.1 聚合介绍1.2 Bucket 聚合1.3 Metrics 聚合1.4 使用 RestClient 进行聚合 2. 自动补全2.1 安装补全包2.2 自定义分词器2.3 自动补全查询2.4 拼音自动补全查询2.5 RestClient 实现自动补全2.5.1 建立索引2.5.2 修改数据定义2.5.3 补全查询2.5.4 解析结果…