当前位置: 首页 > news >正文

[12] 使用 CUDA 进行图像处理

使用 CUDA 进行图像处理

  • 当下生活在高清摄像头的时代,这种摄像头能捕获高达1920*1920像素的高解析度画幅。想要实施的处理这么多的数据,往往需要几个TFlops地浮点处理性能,这些要求CPU也无法满足
  • 通过在代码中使用CUDA,可以利用GPU提供的强大地计算能力
  • CUDA支持多维地Grid和块,因此可以根据图像地尺寸、数据量大小,合理的分配块和线程进行图像处理
  • 简单图像处理过程地特定编程模式:
for(int i=0;i<image_height;i++)
{for(int j=0;j<image_width;j++){//Pixel Processing code for pixel located at(i,j)}
}
  • 将像素处理映射到CUDA地一批线程上:
int i = blockidx.y * blockDim.y + threadIdx.y
int j = blockidx.x * blockDim.x + threadIdx.x

1. 在GPU上通过CUDA进行直方图统计

  • 首先介绍CPU版本的直方图统计,实现如下:
int h_a[1000] = Random values between 0 and 15//假设图像取值范围在【0-15】,定义数组并初始化
int histogram[16];
for(int i=0;i<16;i++)
{histogram[i] = 0;
}
//统计每个值的个数
for(int i=0;i<1000;i++)
{histogram[h_a[i]]+=1;
}
  • 下面写一个同样功能的GPU代码,我们将使用3种不同的方法写这个代码,前两种方法的内核代码如下:
__global__ void histogram_without_atomic(int* d_b, int* d_a)
{int tid = threadIdx.x + blockDim.x * blockIdx.x;int item = d_a[tid];if (tid < SIZE){d_b[item]++;}}__global__ void histogram_atomic(int* d_b, int* d_a)
{int tid = threadIdx.x + blockDim.x * blockIdx.x;int item = d_a[tid];if (tid < SIZE){atomicAdd(&(d_b[item]), 1);}
}
  • 第一个函数是最简单方式实现的直方图统计,每个线程读取 1 个元素值。使用线程ID作为输入数组的索引获取该元素的数值,然后此值再将对应的d_b结果数组中的索引位置处进行 +1 操作。最后d_b数组应该包含输入数据中0-15之间每个值的频次,这种方式将得出错误的结果,因为对相同的存储器位置将有大量的线程试图同时进行不安全的修改,其运行结果如下:
    在这里插入图片描述
  • 第二个函数用原子操作实现统计,避免多线程并行时的资源占用导致的计算异常问题,其计算结果如下:
    在这里插入图片描述
  • main函数如下:
int main()
{//定义设备变量并分配内存int h_a[SIZE];for (int i = 0; i < SIZE; i++) {h_a[i] = i % NUM_BIN;}int h_b[NUM_BIN];for (int i = 0; i < NUM_BIN; i++) {h_b[i] = 0;}// 声明GPU指针变量int* d_a;int* d_b;// 分配GPU变量内存cudaMalloc((void**)&d_a, SIZE * sizeof(int));cudaMalloc((void**)&d_b, NUM_BIN * sizeof(int));// transfer the arrays to the GPUcudaMemcpy(d_a, h_a, SIZE * sizeof(int), cudaMemcpyHostToDevice);cudaMemcpy(d_b, h_b, NUM_BIN * sizeof(int), cudaMemcpyHostToDevice);// 进行直方图统计//histogram_without_atomic << <((SIZE + NUM_BIN - 1) / NUM_BIN), NUM_BIN >> > (d_b, d_a);histogram_atomic << <((SIZE+NUM_BIN-1) / NUM_BIN), NUM_BIN >> >(d_b, d_a);// copy back the sum from GPUcudaMemcpy(h_b, d_b, NUM_BIN * sizeof(int), cudaMemcpyDeviceToHost);printf("Histogram using 16 bin without shared Memory is: \n");for (int i = 0; i < NUM_BIN; i++) {printf("bin %d: count %d\n", i, h_b[i]);}// free GPU memory allocationcudaFree(d_a);cudaFree(d_b);return 0;
}
  • 当我们试图测量使用了原子操作的该代码的性能的时候,你会发现相比CPU的性能,对于很大规模的数组,GPU的实现更慢。这就引入了一个问题:我们真的应当使用CUDA进行直方图统计吗?如果必须能否将这个计算更快些?
  • 这两个问题的答案都是:YES 。如果我们在一个块中用共享内存进行直方图统计,最后再将每个块的部分统计结果叠加到全局内存上的最终结果上去。这样就能加速该操作。这是因为整数加法满足交换律。我需要补充的是:只有当原始数据就在GPU的显存上的时候,才应当考虑使用GPU计算,否则完全不应当 cudaMemcpy 过来再计算,因为仅 cudaMemcpy 的时间就将等于或者大于 CPU 计算的时间,用共享内存进行直方图统计的内核函数代码实现如下:
#include <stdio.h>
#include <cuda_runtime.h>#define SIZE 1000
#define NUM_BIN 256__global__ void histogram_shared_memory(int* d_b, int* d_a)
{int tid = threadIdx.x + blockDim.x * blockIdx.x;int offset = blockDim.x * gridDim.x;__shared__ int cache[256];cache[threadIdx.x] = 0;__syncthreads();while (tid < SIZE){atomicAdd(&(cache[d_a[tid]]), 1);tid += offset;}__syncthreads();atomicAdd(&(d_b[threadIdx.x]), cache[threadIdx.x]);
}
  • 我们要为当前的每个块都统计一次局部结果,所以需要先将共享内存清空,然后用类似之前的方式在共享内存中进行直方图统计。这种情况下,每个块只会统计部分结果存储在各自的共享内存中,并非像以前那样直接统计为全局内存上的总体结果。
  • 本例中,块中256个线程进行共享内存上的256个元素的访问,而原本的代码则在全局内存上的16个元素位置上进行访问。因为共享内存本身要比全局内存具有更高效的并行访问性能,同时将16个统一的竞争访问的位置放宽到了每个共享内存上的256个竞争位置,这两个因素共同缩小了原子操作累计统计的时间。
  • 最终还需要进行一次原子操作,将每个块的共享内存上的部分统计结果累加到全局内存上的最终统计结果。因为整数加法满足交换律,我们不需要担心每个块执行的顺序。
  • main函数如上一个类似:
int main()
{// generate the input array on the hostint h_a[SIZE];for (int i = 0; i < SIZE; i++) {//h_a[i] = bit_reverse(i, log2(SIZE));h_a[i] = i % NUM_BIN;}int h_b[NUM_BIN];for (int i = 0; i < NUM_BIN; i++) {h_b[i] = 0;}// declare GPU memory pointersint* d_a;int* d_b;// allocate GPU memorycudaMalloc((void**)&d_a, SIZE * sizeof(int));cudaMalloc((void**)&d_b, NUM_BIN * sizeof(int));// transfer the arrays to the GPUcudaMemcpy(d_a, h_a, SIZE * sizeof(int), cudaMemcpyHostToDevice);cudaMemcpy(d_b, h_b, NUM_BIN * sizeof(int), cudaMemcpyHostToDevice);// launch the kernelhistogram_shared_memory << <SIZE / 256, 256 >> > (d_b, d_a);// copy back the result from GPUcudaMemcpy(h_b, d_b, NUM_BIN * sizeof(int), cudaMemcpyDeviceToHost);printf("Histogram using 16 bin is: ");for (int i = 0; i < NUM_BIN; i++) {printf("bin %d: count %d\n", i, h_b[i]);}// free GPU memory allocationcudaFree(d_a);cudaFree(d_b);return 0;
}
  • 执行结果:
    在这里插入图片描述

相关文章:

[12] 使用 CUDA 进行图像处理

使用 CUDA 进行图像处理 当下生活在高清摄像头的时代&#xff0c;这种摄像头能捕获高达1920*1920像素的高解析度画幅。想要实施的处理这么多的数据&#xff0c;往往需要几个TFlops地浮点处理性能&#xff0c;这些要求CPU也无法满足通过在代码中使用CUDA&#xff0c;可以利用GP…...

MyBatisPlus代码生成器(交互式)快速指南

引言 本片文章是对代码生成器(交互)快速配置使用流程&#xff0c;更多配置方法可查看官方文档&#xff1a; 代码生成器配置官网 如有疑问欢迎评论区交流&#xff01; 文章目录 引言演示效果图引入相关依赖创建代码生成器对象引入Freemarker模板引擎依赖支持的模板引擎 MyBat…...

深度学习模型训练之日志记录

在深度学习模型训练过程中&#xff0c;进行有效的训练日志记录是至关重要的。以下是一些常见的策略和工具来实现这一目标&#xff1a; 1. 使用TensorBoard TensorBoard是TensorFlow提供的一个可视化工具&#xff0c;用于记录和展示训练过程中的各种指标。 设置TensorBoard&a…...

深入理解Python中的装饰器

装饰器是Python中一个强大且灵活的工具,允许开发者在不修改函数或类定义的情况下扩展或修改其行为。装饰器广泛应用于日志记录、访问控制、缓存等场景。本文将详细探讨Python中的装饰器,包括基本概念、函数装饰器和类装饰器、内置装饰器以及装饰器的高级用法。 目录 装饰器概…...

基于springboot的人力资源管理系统源码数据库

传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;员工信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广大用户的…...

如何舒适的使用VScode

安装好VScode后通常会很不好用&#xff0c;以下配置可以让你的VScode变得好用许多。 VScode的配置流程 1、设置VScode中文2、下载C/C拓展&#xff0c;使代码可以跳转3、更改编码格式4、设置滚轮缩放5、设置字体6、设置保存自动改变格式7、vscode设置快捷代码 1、设置VScode中文…...

【微信小程序】开发环境配置

目录 小程序的标准开发模式&#xff1a; 注册小程序的开发账号 安装开发者工具 下载 设置外观和代理 第一个小程序 -- 创建小程序项目 查看项目效果 第一种&#xff1a;在模拟器上查看项目效果 项目的基本组成结构 小程序代码的构成 app.json文件 project.config…...

启动盘镜像制作神器(下载即用)

一、简介 1、一款受欢迎且功能强大的USB启动盘制作工具,允许用户将操作系统镜像文件(如Windows或Linux的ISO文件)制作成可引导的USB启动盘。它支持多种操作系统,包括Windows、Linux和各种基于UEFI的系统。Rufus的一个显著特点是制作速度快,据称其速度比其他常用工具如UNet…...

PHP框架详解 - Symfony框架

引言 在现代Web开发中&#xff0c;PHP作为一种灵活且功能强大的编程语言&#xff0c;广泛应用于各种Web应用程序的开发中。为了提高开发效率、代码的可维护性和可扩展性&#xff0c;开发者通常会选择使用框架来构建应用程序。在众多PHP框架中&#xff0c;Symfony以其强大的功能…...

鸿蒙开发:【线程模型】

线程模型 线程类型 Stage模型下的线程主要有如下三类&#xff1a; 主线程 执行UI绘制。管理主线程的ArkTS引擎实例&#xff0c;使多个UIAbility组件能够运行在其之上。管理其他线程的ArkTS引擎实例&#xff0c;例如使用TaskPool&#xff08;任务池&#xff09;创建任务或取消…...

初级网络工程师之从入门到入狱(三)

本文是我在学习过程中记录学习的点点滴滴&#xff0c;目的是为了学完之后巩固一下顺便也和大家分享一下&#xff0c;日后忘记了也可以方便快速的复习。 中小型网络系统综合实战实验 前言一、详细拓扑图二、LSW2交换机三、LSW3交换机四、LSW1三层交换机4.1、4.2、4.3、4.4、4.5、…...

【数据结构】排序(直接插入、折半插入、希尔排序、快排、冒泡、选择、堆排序、归并排序、基数排序)

目录 排序一、插入排序1.直接插入排序2.折半插入排序3.希尔排序 二、交换排序1.快速排序2.冒泡排序 三、选择排序1. 简单选择排序2. 堆排序3. 树排序 四、归并排序(2-路归并排序)五、基数排序1. 桶排序&#xff08;适合元素关键字值集合并不大&#xff09;2. 基数排序基数排序的…...

MongoDB ObjectId 详解

MongoDB ObjectId 详解 MongoDB 是一个流行的 NoSQL 数据库,它使用 ObjectId 作为文档的唯一标识符。ObjectId 是一个 12 字节的 BSON 类型,它在 MongoDB 中用于保证每个文档的唯一性。本文将详细解释 ObjectId 的结构、生成方式以及它在 MongoDB 中的应用。 ObjectId 的结…...

大数据-11-案例演习-淘宝双11数据分析与预测 (期末问题)

目录 第一部分 Hadoop是什么 官方解释&#xff1a; 个人总结 HDFS 是什么? 官方解释&#xff1a; 个人总结 yarn是什么? 官方解释&#xff1a; 个人总结 mapreduce&#xff0c;spark 是什么? 官方解释&#xff1a; MapReduce Spark 个人总结 MapReduce Spa…...

Kubernetes集群监控,kube-prometheus安装教程,一键部署

Kube-prometheus介绍 Kube-prometheus 是一个用于监控 Kubernetes 集群的完整解决方案。它基于 Prometheus 生态系统&#xff0c;提供了一整套预配置的组件和配置文件&#xff0c;以便轻松地在 Kubernetes 上部署和运行 Prometheus 监控系统。 Kube-prometheus 主要包括以下组…...

【Gradio】快速入门

https://www.gradio.app/ Gradio 是一个开源 Python 软件包https://github.com/gradio-app/gradio &#xff0c;可以让你快速为机器学习模型、API 或任何任意 Python 函数创建一个演示或网络应用程序。然后&#xff0c;您就可以使用 Gradio 内置的分享功能&#xff0c;在几秒钟…...

深度学习Day-19:DenseNet算法实战与解析

&#x1f368; 本文为&#xff1a;[&#x1f517;365天深度学习训练营] 中的学习记录博客 &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制] 要求&#xff1a; 根据 Pytorch 代码&#xff0c;编写出 TensorFlow 代码研究 DenseNet 与 ResNetV 的区别改进思路是…...

基于openssl实现AES ECB加解密

AES加密&#xff0c;全称高级加密标准&#xff08;Advanced Encryption Standard&#xff09;&#xff0c;是一种广泛使用的对称加密算法&#xff0c;用于保护电子数据的安全。以下是AES加密的基本原理和特点&#xff1a; 基本概念 对称加密&#xff1a;AES是一种对称加密算法…...

Git:从配置到合并冲突

目录 1.前言 2.Git的下载与初始化配置 3.Git中新建仓库 4.Git的工作区域和文件状态 5.Git中查看操作和提交记录 6.Git中添加和提交文件 7.Git中回退提交版本 8.Git中查看版本间的差异 9.Git中删除文件 10.Git中忽略指定文件 11.Git中配置SSH密钥 12.Git中关联克隆仓库 13.Git中…...

leetcode hot100 之 最长公共子序列

题目 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08;…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...