Halide入門教程02
// Halide tutorial lesson 2: Processing images
// Halide入門第二課: 處理圖像
// This lesson demonstrates how to pass in input images and manipulate
// them.
// 本課展示瞭如何讀入圖像數據,並操作像素
// On linux, you can compile and run it like so:
// 在linux操作系統,你可以按照如下方式編譯和運行該代碼
// 運行之前確保操作系統安裝了libpng和libjpeg庫,可以到對應的sourceforge上找到對應的代碼編譯安裝,
// 或者採用linux系統的包管理系統進行安裝,debian系操作系統
// sudo apt-get install libpng
// sudo apt-get install libjpeg
// g++ lesson_02*.cpp -g -I ../include -I ../tools -L ../bin -lHalide `libpng-config --cflags --ldflags` -ljpeg -lpthread -ldl -o lesson_02 -std=c++11
// LD_LIBRARY_PATH=../bin ./lesson_02
// On os x:
// g++ lesson_02*.cpp -g -I ../include -I ../tools -L ../bin -lHalide `libpng-config --cflags --ldflags` -ljpeg -o lesson_02 -std=c++11
// DYLD_LIBRARY_PATH=../bin ./lesson_02
// If you have the entire Halide source tree, you can also build it by
// running:
// make tutorial_lesson_02_input_image
// 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.
#include "Halide.h"
// Include some support code for loading pngs.
// halide_image_io.h提供了png格式圖片的讀寫函數
#include "halide_image_io.h"
using namespace Halide::Tools;
int main(int argc, char **argv) {
// This program defines a single-stage imaging pipeline that
// brightens an image.
// 該程序定義了一個階段的圖像處理pipeline,將圖像對應的像素點放大一定倍數
// 達到提升圖像亮度的目的。
// First we'll load the input image we wish to brighten.
// halide_image_io.h提供的圖像IO函數,讀入要處理的圖像數據
Halide::Buffer<uint8_t> input = load_image("images/rgb.png");
// See figures/lesson_02_input.jpg for a smaller version.
// Next we define our Func object that represents our one pipeline
// stage.
// 接下來定義Func對象,Func對象表示我們將要進行的圖像亮度提升pipeline
Halide::Func brighter;
// Our Func will have three arguments, representing the position
// in the image and the color channel. Halide treats color
// channels as an extra dimension of the image.
// 接下來定義操作圖像像素的索引,即Var(變量)x(column),y(row),c(channel)
// x,y爲座標索引,c爲顏色通道索引。
Halide::Var x, y, c;
// Normally we'd probably write the whole function definition on
// one line. Here we'll break it apart so we can explain what
// we're doing at every step.
// For each pixel of the input image.
// value表達式表示c通道(x,y)座標處的像素值
Halide::Expr value = input(x, y, c);
// Cast it to a floating point value.
// 爲了進行浮點計算,先將數據類型轉換成單精度浮點類型
value = Halide::cast<float>(value);
// Multiply it by 1.5 to brighten it. Halide represents real
// numbers as floats, not doubles, so we stick an 'f' on the end
// of our constant.
// 將c通道(x,y)座標處的像素值放大1.5倍
value = value * 1.5f;
// Clamp it to be less than 255, so we don't get overflow when we
// cast it back to an 8-bit unsigned int.
// 爲了防止數據溢出,將放大後的像素值clip到[0,255]區間,並轉換成8位無符號整型
value = Halide::min(value, 255.0f);
// Cast it back to an 8-bit unsigned integer.
value = Halide::cast<uint8_t>(value);
// Define the function.
// 定義函數,將亮度提升後的像素值,賦值給函數對象的(x,y,c)點
brighter(x, y, c) = value;
// The equivalent one-liner to all of the above is:
//
// brighter(x, y, c) = Halide::cast<uint8_t>(min(input(x, y, c) * 1.5f, 255));
//
// In the shorter version:
// - I skipped the cast to float, because multiplying by 1.5f does
// that automatically.
// - I also used an integer constant as the second argument in the
// call to min, because it gets cast to float to be compatible
// with the first argument.
// - I left the Halide:: off the call to min. It's unnecessary due
// to Koenig lookup.
// Remember, all we've done so far is build a representation of a
// Halide program in memory. We haven't actually processed any
// pixels yet. We haven't even compiled that Halide program yet.
// 上述所有操作知識在內存中建立Halide程序,告訴Halide怎麼去進行算法操作,即對算法進行了定義。
// 實際上還沒有開始進行任何像素的處理。甚至Halide程序還沒有進行編譯
// So now we'll realize the Func. The size of the output image
// should match the size of the input image. If we just wanted to
// brighten a portion of the input image we could request a
// smaller size. If we request a larger size Halide will throw an
// error at runtime telling us we're trying to read out of bounds
// on the input image.
// 現在將要實現函數。輸出圖像的尺寸必須和輸入圖像的尺寸相匹配。如果我們只想提高輸入圖像部分區域
//像素點的亮度,可以指定一個小一點的尺寸。如果需要一個更大尺寸的輸出,Halide在運行時會拋出一個
//錯誤告訴我們,邊界超出輸入圖像。
Halide::Buffer<uint8_t> output =
brighter.realize(input.width(), input.height(), input.channels());
// Save the output for inspection. It should look like a bright parrot.
// 寫下被處理過的圖像
save_image(output, "brighter.png");
// See figures/lesson_02_output.jpg for a small version of the output.
printf("Success!\n");
return 0;
}
在終端中編譯並執行代碼:
$ g++ lesson_02*.cpp -g -I ../include -I ../tools -L ../bin -lHalide `libpng-config --cflags --ldflags` -ljpeg -lpthread -ldl -o lesson_02 -std=c++11
// 注: 可以將Halide的bin目錄添加到環境變量中,或者在實驗時
// export LD_LIBRARY_PATH=../bin
// 這樣就不需要每次都指定halide動態鏈接庫所在路徑
$ ./lesson_02
輸出結果:
$ Success!
處理前圖像rgb.png
亮度提升後圖像brighter.png
流程總結:
1. 讀取待處理圖像數據
2. 定義變量,表達式
3. 定義Func,算法實現(此時只是內存中的算法,並沒有開始對像素點進行操作)
4. 算法調度,調用Func的realize成員變量,實現算法(開始對像素進行操作,進行圖像處理)
5. 將output數據寫回硬盤