1. 程式人生 > >Halide 入門教程第一講:熟悉Funcs,Vars和Exprs

Halide 入門教程第一講:熟悉Funcs,Vars和Exprs

// Halide tutorial lesson 1: Getting started with Funcs, Vars, and Exprs
// Halide入門教程第一課:瞭解Funcs(函式),Vars(變數)和Exprs(表示式)
// This lesson demonstrates basic usage of Halide as a JIT compiler for imaging.
// 本課演示了Halide作為影象處理JIT compiler(即時編譯器)的一些基本用法

// On linux, you can compile and run it like so:
// 在linux作業系統上,你可以按照如下方式進行編譯和執行
// g++ lesson_01*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_01 -std=c++11
// LD_LIBRARY_PATH=../bin ./lesson_01

// On os x:
// g++ lesson_01*.cpp -g -I ../include -L ../bin -lHalide -o lesson_01 -std=c++11
// DYLD_LIBRARY_PATH=../bin ./lesson_01



// If you have the entire Halide source tree, you can also build it by running
// 如果你有整個Halide程式碼樹,你可以按照如下方式進行編譯
//    make tutorial_lesson_01_basics
// in a shell with the current directory at the top of the halide
// source tree.

// The only Halide header file you need is Halide.h. It includes all of Halide.
// Halide.h包含了整個Halide, 只需要include這個標頭檔案即可

#include "Halide.h"

// We'll also include stdio for printf.

#include <stdio.h>

int main(int argc, char **argv) {

// This program defines a single-stage imaging pipeline that
// outputs a grayscale diagonal gradient.

// A 'Func' object represents a pipeline stage. It's a pure function that defines what
// value each pixel should have. You can think of it as a computed image.
// Func物件表示了一個pipeline stage(一級流水線。一個較為完整的影象處理系統,可看成
//為一條流水線。流水線中的每一個處理模組,為一級流水線)。它是一個純函式,定義了每
// 個畫素點對應的值。可以理解為計算出的影象。

    Halide::Func gradient;

// Var objects are names to use as variables in the definition of a Func.
// They have no meaning by themselves.
// Var物件是Func定義域中的變數名,或者說是Func的引數。它們本身沒有意義。Var用來
//索引函式(影象)對應的畫素點,如:

    Halide::Var x, y;

// We typically use Vars named 'x' and 'y' to correspond to the x
// and y axes of an image, and we write them in that order. If
// you're used to thinking of images as having rows and columns,
// then x is the column index, and y is the row index.
// x和y分別對應著影象的x軸和y軸,x對應的是列索引,y對應著行索引
// -------------> x axes
// |
// |
// |
// v
// y axes

// Funcs are defined at any integer coordinate of its variables as
// an Expr in terms of those variables and other functions.
// Here, we'll define an Expr which has the value x + y. Vars have
// appropriate operator overloading so that expressions like
// 'x + y' become 'Expr' objects.
// 函式定義在整數座標處,函式值是變數和其他函式的表示式Expr的結果。
// 在此我們定義了一個 x + y的表示式。變數過載了算數運算子,使得變數運算的結果
// 為一個Expr物件,如

    Halide::Expr e = x + y;

    // Now we'll add a definition for the Func object. At pixel x, y,
    // the image will have the value of the Expr e. On the left hand
    // side we have the Func we're defining and some Vars. On the right
    // hand side we have some Expr object that uses those same Vars.

// 現在我們將給函式物件一個定義的實現。在畫素點座標(x,y)處,影象的畫素值
//為表示式e的值。
// 表示式左邊是我們正在定義的函式物件和一些變數位於,表示式的右邊是一些
//使用相同變數的Expr物件。

// gradient(x, y) = e 相當於在(x,y)處的畫素值是表示式x+y的運算結果。

    gradient(x, y) = e;

    // This is the same as writing:
    //
    //   gradient(x, y) = x + y;
    //
    // which is the more common form, but we are showing the
    // intermediate Expr here for completeness.

    // That line of code defined the Func, but it didn't actually
    // compute the output image yet. At this stage it's just Funcs,
    // Exprs, and Vars in memory, representing the structure of our
    // imaging pipeline. We're meta-programming. This C++ program is
    // constructing a Halide program in memory. Actually computing
    // pixel data comes next.

// 上述幾行程式碼定義了Func,但實際上並沒有計算輸出影象。在這個階段,它僅僅
//是代表我們的影象流水線級的記憶體中的函式、表示式和變數。
// 我們在進行超程式設計。C++程式正在記憶體中構造Halide程式。實際上進行畫素資料
// 計算的在下一階段進行。

    // Now we 'realize' the Func, which JIT compiles some code that
    // implements the pipeline we've defined, and then runs it.  We
    // also need to tell Halide the domain over which to evaluate the
    // Func, which determines the range of x and y above, and the
    // resolution of the output image. Halide.h also provides a basic
    // templatized image type we can use. We'll make an 800 x 600
    // image.

// 在此,我們‘實現’(realize)前一個階段定義的Func,即時編譯器編譯我們定義的實現流水線級的程式碼,然後執行。
// 我們需要告訴Halide在指定的影象域(domain)內進行Func計算(這裡的域可以理解為一幅影象內指定的一個視窗)。domain決定了前面定義的x,y變數的範圍,輸出影象的解析度等。
// Halide.h提供了可供使用的一些基本的影象型別模板。

// 在此,我們將生成一幅800x600的影象。

    Halide::Buffer<int32_t> output = gradient.realize(800, 600);

    // Halide does type inference for you. Var objects represent
    // 32-bit integers, so the Expr object 'x + y' also represents a
    // 32-bit integer, and so 'gradient' defines a 32-bit image, and
    // so we got a 32-bit signed integer image out when we call
    // 'realize'. Halide types and type-casting rules are equivalent
    // to C.

    // Halide能夠進行資料型別推斷。Var物件為32位(有符號)整數,則Expr物件x+y也是32位整數(理論上應該是33位整數),
    // 因此,gradient定義了一幅32位的影象。在我們呼叫了realize之後,得到一幅32位有符號整數影象輸出。
    // Halide的型別轉換規則和C語言的型別轉換一致。

// Let's check everything worked, and we got the output we were expecting:
    for (int j = 0; j < output.height(); j++) {
        for (int i = 0; i < output.width(); i++) {
            // We can access a pixel of an Buffer object using similar
            // syntax to defining and using functions.
            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;
            }
        }
    }



    // Everything worked! We defined a Func, then called 'realize' on
    // it to generate and run machine code that produced a Buffer.
    printf("Success!\n");

    return 0;

}