Halide 入門教程第一講:熟悉Funcs,Vars和Exprs
阿新 • • 發佈:2018-12-01
// 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; }