- 人工智能
- 计算机视觉
- 深度学习
- 微调
【免费下载链接】jetson-inference
Hello AI World guide to deploying deep-learning inference networks and deep vision primitives with TensorRT and NVIDIA Jetson.
导读
本文是 jetson-inference 项目附录(docs/aux-image.md)的完整技术指南,系统讲解由 jetson-utils 库提供的、运行在 GPU 上的图像格式定义、内存分配与拷贝、Python 图像胶囊对象(cudaImage)以及与 Numpy / PyTorch / CuPy 等生态的零拷贝互操作,并逐一剖析颜色转换(cudaConvertColor)、缩放(cudaResize)、裁剪(cudaCrop)、归一化(cudaNormalize)、叠加(cudaOverlay)与绘制图形(cudaDraw)等 CUDA 图像处理例程。读完本文,你将能在 Jetson 平台上用 Python 或 C++ 直接操作 GPU 图像内存,为深度学习推理管线编写高效的前处理与后处理代码。
适用前提:本文涉及的
jetson_utilsPython 模块与 CUDA 例程,均随 jetson-inference 一起构建安装;C++ 头文件位于jetson-utils子库中(cuda/cudaMappedMemory.h、cuda/cudaColorspace.h等)。视频采集与输出、图像加载保存的更多背景请先阅读 Camera Streaming and Multimedia 指南。
一、图像格式体系(Image Formats)
虽然 视频流接口 与 DNN 对象(如 imageNet、detectNet、segNet)都期望输入 RGB/RGBA 格式的图像,但 jetson-utils 针对传感器采集与底层 I/O 还定义了多种其他格式:
| 类别 | 格式字符串 | imageFormat枚举值 | 数据类型 | 位深(每像素有效位数) |
|---|---|---|---|---|
| RGB/RGBA | rgb8 | IMAGE_RGB8 | uchar3 | 24 |
rgba8 | IMAGE_RGBA8 | uchar4 | 32 | |
rgb32f | IMAGE_RGB32F | float3 | 96 | |
rgba32f | IMAGE_RGBA32F | float4 | 128 | |
| BGR/BGRA | bgr8 | IMAGE_BGR8 | uchar3 | 24 |
bgra8 | IMAGE_BGRA8 | uchar4 | 32 | |
bgr32f | IMAGE_BGR32F | float3 | 96 | |
bgra32f | IMAGE_BGRA32F | float4 | 128 | |
| YUV(4:2:2) | yuyv | IMAGE_YUYV | uint8 | 16 |
yuy2 | IMAGE_YUY2 | uint8 | 16 | |
yvyu | IMAGE_YVYU | uint8 | 16 | |
uyvy | IMAGE_UYVY | uint8 | 16 | |
| YUV(4:2:0) | i420 | IMAGE_I420 | uint8 | 12 |
yv12 | IMAGE_YV12 | uint8 | 12 | |
nv12 | IMAGE_NV12 | uint8 | 12 | |
| Bayer | bayer-bggr | IMAGE_BAYER_BGGR | uint8 | 8 |
bayer-gbrg | IMAGE_BAYER_GBRG | uint8 | 8 | |
bayer-grbg | IMAGE_BAYER_GRBG | uint8 | 8 | |
bayer-rggb | IMAGE_BAYER_RGGB | uint8 | 8 | |
| Grayscale | gray8 | IMAGE_GRAY8 | uint8 | 8 |
gray32f | IMAGE_GRAY32F | float | 32 |
要点说明:
- YUV 格式的详细规范可参考 fourcc 标准(YV12/NV12 等常见于 H.264/HEVC 编解码流水线,YUYV/UYVY 常见于 V4L2 摄像头采集)。
- C++ 注意:
uchar3/uchar4/float3/float4这些向量类型只能用于 RGB/RGBA 格式。若你用这些类型表示 BGR/BGRA 数据,某些处理函数会把它误判为 RGB/RGBA,除非显式指定正确的 imageFormat 枚举。 - 格式之间的转换请使用下文 颜色转换 的
cudaConvertColor()。
二、GPU 内存分配(Image Allocation)
当需要为中间/输出图像(即处理过程中的工作内存)分配 GPU 显存时:
- C++:使用
cudaAllocMapped()(头文件jetson-utils/cudaMappedMemory.h)。 - Python:使用
jetson_utils.cudaImage对象或jetson_utils.cudaAllocMapped()。 - 注意:
videoSource输入流会自动分配自己的 GPU 内存并返回最新图像,因此采集场景无需自行分配。
由cudaAllocMapped()分配的内存位于CPU/GPU 共享内存空间(即 ZeroCopy 内存),CPU 与 GPU 均可直接访问,无需在两者之间执行内存拷贝。
同步要求:若 GPU 处理完成后想从 CPU 访问图像,必须先调用cudaDeviceSynchronize()等待 GPU 完成。C++ 中释放内存用cudaFreeHost();Python 中内存由垃圾回收器自动释放,也可用del显式释放。
Python 分配 / 同步 / 释放
from jetson_utils import cudaImage, cudaDeviceSynchronize # 分配一张 1920x1080 的 rgb8 图像 img = cudaImage(width=1920, height=1080, format='rgb8') # 在 GPU 上进行一些处理 ... # 等待 GPU 处理完成 cudaDeviceSynchronize() # Python 会自动释放内存,也可以用 'del' 显式释放 del imgC++ 分配 / 同步 / 释放
#include <jetson-utils/cudaMappedMemory.h> void* img = NULL; // 分配一张 1920x1080 的 rgb8 图像 if( !cudaAllocMapped(&img, 1920, 1080, IMAGE_RGB8) ) return false; // 内存错误 // 在 GPU 上进行一些处理 ... // 等待 GPU 处理完成 CUDA(cudaDeviceSynchronize()); // 释放内存 CUDA(cudaFreeHost(img));C++ 类型化指针的简化写法
如果指针已声明为uchar3/uchar4/float3/float4类型,可省略显式的 imageFormat 枚举,与上面的分配在功能上等价:
uchar3* img = NULL; // 可以是 uchar3(rgb8)、uchar4(rgba8)、float3(rgb32f)、float4(rgba32f) if( !cudaAllocMapped(&img, 1920, 1080) ) return false;注意:使用这些向量类型时,图像会被假定为对应的 RGB/RGBA 色彩空间;若实际存放的是 BGR/BGRA 数据,务必显式传入正确的图像格式。
三、图像拷贝(Copying Images)
cudaMemcpy()用于在同一格式、同一尺寸的图像之间拷贝内存。它是 CUDA 标准函数,Python 端jetson_utils也提供了等价版本:
Python
from jetson_utils import cudaMemcpy, cudaImage, loadImage # 加载图像并分配目标内存 img_a = loadImage("my_image.jpg") img_b = cudaImage(like=img_a) # 等价于显式指定 width, height, format # 拷贝图像(参数顺序:dst, src) cudaMemcpy(img_b, img_a) # 也可以使用快捷方式,返回一份副本 img_c = cudaMemcpy(img_a)C++
#include <jetson-utils/cudaMappedMemory.h> #include <jetson-utils/imageIO.h> uchar3* img_a = NULL; uchar3* img_b = NULL; int width = 0; int height = 0; // 加载示例图像 if( !loadImage("my_image.jpg", &img_a, &width, &height) ) return false; // 加载错误 // 分配目标内存 if( !cudaAllocMapped(&img_b, width, height) ) return false; // 内存错误 // 拷贝图像(dst, src) if( CUDA_FAILED(cudaMemcpy(img_b, img_a, width * height * sizeof(uchar3), cudaMemcpyDeviceToDevice)) ) return false; // memcpy 错误四、Python 图像胶囊对象(cudaImage)
在 Python 中分配图像,或用videoSource.Capture()从视频流采集图像时,返回的是一个自包含的内存胶囊对象(类型jetson_utils.cudaImage),可在不拷贝底层内存的情况下随处传递。
cudaImage对象具有以下成员:
<cudaImage object> .ptr # 内存地址(一般不直接使用) .size # 字节大小 .shape # (height, width, channels) 元组 .width # 像素宽度 .height # 像素高度 .channels # 颜色通道数 .format # 格式字符串 .mapped # 是否为 ZeroCopy 内存 .timestamp # 时间戳(纳秒)因此可以直接写img.width、img.height等来访问图像属性。
4.1 数组接口总览
为实现与其他库的零拷贝互操作,可从 Python 通过多种方式访问cudaImage内存:
- 直接从 Python 下标索引图像(4.2 节)
- Numpy
__array__接口、cudaToNumpy()/cudaFromNumpy()(4.3 节) - Numba
__cuda_array_interface__(适用于 PyTorch、CuPy、PyCUDA、VPI 等,4.4 节) - 直接共享内存指针
.ptr(4.5 节)
这些机制的核心设计是:底层内存被映射并与其他库共享,从而避免内存拷贝。
4.2 从 Python 直接访问像素数据
cudaImage支持下标索引,可直接在 CPU 上读写像素:
for y in range(img.height): for x in range(img.width): pixel = img[y,x] # 返回元组,RGB 格式为 (r,g,b),RGBA 格式为 (r,g,b,a) img[y,x] = pixel # 用元组设置像素(元组长度必须匹配通道数)注意:下标索引仅在
mapped=True(默认值)分配的cudaImage上可用;否则数据无法从 CPU 访问,会抛出异常。
索引元组支持以下形式:
img[y,x]:注意(y,x)的顺序,与 Numpy 一致;img[y,x,channel]:只访问某个通道(0 红、1 绿、2 蓝、3 透明);img[y*img.width+x]:扁平一维索引,访问该像素的全部通道。
性能提醒:虽然支持逐像素下标访问,但对大图像逐像素索引会显著拖慢应用,不建议在 Python 中这样做;在 GPU 实现不可用的情况下,更好的选择是改用 Numpy。
4.3 与 Numpy 数组互操作
cudaImage实现了 Numpy 的__array__接口协议,因此可以直接用在很多 Numpy 函数中,无需来回拷贝:
import numpy as np from jetson_utils import cudaImage cuda_img = cudaImage(320, 240, 'rgb32f') array = np.ones(cuda_img.shape, np.float32) print(np.add(cuda_img, array))注意:Numpy 运行在 CPU 上,因此
cudaImage应以mapped=True(默认)分配,使其内存对 CPU/GPU 同时可访问。Numpy 对它的任何修改都会反映到底层cudaImage内存中。
需要留意的是:应使用独立的 Numpy 例程(如numpy.mean(array))而非 ndarray 类方法(如array.mean())。因为cudaImage只导出__array__接口用于访问内存,并未实现 Numpy 的类方法。要使用全套 ndarray 方法,见下面的cudaToNumpy()。
4.3.1 转换为 Numpy 数组(cudaToNumpy)
调用cudaToNumpy()可显式获得一个映射到cudaImage的numpy.ndarray:
import numpy as np from jetson_utils import cudaImage, cudaToNumpy cuda_img = cudaImage(320, 240, 'rgb32f') array = cudaToNumpy(cuda_img) print(array.mean())底层内存不会被拷贝,Numpy 直接访问它——因此若通过 Numpy 就地修改数据,底层cudaImage也会同步变化。
与 OpenCV 联用时注意:OpenCV 期望 BGR 色彩空间,因此应先调用cudaConvertColor()把图像从 RGB 转为 BGR。
4.3.2 从 Numpy 数组转入(cudaFromNumpy)
若你有一个 Numpy ndarray(例如由 OpenCV 提供),它只能从 CPU 访问。可用cudaFromNumpy()把它拷贝到 GPU(进入共享的 CPU/GPU 映射内存):
import numpy as np from jetson_utils import cudaFromNumpy array = np.zeros((240, 320, 3), dtype=np.float32) cuda_img = cudaFromNumpy(array)同理,OpenCV 图像是 BGR 色彩空间,之后应调用cudaConvertColor()从 BGR 转为 RGB。
仓库内的相关示例:segnet 后处理工具 python/examples/segnet_utils.py 中就通过
cudaAllocMapped()分配 overlay/mask 缓冲、并用cudaToNumpy()把gray8类别掩膜映射为 Numpy 数组供逐类统计使用;python/examples/README.md 也专门提示了 numpy 互操作示例的用法。
4.4 CUDA 数组接口
cudaImage还实现了 Numba 的__cuda_array_interface__,为使用 GPU 内存的库(PyTorch、CuPy、PyCUDA、VPI 等)提供零拷贝互操作。与 Numpy__array__类似,它可透明地把cudaImage传入 Numba/PyTorch/CuPy/PyCUDA 函数,内存被共享,无拷贝与额外开销。
以 CuPy 为例:
import cupy from jetson_utils import cudaImage cuda_img = cudaImage(640, 480, 'rgb8') cupy_array = cupy.ones((480, 640, 3)) print(cupy.add(cuda_img, cupy_array))
cudaImage同时也实现了 PyCUDA 的gpudata接口,可像 PyCUDAGPUArray一样使用。
与 PyTorch 张量共享内存:
import torch from jetson_utils import cudaImage # 分配 cuda 内存 cuda_img = cudaImage(640, 480, 'rgb8') # 通过 __cuda_array_interface__ 映射为 torch 张量 tensor = torch.as_tensor(cuda_img, device='cuda')这使cudaImage的 GPU 内存可被 PyTorch GPU 张量直接使用而不发生拷贝——PyTorch 对张量内容的任何修改都会反映到cudaImage中。注意必须指定device='cuda',PyTorch 才会执行零拷贝映射;可通过比对cudaImage与 PyTorch 张量的数据指针是否一致来验证。
4.5 共享内存指针
对不支持上述接口的库,cudaImage通过.ptr属性暴露底层内存的原始数据指针,可在不拷贝的情况下导入其他数据结构。反过来,cudaImage构造器也接受ptr参数指向外部分配的缓冲区——此时cudaImage共享该内存而不是自行分配。
把已有的 PyTorch GPU 张量映射到cudaImage:
import torch from jetson_utils import cudaImage # 分配 NCHW 布局(颜色跨步)的 GPU 张量 tensor = torch.rand(1, 3, 480, 640, dtype=torch.float32, device='cuda') # 转置为 NHWC 布局(颜色交织) tensor = tensor.to(memory_format=torch.channels_last) # 或 tensor.permute(0, 3, 2, 1) # 用同一底层内存映射为 cudaImage(任何修改都会反映到 PyTorch 张量) cuda_img = cudaImage(ptr=tensor.data_ptr(), width=tensor.shape[-1], height=tensor.shape[-2], format='rgb32f')注意:务必区分 NCHW 通道布局(颜色跨步)与 NHWC 布局(颜色交织),
cudaImage期望的是后者。
当外部指针被映射进cudaImage时,默认情况下cudaImage不取得底层内存的所有权,释放时不会 free 它(如需改变,可在构造器中设置freeOnDelete=True)。库之间的同步应由使用者自行处理(例如避免 PyTorch 与cudaImage同时访问同一内存)。
五、颜色转换(Color Conversion)
cudaConvertColor()(头文件jetson-utils/cudaColorspace.h)用 GPU 在图像格式与色彩空间之间进行转换。例如:RGB 转 BGR(或反之)、YUV 转 RGB、RGB 转灰度等;也可以改变数据类型与通道数(如 RGB8 转 RGBA32F)。可转换的格式详见 图像格式体系。
转换限制
- YUV 格式不支持 BGR/BGRA 与灰度(仅支持 RGB/RGBA);
- YUV 的 NV12、YUYV、YVYU、UYVY 只能转为RGB/RGBA(不能反向);
- Bayer 格式只能转为 RGB8(
uchar3)与 RGBA8(uchar4)。
Python 示例
import jetson_utils # 加载输入图像(默认格式 rgb8,也可指定 rgba8/rgb32f/rgba32f) imgInput = jetson_utils.loadImage('my_image.jpg', format='rgb8') # 按输入同尺寸分配 rgba32f 输出 imgOutput = jetson_utils.cudaAllocMapped(width=imgInput.width, height=imgInput.height, format='rgba32f') # 从 rgb8 转为 rgba32f(转换格式取自图像胶囊对象) jetson_utils.cudaConvertColor(imgInput, imgOutput)C++ 示例
#include <jetson-utils/cudaColorspace.h> #include <jetson-utils/cudaMappedMemory.h> #include <jetson-utils/imageIO.h> uchar3* imgInput = NULL; // 输入 rgb8(uchar3) float4* imgOutput = NULL; // 输出 rgba32f(float4) int width = 0; int height = 0; // 以 rgb8(uchar3)加载图像 if( !loadImage("my_image.jpg", &imgInput, &width, &height) ) return false; // 按同尺寸分配 rgba32f(float4)输出 if( !cudaAllocMapped(&imgOutput, width, height) ) return false; // 从 rgb8 转为 rgba32f if( CUDA_FAILED(cudaConvertColor(imgInput, IMAGE_RGB8, imgOutput, IMAGE_RGBA32F, width, height)) ) return false; // 发生错误或转换不受支持从源码结构看,
cudaConvertColor与cudaResize、cudaNormalize等例程共同组成了 DNN 前处理的基础设施——例如 c/imageNet.cpp 的imageNet::PreProcess()在把图像送入 TensorRT 引擎前,就通过归一化/通道变换把输入图像转换到网络期望的张量范围与布局,足见这些 CUDA 例程在推理流水线中的枢纽地位。
六、缩放(Resizing)
cudaResize()(头文件jetson-utils/cudaResize.h)用 GPU 将图像缩放(可降采样或升采样)到不同尺寸。以下示例把图像缩小一半:
Python
import jetson_utils # 加载输入图像 imgInput = jetson_utils.loadImage('my_image.jpg') # 分配输入一半尺寸的输出 imgOutput = jetson_utils.cudaAllocMapped(width=imgInput.width * 0.5, height=imgInput.height * 0.5, format=imgInput.format) # 缩放图像(尺寸取自图像胶囊对象) jetson_utils.cudaResize(imgInput, imgOutput)C++
#include <jetson-utils/cudaResize.h> #include <jetson-utils/cudaMappedMemory.h> #include <jetson-utils/imageIO.h> // 加载输入图像 uchar3* imgInput = NULL; int inputWidth = 0; int inputHeight = 0; if( !loadImage("my_image.jpg", &imgInput, &inputWidth, &inputHeight) ) return false; // 分配输入一半尺寸的输出 uchar3* imgOutput = NULL; int outputWidth = inputWidth * 0.5f; int outputHeight = inputHeight * 0.5f; if( !cudaAllocMapped(&imgOutput, outputWidth, outputHeight) ) return false; // 缩放图像 if( CUDA_FAILED(cudaResize(imgInput, inputWidth, inputHeight, imgOutput, outputWidth, outputHeight)) ) return false;仓库实际用例:换背景示例 python/examples/backgroundnet.py 中先
cudaResize()把替换背景图缩放到与输入一致,再cudaMemcpy()拷贝进输出缓冲,最后cudaOverlay()合成,完整串起了缩放+拷贝+叠加三个 CUDA 例程。
七、裁剪(Cropping)
cudaCrop()(头文件jetson-utils/cudaCrop.h)用 GPU 把图像裁剪到指定的兴趣区域(ROI)。以下示例围绕图像中心裁剪一半区域。
ROI 矩形的坐标形式为(left, top, right, bottom)。
Python
import jetson_utils # 加载输入图像 imgInput = jetson_utils.loadImage('my_image.jpg') # 计算边框像素量(围绕中心裁剪一半) crop_factor = 0.5 crop_border = ((1.0 - crop_factor) * 0.5 * imgInput.width, (1.0 - crop_factor) * 0.5 * imgInput.height) # 计算 ROI 为 (left, top, right, bottom) crop_roi = (crop_border[0], crop_border[1], imgInput.width - crop_border[0], imgInput.height - crop_border[1]) # 分配裁剪尺寸的输出图像 imgOutput = jetson_utils.cudaAllocMapped(width=imgInput.width * crop_factor, height=imgInput.height * crop_factor, format=imgInput.format) # 裁剪到 ROI jetson_utils.cudaCrop(imgInput, imgOutput, crop_roi)C++
#include <jetson-utils/cudaCrop.h> #include <jetson-utils/cudaMappedMemory.h> #include <jetson-utils/imageIO.h> // 加载输入图像 uchar3* imgInput = NULL; int inputWidth = 0; int inputHeight = 0; if( !loadImage("my_image.jpg", &imgInput, &inputWidth, &inputHeight) ) return false; // 计算边框像素量(围绕中心裁剪一半) const float crop_factor = 0.5; const int2 crop_border = make_int2((1.0f - crop_factor) * 0.5f * inputWidth, (1.0f - crop_factor) * 0.5f * inputHeight); // 计算 ROI 为 (left, top, right, bottom) const int4 crop_roi = make_int4(crop_border.x, crop_border.y, inputWidth - crop_border.x, inputHeight - crop_border.y); // 分配输入一半尺寸的输出 uchar3* imgOutput = NULL; if( !cudaAllocMapped(&imgOutput, inputWidth * crop_factor, inputHeight * crop_factor) ) return false; // 裁剪图像 if( CUDA_FAILED(cudaCrop(imgInput, imgOutput, crop_roi, inputWidth, inputHeight)) ) return false;仓库实际用例:快照裁剪示例 python/examples/detectnet-snap.py 先用
cudaAllocMapped()按检测框 ROI 的宽高分配快照缓冲,再cudaCrop()裁出目标区域、cudaDeviceSynchronize()同步后saveImage()落盘,演示了“检测框 ROI → GPU 裁剪 → 保存”的完整链路。
八、归一化(Normalization)
cudaNormalize()(头文件jetson-utils/cudaNormalize.h)用 GPU 改变像素强度范围。例如把[0,1]范围的像素值转为[0,255];像素值的另一个常见范围是[-1,1]。
注意:jetson-inference 与 jetson-utils 中的其他函数都期望像素值在
[0,255]范围,因此通常不需要用cudaNormalize();但当你在处理来自其他来源/去向的数据时它就会派上用场。
以下示例把图像从[0,255]归一化到[0,1]:
Python
import jetson_utils # 加载输入图像(像素范围为 0-255) imgInput = jetson_utils.loadImage('my_image.jpg') # 分配与输入同尺寸的输出 imgOutput = jetson_utils.cudaAllocMapped(width=imgInput.width, height=imgInput.height, format=imgInput.format) # 把图像从 [0,255] 归一化到 [0,1] jetson_utils.cudaNormalize(imgInput, (0,255), imgOutput, (0,1))C++
#include <jetson-utils/cudaNormalize.h> #include <jetson-utils/cudaMappedMemory.h> #include <jetson-utils/imageIO.h> uchar3* imgInput = NULL; uchar3* imgOutput = NULL; int width = 0; int height = 0; // 加载输入图像(像素范围为 0-255) if( !loadImage("my_image.jpg", &imgInput, &width, &height) ) return false; // 分配与输入同尺寸的输出 if( !cudaAllocMapped(&imgOutput, width, height) ) return false; // 把图像从 [0,255] 归一化到 [0,1] CUDA(cudaNormalize(imgInput, make_float2(0,255), imgOutput, make_float2(0,1), width, height));九、叠加(Overlay)
cudaOverlay()(头文件jetson-utils/cudaOverlay.h)用 GPU 把一张输入图像合成到输出图像的指定位置。叠加操作通常按顺序调用,从而把多张图像拼成一张合成图。
以下示例加载两张图像并把它们并排合成到一张输出图中:
Python
import jetson_utils # 加载输入图像 imgInputA = jetson_utils.loadImage('my_image_a.jpg') imgInputB = jetson_utils.loadImage('my_image_b.jpg') # 分配能并排容纳两张输入的输出 imgOutput = jetson_utils.cudaAllocMapped(width=imgInputA.width + imgInputB.width, height=max(imgInputA.height, imgInputB.height), format=imgInputA.format) # 合成两张图像(最后两个参数是输出图像中的 x,y 坐标) jetson_utils.cudaOverlay(imgInputA, imgOutput, 0, 0) jetson_utils.cudaOverlay(imgInputB, imgOutput, imgInputA.width, 0)C++
#include <jetson-utils/cudaOverlay.h> #include <jetson-utils/cudaMappedMemory.h> #include <jetson-utils/imageIO.h> #include <algorithm> // for std::max() uchar3* imgInputA = NULL; uchar3* imgInputB = NULL; uchar3* imgOutput = NULL; int2 dimsA = make_int2(0,0); int2 dimsB = make_int2(0,0); // 加载输入图像 if( !loadImage("my_image_a.jpg", &imgInputA, &dimsA.x, &dimsA.y) ) return false; if( !loadImage("my_image_b.jpg", &imgInputB, &dimsB.x, &dimsB.y) ) return false; // 分配能并排容纳两张输入的输出 const int2 dimsOutput = make_int2(dimsA.x + dimsB.x, std::max(dimsA.y, dimsB.y)); if( !cudaAllocMapped(&imgOutput, dimsOutput.x, dimsOutput.y) ) return false; // 合成两张图像(最后两个参数是输出图像中的 x,y 坐标) CUDA(cudaOverlay(imgInputA, dimsA, imgOutput, dimsOutput, 0, 0)); CUDA(cudaOverlay(imgInputB, dimsB, imgOutput, dimsOutput, dimsA.x, 0));仓库实际用例:
cudaOverlay是推理可视化中最常用的合成原语——python/examples/segnet.py 把类别叠加层与类别掩膜并排合成到复合图;examples/segnet/segnet.cpp 与 examples/depthnet/depthnet.cpp 在 C++ 端把原始输入与深度/掩膜结果并排拼合,便于直接观察网络输出效果。
十、绘制图形(Drawing Shapes)
jetson-utils/cudaDraw.h定义了若干绘制基本图形(圆、线、矩形)的函数。
Python
# 加载输入图像 input = jetson_utils.loadImage("my_image.jpg") # cudaDrawCircle(input, (cx,cy), radius, (r,g,b,a), output=None) jetson_utils.cudaDrawCircle(input, (50,50), 25, (0,255,127,200)) # cudaDrawRect(input, (left,top,right,bottom), (r,g,b,a), output=None) jetson_utils.cudaDrawRect(input, (200,25,350,250), (255,127,0,200)) # cudaDrawLine(input, (x1,y1), (x2,y2), (r,g,b,a), line_width, output=None) jetson_utils.cudaDrawLine(input, (25,150), (325,15), (255,0,200,200), 10)注意:若不指定可选的
output图像,操作将在input图像上就地执行。
C++
#include <jetson-utils/cudaDraw.h> #include <jetson-utils/imageIO.h> uchar3* img = NULL; int width = 0; int height = 0; // 加载示例图像 if( !loadImage("my_image.jpg", &img, &width, &height) ) return false; // 加载错误 // 具体定义见 cudaDraw.h CUDA(cudaDrawCircle(img, width, height, 50, 50, 25, make_float4(0,255,127,200))); CUDA(cudaDrawRect(img, width, height, 200, 25, 350, 250, make_float4(255,127,0,200))); CUDA(cudaDrawLine(img, width, height, 25, 150, 325, 15, make_float4(255,0,200,200), 10));十一、在推理管线中组合使用
把上述 API 串起来,就能搭建完整的“采集/加载 → 预处理 → 推理 → 可视化/保存”流水线。仓库中已有多条可供直接参照的完整链路:
- 换背景流水线python/examples/backgroundnet.py:
cudaAllocMapped分配缓冲 →cudaResize缩放替换背景 →cudaMemcpy拷贝 →cudaOverlay合成前景与背景; - 检测快照流水线python/examples/detectnet-snap.py:
cudaAllocMapped按 ROI 分配 →cudaCrop裁出目标 →cudaDeviceSynchronize同步 →saveImage保存; - 分割可视化流水线python/examples/segnet.py 与 python/examples/depthnet.py:
cudaOverlay并排合成输入/掩膜/深度图,cudaDeviceSynchronize保证帧同步。
所有这些例程都遵循同一模式:分配共享内存 → GPU 处理 → 同步 → 释放。把握好 ZeroCopy 内存的特性(CPU/GPU 直接共享、免拷贝但需同步),再配合cudaImage与 Numpy/PyTorch 等生态的零拷贝接口,即可在 Jetson 上写出高效、可维护的图像处理与推理前后处理代码。相关示例与测试可进一步参考 python/examples、examples 以及 jetson-utils 子库中的cuda/头文件。
延伸阅读
- Camera Streaming and Multimedia:视频采集/输出、图像加载保存的前置知识;
- jetson-inference 主指南:Hello AI World 推理部署整体流程;
- Deep Learning Nodes for ROS/ROS2(ROS 目录 ros):把图像处理与推理接入 ROS 生态。
- 人工智能
- 计算机视觉
- 深度学习
- 微调
【免费下载链接】jetson-inference
Hello AI World guide to deploying deep-learning inference networks and deep vision primitives with TensorRT and NVIDIA Jetson.
相关推荐
tldraw图片工具:图像裁剪与格式转换处理
tldraw图片工具:图像裁剪与格式转换处理 引言:为什么需要专业的白板图像处理? 在现代协作白板应用中,图像处理是不可或缺的核心功能。无论是产品设计会议中的界
前端UI组件Ant引擎图像处理:图片加载与格式转换
Ant引擎图像处理:图片加载与格式转换 概述 Ant引擎作为灵犀互娱开发的开源游戏引擎,提供了强大的图像处理能力。其核心图像处理模块基于bimg库构建,支持多种
游戏开发图形学3D渲染终极Karakeep图片处理指南:Sharp优化与格式转换实用技巧
终极Karakeep图片处理指南:Sharp优化与格式转换实用技巧 Karakeep作为一款自托管的全能书签应用,不仅能收藏链接和笔记,还提供了强大的图片管理功
后端前端移动开发AI 应用知识管理全文检索MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考