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

CANN/ops-cv光栅化算子文档

aclnnRasterizer

【免费下载链接】ops-cv本项目是CANN提供的图像处理、目标检测相关的算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-cv

📄 查看源码

产品支持情况

产品是否支持
Ascend 950PR/Ascend 950DT×
Atlas A3 训练系列产品/Atlas A3 推理系列产品
Atlas A2 训练系列产品/Atlas A2 推理系列产品
Atlas 200I/500 A2 推理产品×
Atlas 推理系列产品×
Atlas 训练系列产品×

功能说明

  • 接口功能:实现光栅化计算。根据给定的三维空间中的点和面,获取屏幕中每个像素点的最小深度及其对应的面片索引,并计算该面片的重心坐标透视矫正插值。

  • 计算公式: $findices$记录每个像素点最小深度对应的面索引,$barycentric$记录每个顶点相对于$findices$中记录的面的重心坐标透视矫正插值。 计算过程中使用的Z-Buffer记录每个像素点$(x, y)$的最小深度$z_{\min}(x, y)$以及该深度对应的三角形面片索引$\text{face_idx}(x, y)$。

    计算过程如下: 对空间中的每个三角形面片$f$:

    1. 将$f$的三个顶点坐标$v_0$, $v_1$, $v_2$转换为屏幕坐标$v_{s0}$,$v_{s1}$,$v_{s2}$

    2. 根据$v_{s0}$,$v_{s1}$,$v_{s2}$计算包围$f$的矩形范围

    3. 对矩形内每个像素点$v_i = (x_i, y_i)$,执行以下操作:

      a. 计算像素中心坐标$v_c$
      b. 计算$v_c$相对于三角形$f$的重心坐标$(\alpha, \beta, \gamma)$
      c. 根据$(\alpha, \beta, \gamma)$判断$v_c$是否在三角形内部。若$v_c$不在三角形内部,则处理矩形内下个像素点,否则执行下述步骤
      d. 使用$(\alpha, \beta, \gamma)$和$v_{s0}$,$v_{s1}$,$v_{s2}$得到当前像素的深度值depth
      e. 若启用了深度先验;否则,直接执行下一步“Z-Buffer更新”

      • 使用深度先验图计算深度阈值depth_thres
      • 如果depth < depth_thres,处理矩形内下个像素点,否则执行下述步骤

      f. Z-Buffer更新:

      • 若$depth < z_{\min}(x_i, y_i)$:

      $$ \quad z_{\min}(x_i, y_i) \gets \text{depth} \ \quad \text{face_idx}(x_i, y_i) \gets f $$

      • 若$depth = z_{\min}(x_i, y_i)$:

      $$ \quad \text{face_idx}(x_i, y_i) \gets \min(\text{face_idx}(x_i, y_i),\ f) $$

    按上述步骤对空间中所有的三角形面片进行处理后,对大小为$height * width$的屏幕上每个像素点$v_i = (x_i, y_i)$:

    1. 取Z-Buffer中$v_i$对应的面片索引$f_{idx}$,$findices (x_i, y_i) \gets f_{idx}$
    2. 将$f$的三个顶点坐标$v_0$,$v_1$,$v_2$转换为屏幕坐标$v_{s0}$,$v_{s1}$,$v_{s2}$
    3. 计算$v_i$的中心点坐标$v_c$
    4. 计算$v_c$相对于三角形$f$的重心坐标$(\alpha, \beta, \gamma)$
    5. 使用$(\alpha, \beta, \gamma)$计算透视矫正插值$(\tilde{\alpha}, \tilde{\beta}, \tilde{\gamma})$
    6. $barycentric(x_i, y_i) \gets (\tilde{\alpha}, \tilde{\beta}, \tilde{\gamma})$

    以下是涉及的各种具体计算方法:

    • 顶点$v = (x, y, z, w)$转换为屏幕坐标$v_s = (x_s, y_s, z_s)$

      $$ x_s = (x / w * 0.5 + 0.5) * (width - 1) + 0.5\ y_s = (0.5 + 0.5 * y / w) * (height - 1) + 0.5\ z_s = z / w * 0.49999 + 0.5 $$

    • 点$v$相对于三角形 $(v_0, v_1, v_2)$的重心坐标$(\alpha, \beta, \gamma)$

      1. 分别计算计算三角形$(v_0, v_1, v_2)$、$(v_0, v, v_2)$和$(v_0, v_1, v)$的有向面积$area$、$beta_tri$和$gamma_tri$
      2. 若$area$为0,则$\alpha = \beta = \gamma = -1$, 否则

      $$ \beta = beta_tri / area\ \gamma = gamma_tri / area\ \alpha = 1 - \beta - \gamma $$

    • 由顶点$v_0 = (x_0, y_0, z_0)$, $v_1 = (x_1, y_1, z_1)$和$v_2 = (x_2, y_2, z_2)$组成的三角形的有向面积

      $$ area = (x_2 - x_0) * (y_1 - y_0) - (x_1 - x_0) * (y_2 - y_0) $$

    • 结合重心坐标$(\alpha, \beta, \gamma)$和三角形屏幕坐标$v_0 = (x_0, y_0, z_0)$, $v_1 = (x_1, y_1, z_1)$和$v_2 = (x_2, y_2, z_2)$计算像素点$v = (x, y)$ 的深度$depth$

      $$ depth = \alpha * z_0 + \beta * z_1 + \gamma * z_2 $$

    • 结合深度图$d$,遮挡截断$occlusion_truncation$计算点$v = (x, y)$的深度阈值$depth_thres$

      $$ depth_thres = d(x, y) * 0.49999 + 0.5 + occlusion_truncation $$

    • 根据重心坐标$(\alpha, \beta, \gamma)$判断顶点是否在三角形内 如果$\alpha >= 0$且$\beta >= 0$且$\gamma >= 0$则点在三角形内(包括在三角形边上),否则点不在三角形内。

    • 结合重心坐标$(\lambda_0, \lambda_1, \lambda_2)$以及三角形的三个顶点坐标$v_0 = (x_0, y_0, z_0, w_0)$, $v_1 = (x_1, y_1, z_1, w_1)$和$v_2 = (x_2, y_2, z_2, w_2)$计算透视矫正插值$(\lambda_0^{corrected}, \lambda_1^{corrected}, \lambda_2^{corrected})$

      $$ \lambda_i^{corrected} = \frac{\lambda_i / w_i} { \sum (\lambda_j / w_j)} $$

函数原型

每个算子分为两段式接口,必须先调用“aclnnRasterizerGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnRasterizer”接口执行计算。

aclnnStatus aclnnRasterizerGetWorkspaceSize( const aclTensor *v, const aclTensor *f, const aclTensor *dOptional, int64_t width, int64_t height, double occlusionTruncation, int64_t useDepthPrior, const aclTensor *findicesOut, const aclTensor *barycentricOut, uint64_t *workspaceSize, aclOpExecutor **executor)
aclnnStatus aclnnRasterizer( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)

aclnnRasterizerGetWorkspaceSize

  • 参数说明

    参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensor
    v(aclTensor*)输入表示空间中顶点坐标的输入张量。
    • 不支持空Tensor。
    • shape为(numVertices, 4),其中numVertices表示顶点数量,为正整数。每个顶点坐标表示为(x, y, z, w)。
    FLOAT32ND2×
    f(aclTensor*)输入表示空间中的面的输入张量。
    • 不支持空Tensor。
    • shape为(numFaces, 3),其中 numFaces表示空间中面的数量,为正整数。每个面是一个三角形,三角形每个顶点表示为顶点在v中的索引,因此f中元素取值应当是对v中元素的合法索引,即取值范围为[0, numVertices-1]。由调用者保证f中元素合法。
    INT32ND2×
    dOptional(aclTensor*)输入表示深度图的输入张量,用于计算深度阈值。
    • 可选输入,支持空Tensor。
    • 此参数不生效。
    FLOAT32ND2×
    width(int64_t)输入屏幕宽度。取值范围[1, 4096]。----
    height(int64_t)输入屏幕高度。取值范围[1, 4096]。----
    occlusionTruncation(double)输入遮挡截断,用于计算深度阈值。此参数不生效。----
    useDepthPrior(int64_t)输入表示是否应用深度先验。
    • 值为0或1。1表示应用深度先验,0表示不应用深度先验。
    • 当前算子不支持应用深度先验,因此值固定为0。
    ----
    findicesOut(aclTensor*)输出表示屏幕中每个像素点最小深度对应的面的索引。
    • 不支持空Tensor。
    • shape为(height, width),其中height是屏幕高度,width是屏幕宽度。
    INT32ND2×
    barycentricOut(aclTensor*)输出表示屏幕中每个像素点相对于最小深度对应的面的重心坐标透视矫正插值的输出张量。
    • 不支持空Tensor。
    • shape为(height, width, 3),其中height是屏幕高度,width是屏幕宽度。
    FLOAT32ND3×
    workspaceSize(uint64_t*)输出返回需要在Device侧申请的workspace大小。-----
    executor(aclOpExecutor**)输出返回op执行器,包含了算子计算流程。-----
  • 返回值

    aclnnStatus:返回状态码,具体参见aclnn返回码。

    第一段接口完成入参校验,出现以下场景时报错:

    返回码错误码描述
    ACLNN_ERR_PARAM_NULLPTR161001传入的v、f、findicesOut或barycentricOut是空指针。
    ACLNN_ERR_PARAM_INVALID161002v、f、findicesOut或barycentricOut的数据类型不在支持范围之内。
    ACLNN_ERR_INNER_TILING_ERROR561002v、f、findicesOut或barycentricOut的shape不在支持范围之内。
    useDepthPrior、height或width取值不在支持范围之内。

aclnnRasterizer

  • 参数说明

    参数名输入/输出描述
    workspace输入在Device侧申请的workspace内存地址。
    workspaceSize输入在Device侧申请的workspace大小,由第一段接口aclnnRasterizerGetWorkspaceSize获取。
    executor输入op执行器,包含了算子计算流程。
    stream输入指定执行任务的Stream。
  • 返回值

    aclnnStatus:返回状态码,具体参见aclnn返回码。

约束说明

  • 仅支持useDepthPrior为0输入场景,参数dOptional、occlusionTruncation、useDepthPrior在实际计算中不生效。

  • 确定性计算:

    • aclnnRasterizer默认确定性实现。

调用示例

示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例。

#include <iostream> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_rasterizer.h" #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vector<int64_t> &shape) { int64_t shapeSize = 1; for (auto i : shape) { shapeSize *= i; } return shapeSize; } int Init(int32_t deviceId, aclrtStream *stream) { // 固定写法,资源初始化 auto ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); ret = aclrtSetDevice(deviceId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); ret = aclrtCreateStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); return 0; } template <typename T> int CreateAclTensor(const std::vector<T> &hostData, const std::vector<int64_t> &shape, void **deviceAddr, aclDataType dataType, aclTensor **tensor) { auto size = GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); // 计算连续tensor的strides std::vector<int64_t> strides(shape.size(), 1); for (int64_t i = shape.size() - 2; i >= 0; i--) { strides[i] = shape[i + 1] * strides[i + 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1. (固定写法)device/stream初始化,参考acl API手册 // 根据自己的实际device填写deviceId int32_t deviceId = 0; aclrtStream stream; auto ret = Init(deviceId, &stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); std::vector<int64_t> vShape = {3, 4}; std::vector<int64_t> fShape = {1, 3}; std::vector<int64_t> dShape = {10, 10}; std::vector<int64_t> findicesShape = {10, 10}; std::vector<int64_t> baryShape = {10, 10, 3}; int64_t height = 10; int64_t width = 10; float occlusionTruncation = 0.0f; int64_t useDepthPrior = 0; std::vector<float> vData = {6.0f, 4.0f, 1.0f, 6.9f, 7.0928106f, 0.3491799f, 3.0046327f, 6.6574745f, 7.308903f, 7.6934705f, 0.1315008f, 3.9899914f}; std::vector<int32_t> fData = {2, 1, 0}; std::vector<float> dData(100, 0.0f); std::vector<int32_t> findicesData(100, 0); std::vector<float> baryData(10 * 10 * 3, 0.0f); void *vDeviceAddr = nullptr; void *fDeviceAddr = nullptr; void *dDeviceAddr = nullptr; void *findicesDeviceAddr = nullptr; void *baryDeviceAddr = nullptr; aclTensor *v = nullptr; aclTensor *f = nullptr; aclTensor *d = nullptr; aclTensor *findices = nullptr; aclTensor *barycentric = nullptr; ret = CreateAclTensor(vData, vShape, &vDeviceAddr, aclDataType::ACL_FLOAT, &v); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(fData, fShape, &fDeviceAddr, aclDataType::ACL_INT32, &f); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(dData, dShape, &dDeviceAddr, aclDataType::ACL_FLOAT, &d); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(findicesData, findicesShape, &findicesDeviceAddr, aclDataType::ACL_INT32, &findices); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(baryData, baryShape, &baryDeviceAddr, aclDataType::ACL_FLOAT, &barycentric); CHECK_RET(ret == ACL_SUCCESS, return ret); // 3. 调用CANN算子库API,需要修改为具体的API名称 uint64_t workspaceSize = 0; aclOpExecutor *executor; // 调用aclnnRasterizer第一段接口 ret = aclnnRasterizerGetWorkspaceSize(v, f, d, width, height, occlusionTruncation, useDepthPrior, findices, barycentric, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRasterizerGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 void *workspaceAddr = nullptr; if (workspaceSize > 0) { ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); } // 调用aclnnRasterizer第二段接口 ret = aclnnRasterizer(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRasterizer failed. ERROR: %d\n", ret); return ret); // 4. (固定写法)同步等待任务执行结束 ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 auto findicesSize = GetShapeSize(findicesShape); std::vector<int32_t> findicesOutData(findicesSize, 0); ret = aclrtMemcpy(findicesOutData.data(), findicesSize * sizeof(findicesOutData[0]), findicesDeviceAddr, findicesSize * sizeof(findicesOutData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); auto barycentricSize = GetShapeSize(baryShape); std::vector<float> baryOutData(barycentricSize, 0); ret = aclrtMemcpy(baryOutData.data(), barycentricSize * sizeof(baryOutData[0]), baryDeviceAddr, barycentricSize * sizeof(baryOutData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); for (int64_t i = 0; i < findicesSize; i++) { LOG_PRINT("findices[%ld] is: %d\n", i, findicesOutData[i]); } for (int64_t i = 0; i < barycentricSize; i++) { LOG_PRINT("barycentric[%ld] is: %f\n", i, baryOutData[i]); } // 6. 释放aclTensor,需要根据具体API的接口定义修改 aclDestroyTensor(v); aclDestroyTensor(f); aclDestroyTensor(d); aclDestroyTensor(findices); aclDestroyTensor(barycentric); // 7. 释放device资源,需要根据具体API的接口定义修改 if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }

【免费下载链接】ops-cv本项目是CANN提供的图像处理、目标检测相关的算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-cv

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.jsqmd.com/news/782864/

相关文章:

  • 泰山派3M-RK3576-镜像烧录-成品镜像烧录
  • 吉林K式板房企业排行:5家合规供应商实测对比 - 奔跑123
  • CANN/pypto反量化函数文档
  • cann/cannbot-skills尾安全约束
  • 11.9k Star!Claude Code PPT 神器:本机一行命令,AI 出真还能编辑!
  • 2026新疆财务凭证纸厂家对比:绿色认证资质如何影响政企采购决策 - 优质企业观察收录
  • 一个人,一台电脑,月入翻倍:她如何用AI重构“旅行路书”?
  • CANN高性能线性代数算子库
  • PathAsst:多模态生成式AI如何重塑病理诊断工作流
  • 通过curl命令诊断大模型API连接与返回问题
  • CANN/ops-solver算子列表
  • CANN/HCOMM内存导入关闭API
  • Hermes Agent 应用场景想象
  • CANN/community PR操作指南
  • CANN/tensorflow 后续版本废弃配置
  • 我在上海滩的奋斗
  • 口碑好的四川别墅电梯哪家专业
  • 笑不活了!兰州全城上门收金,旧金变现不用跑区县,在家躺着数钱! - 金掌柜黄金回收
  • AI时代知识工作转型:从生产到批判性整合的核心能力构建
  • AI赋能材料科学:从局域结构表征到分子相互作用预测的完整实践指南
  • 基于SHAP与XAI的3D打印工艺参数优化:从黑箱预测到可解释洞察
  • CANN/pypto eq运算API文档
  • 吉林钢结构厂家实测排行:资质与性能双维度对比 - 奔跑123
  • 2026年新疆热敏收银纸、票据印刷及办公用纸一站式采购指南 - 优质企业观察收录
  • 为内部知识库问答系统集成Taotoken多模型聚合能力
  • 吉林及周边工程总承包企业综合实力排行盘点 - 奔跑123
  • CANN/pyto gathermask函数API文档
  • CANN/runtime IPC进程间内存共享
  • 2026年新疆不干胶标签及办公用纸一站式采购指南:金阳印务官方联系与深度评测 - 优质企业观察收录
  • CANN预选赛算子测试