OpenCL を使って 画像のヒストグラムを計算する

###　画像のヒストグラム

画像のヒストグラム(Image histogram) は、明度やRGBの階調値の発生頻度発生頻度を示す統計データです。
棒グラフで可視化することが多い。
画像の特徴を表すものとして、多くの画像編集ソフトで表示できる。
下図は GIMP の例
!![hisogram_gimpの_small.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/f9241a55-3db5-a6d7-4bc6-08e1c09bb556.png)

[wikipedia: Image histogram](https://en.wikipedia.org/wiki/Image_histogram)

[wikipedia: ヒストグラム](https://ja.wikipedia.org/wiki/%E3%83%92%E3%82%B9%E3%83%88%E3%82%B0%E3%83%A9%E3%83%A0)

### ヒストグラムを計算するサンプルコード

github に公開されているものを試す。
https://github.com/bgaster/opencl-book-samples/tree/master/src/Chapter_14/histogram

このサンプルでは、２段階で計算する。
(1) 画像をタイルに分割して、タイルごとの部分値を並列計算する。
(2) 部分値を合計する。 

部分値は、ホスト側からアクセスせず、
ターゲット側からアクセスする　読み書き可能なメモリ領域に格納する。
模式的には下図のようになる。
![memory_model.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/5bf1d899-f566-6d88-b827-82ceebe63bd8.png)

ホスト側

```histogram.cpp

    partial_histogram_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, num_groups*257*3*sizeof(unsigned int), NULL, &err);

    clSetKernelArg(histogram_rgba_unorm8, 0, sizeof(cl_mem), &input_image_unorm8);
    clSetKernelArg(histogram_rgba_unorm8, 1, sizeof(int), &NUM_PIXELS_PER_WORK_ITEM);
    clSetKernelArg(histogram_rgba_unorm8, 2, sizeof(cl_mem), &partial_histogram_buffer);

    clSetKernelArg(histogram_sum_partial_results_unorm8, 0, sizeof(cl_mem), &partial_histogram_buffer);
    clSetKernelArg(histogram_sum_partial_results_unorm8, 1, sizeof(int), &num_groups);
    clSetKernelArg(histogram_sum_partial_results_unorm8, 2, sizeof(cl_mem), &histogram_buffer);
```

ターゲット側

```image_histogram.c

kernel
void histogram_image_rgba_unorm8(image2d_t img, int num_pixels_per_workitem, global uint *histogram)

kernel
void histogram_sum_partial_results_unorm8(global uint *partial_histogram, int num_groups, global uint *histogram)
```

入力画像を画像ファイルから読み込むように修正したものを Github に公開した。
https://github.com/ohwada/MAC_cpp_Samples/tree/master/OpenCL-Histogram

### ヒストグラムをグラフ化する

OpenCL のプログラムは、ヒストグラムの値を計算するだけです。

python の [matplotlib](https://matplotlib.org/) を使って、棒グラフに表示する。

実行した例。
![baboon_hist_plot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/babb86d1-f74c-5349-f866-2c1a60e58982.png)

### 結果の妥当性

上記の図の妥当性を別の手段で計算作図したものと比較して検証する。

手段１: GIMP
画像編集ソフトの [GIMP](https://www.gimp.org/) でヒストグラムを表示したもの。
比較したところ、似ているのか似ていないのか、判定できず。
![comparison_gimp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/05e0ac15-dd80-2c1c-3ae0-32079cc7efbe.png)

手段２: matplotlib
matplotlib の [ hist API](https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.hist.html) で計算作図したもの。
hist API　はヒストグラムの計算と作図をまとめてやってくれる。
比較したところ似てますね。
![comparison_python.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/df324cac-dd00-a44c-1144-aee82a7b6946.png)

手段２: matplotlib
matplotlib の [ hist API](https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.hist.html) で計算作図したもの。
hist API　はヒストグラムの計算と作図をまとめてやってくれる。
比較したところ似てます。

使用した　pythonのコードはこちら。
https://github.com/ohwada/MAC_cpp_Samples/tree/master/OpenCL-Histogram/tools

手段３: OpenCV
OpenCV の [calcHist API](http://opencv.jp/opencv-2svn/cpp/imgproc_histograms.html) で計算したものを。
OpenCV の 描画API で作図したもの。
比較したところ似てます。
![comparison_ocv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/f1bd4a24-c9e9-f974-0410-a96130241274.png)

使用した OpenCV のコード はこちら。
https://github.com/ohwada/MAC_cpp_Samples/tree/master/OpenCV-Histogram