halide编程技术指南(连载一)

本文已同步至公众号,欢迎关注。

 

Halide是一种编程语言,使得在现代机器上编写高性能图像和数组处理代码更加容易。Halide支持如下的平台:

 

CPU体系结构:X86,ARM,MIPS,Hexagon,PowerPC

操作系统:Linux,Windows,macOS,Android,iOS,Qualcomm QuRT

GPU计算API:CUDA,OpenCL,OpenGL,OpenGL计算着色器,Apple Metal,Microsoft Direct X 12

Halide并不是独立的编程语言,而是嵌入在C ++中。 这意味可以像编写c++代码一样编写halide代码,然后,可以将该表示形式编译为目标文件,或对其进行JIT编译并在同一过程中运行。

 

如果你想用普通的CPU做加速,又不想去优化算法,那么halide将是非常优秀的选择。唯一要做的,就是把算法用halide重写一遍即可。而且,halide重写的算法,就跟你正常理解的是完全一样的,不需要拐弯抹角。这在图像处理中非常有用。

 

笔者使用halide已经一年有余了,觉得很有必要对其做个介绍,尤其是使用方法的介绍。Halide的英文教程可以参考:

https://halide-lang.org/tutorials/tutorial_introduction.html

API可以参考:

https://halide-lang.org/docs/

 

但是,对于初学者来说,知道怎么用,然后去看API才是重点。

 

笔者针对官方教程做定向翻译,难懂的地方再加标注。最后手把手教你写一个图像高斯模糊的halide程序。如果你觉得中文的就是垃圾,可以去参考英文的原版。

 

第一章 基本定义

如果想用halide,只需要包含<halide.h>这个头文件即可。

#include "Halide.h"

当然,在halide中,也可以包含C语言的头文件。例如包含<stdio.h>,使用printf函数

#include <stdio.h>

我们用一个main函数来展开。

int main(int argc, char **argv) {
    // 这个主函数定义了一个图像处理通道,用于获得灰度图像的对角梯度
    // 'Func'对象代表一个处理管道,它规定了每个像素因该是怎么样的数据,可以理解为就是一幅处理后的图。例如opencv中的cv::mat
    Halide::Func gradient;

    // ‘Var’对象实际上就是类型,就像我们常说的int,float等。它本身是没有任何含义的。
    Halide::Var x, y;

    // 我们用x和y来表示图像的x轴和y轴,按照我们处理图像的惯常思维,x就是图像列的索引,y就是图像行的索引。
    // 就这些变量和其他函数而言,Func在其变量的任何整数坐标处定义为Expr。 在这里,我们将定义一个Expr,其值为x + y。 Var具有适当的运算符重载,因此“ x + y”之类的表达式成为“ Expr”对象。可以理解为表达式,或数学函数。
    Halide::Expr e = x + y;

// 现在我们为’Func’对象gradient进行定义。在x,y像素处,图像的像素值是Expr e的值。在等式的左边,就是我们定义的Func gradient对象和Vars变量x,y,在等式的右边就是用相同的Vars x,y定义的Expr e对象,
    gradient(x, y) = e;

    // 同样可以写为:
    //   gradient(x, y) = x + y;
    // 这是更为一般的形式,但是为了完整起见,在此显示中间量Expr e。
    // 该行代码定义了Func,但实际上并没有计算输出图像。在此阶段,内存中只有Funcs,Exprs和Vars,代表了我们成像管道的结构。我们正在元编程。这个C ++程序正在内存中构造一个Halide程序。而真正的像素数据计算紧随其后。

    // 现在我们“实现” Func,JIT编译一些代码以实现我们定义的管道,然后运行它。我们还需要告诉Halide评估Func的域,该域确定上述x和y的范围以及输出图像的分辨率。Halide.h还提供了我们可以使用的基本模板图像类型。例如,我们生成一个800 x 600的图像,就需要定义一个域,也就是一个模板buffer<int32_t>。
    Halide::Buffer<int32_t> output = gradient.realize(800, 600);

    // Halide确实为您键入推断。Var对象代表32位整数,因此Expr对象'x + y'也代表32位整数,因此'gradient'定义了32位图像,因此当出现以下情况时,我们得到了32位有符号整数图像 我们称之为“实现”。halide类型和类型转换规则等效于C。
    // 下面这个是验证程序,以期上面的结果跟下面展开的结果是一样的。
    for (int j = 0; j < output.height(); j++) {
        for (int i = 0; i < output.width(); i++) {
            // 我们可以使用类似的语法来定义和使用函数,来访问Buffer对象的像素。
            if (output(i, j) != i + j) {
                printf("Something went wrong!\n"
                       "Pixel %d, %d was supposed to be %d, but instead it's %d\n",
                       i, j, i+j, output(i, j));
                return -1;
            }
        }
    }
    // 一切正常! 我们定义了一个Func,然后在其上调用“ realize”以生成并运行产生Buffer的机器代码。(暂且不说)
    printf("Success!\n");
    return 0;
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Halide 是一个开源的图像处理和计算机视觉 DSL(领域特定语言),其目的是让程序员更加轻松地编写高性能的图像处理代码。Halide 的特点是具有易于使用的语法、高性能的代码生成以及可移植性。 本系列文章将介绍 Halide 的基本语法和使用方法,并通过一些实例来演示如何使用 Halide 进行图像处理和计算机视觉任务。 第一篇文章将介绍 Halide 的基本概念和安装方法。 ## 什么是 Halide? Halide 是由丹尼尔·瑞德福(Daniel R. Johnson)和 Jonathan Ragan-Kelley 在 MIT 开发的一个开源项目。它是一个用于编写高性能图像处理和计算机视觉代码的 DSL。 Halide 的主要目标是使程序员能够使用一种简单易懂的语法编写高性能的代码,而无需了解 CPU 或 GPU 的细节。Halide 支持多种平台,包括 x86、ARM、MIPS 和 PowerPC 等 CPU,以及 NVIDIA、AMD 和 ARM 等 GPU。 Halide 的核心概念是“函数”。函数可以看作是一组描述了如何对输入数据进行处理的指令集合。这些指令可以被 Halide 编译成高效的 CPU 或 GPU 代码,并在运行时执行。 ## Halide 的安装方法 Halide 可以在 Linux、macOS 和 Windows 等操作系统上运行,并且支持多种编译器,包括 GCC、Clang 和 MSVC 等。下面是在 Ubuntu 20.04 上安装 Halide 的步骤: 1. 添加 Halide 的 PPA: ``` sudo add-apt-repository ppa:halide/ppa ``` 2. 更新软件包列表: ``` sudo apt-get update ``` 3. 安装 Halide: ``` sudo apt-get install libhalide-dev ``` 安装完成后,可以使用以下命令检查 Halide 是否已经安装成功: ``` pkg-config --cflags --libs Halide ``` 如果输出了一些 Halide 相关的信息,则表示 Halide 安装成功。 ## 总结 本篇文章介绍了 Halide 的基本概念和安装方法。下一篇文章将介绍 Halide 的基本语法和使用方法。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值