[test-suite] r339006 - Add Image dithering kernels using Benchmark Library

Pankaj Kukreja via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 6 04:19:13 PDT 2018


Author: proton
Date: Mon Aug  6 04:19:13 2018
New Revision: 339006

URL: http://llvm.org/viewvc/llvm-project?rev=339006&view=rev
Log:
Add Image dithering kernels using Benchmark Library

Contains Ordered and Floyd-Steinberg dithering algorithms

Reviewers: Meinersbur

Differential Revision: https://reviews.llvm.org/D49503

Added:
    test-suite/trunk/MicroBenchmarks/ImageProcessing/CMakeLists.txt
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/dither.h
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/main.cpp
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output
    test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/CMakeLists.txt?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/CMakeLists.txt (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/CMakeLists.txt Mon Aug  6 04:19:13 2018
@@ -0,0 +1 @@
+add_subdirectory(Dither)

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt Mon Aug  6 04:19:13 2018
@@ -0,0 +1,13 @@
+set(IMAGEPROC_UTILS MicroBenchmarks/ImageProcessing/utils)
+list(APPEND CPPFLAGS -I ${CMAKE_SOURCE_DIR}/${IMAGEPROC_UTILS} -std=c++11)
+
+llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh ${CMAKE_CURRENT_BINARY_DIR}/orderedOutput.txt")
+llvm_test_verify("${FPCMP} ${CMAKE_CURRENT_BINARY_DIR}/orderedOutput.txt ${CMAKE_CURRENT_SOURCE_DIR}/orderedDither.reference_output")
+
+llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh ${CMAKE_CURRENT_BINARY_DIR}/floydOutput.txt")
+llvm_test_verify("${FPCMP} ${CMAKE_CURRENT_BINARY_DIR}/floydOutput.txt ${CMAKE_CURRENT_SOURCE_DIR}/floydDither.reference_output")
+
+llvm_test_run(WORKDIR ${CMAKE_CURRENT_BINARY_DIR})
+llvm_test_executable(Dither main.cpp orderedDitherKernel.c  floydDitherKernel.c ../utils/ImageHelper.cpp ../utils/glibc_compat_rand.c)
+
+target_link_libraries(Dither benchmark)

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/dither.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/dither.h?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/dither.h (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/dither.h Mon Aug  6 04:19:13 2018
@@ -0,0 +1,15 @@
+/**
+  Pankaj Kukreja
+  github.com/proton0001
+  Indian Institute of Technology Hyderabad
+*/
+#ifndef _DITHER_H_
+#define _DITHER_H_
+
+#define MaxGray 255
+#define MXGRAY 256
+
+#define HEIGHT 512
+#define WIDTH 512
+
+#endif /* _DITHER_H_ */

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output Mon Aug  6 04:19:13 2018
@@ -0,0 +1 @@
+23473c2d34c91e33eaa3d5008ce3640e

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.c Mon Aug  6 04:19:13 2018
@@ -0,0 +1,69 @@
+/**
+  Source: https://imagej.net/Dithering
+  Modified by Pankaj Kukreja (github.com/proton0001)
+  Indian Institute of Technology Hyderabad
+*/
+#include "dither.h"
+void floydDitherKernel(int height, int width, int inputImage[HEIGHT][WIDTH],
+                       int outputImage[height][width]) {
+  for (int i = 0; i < height; i++) {
+    for (int j = 0; j < width; j++) {
+      outputImage[i][j] = inputImage[i][j];
+    }
+  }
+
+  int err;
+  int a, b, c, d;
+
+  for (int i = 1; i < height - 1; i++) {
+    for (int j = 1; j < width - 1; j++) {
+      if (outputImage[i][j] > 127) {
+        err = outputImage[i][j] - 255;
+        outputImage[i][j] = 255;
+      } else {
+        err = outputImage[i][j] - 0;
+        outputImage[i][j] = 0;
+      }
+      a = (err * 7) / 16;
+      b = (err * 1) / 16;
+      c = (err * 5) / 16;
+      d = (err * 3) / 16;
+
+      int temp1 = (outputImage[i][j + 1] + a);
+      if (temp1 > 255) {
+        outputImage[i][j + 1] = 255;
+      } else if (temp1 < 0) {
+        outputImage[i][j + 1] = 0;
+      } else {
+        outputImage[i][j + 1] = temp1;
+      }
+
+      int temp2 = (outputImage[i + 1][j + 1] + b);
+      if (temp2 > 255) {
+        outputImage[i + 1][j + 1] = 255;
+      } else if (temp2 < 0) {
+        outputImage[i + 1][j + 1] = 0;
+      } else {
+        outputImage[i + 1][j + 1] = temp2;
+      }
+
+      int temp3 = outputImage[i + 1][j + 0] + c;
+      if (temp3 > 255) {
+        outputImage[i + 1][j + 0] = 255;
+      } else if (temp3 < 0) {
+        outputImage[i + 1][j + 0] = 0;
+      } else {
+        outputImage[i + 1][j + 0] = temp3;
+      }
+
+      int temp4 = outputImage[i + 1][j - 1] + d;
+      if (temp4 > 255) {
+        outputImage[i + 1][j - 1] = 255;
+      } else if (temp4 < 0) {
+        outputImage[i + 1][j - 1] = 0;
+      } else {
+        outputImage[i + 1][j - 1] = temp4;
+      }
+    }
+  }
+}

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/main.cpp
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/main.cpp?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/main.cpp (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/main.cpp Mon Aug  6 04:19:13 2018
@@ -0,0 +1,156 @@
+/**
+  Pankaj Kukreja
+  github.com/proton0001
+  Indian Institute of Technology Hyderabad
+*/
+#include "ImageHelper.h"
+#include "dither.h"
+#include <cmath>
+#include <iostream> // std::cerr
+
+#define BENCHMARK_LIB
+#ifdef BENCHMARK_LIB
+#include "benchmark/benchmark.h"
+#endif
+
+int *inputImage;
+extern "C" {
+void orderedDitherKernel(int height, int width, int *inpImage, int *outImage,
+                         int *temp, int n, int m);
+void floydDitherKernel(int height, int width, int *inpImage, int *outImage);
+}
+int main(int argc, char **argv) {
+#ifdef BENCHMARK_LIB
+  ::benchmark::Initialize(&argc, argv);
+#endif
+
+  const char *orderedOutputFilename = (char *)"./orderedOutput.txt";
+  const char *floydOutputFilename = (char *)"./floydOutput.txt";
+  inputImage = (int *)malloc(sizeof(int) * HEIGHT * WIDTH);
+  if (inputImage == NULL) {
+    std::cerr << "Insufficient memory\n";
+    exit(1);
+  }
+  initializeRandomImage(inputImage, HEIGHT, WIDTH);
+
+#ifdef BENCHMARK_LIB
+  ::benchmark::RunSpecifiedBenchmarks();
+#endif
+  int *outputImage = (int *)malloc(sizeof(int) * HEIGHT * WIDTH);
+  int *temp = (int *)malloc(sizeof(int) * HEIGHT * WIDTH);
+  if (outputImage == NULL || temp == NULL) {
+    std::cerr << "Insufficient memory\n";
+    exit(1);
+  }
+  orderedDitherKernel(HEIGHT, WIDTH, inputImage, outputImage, temp, 16, 4);
+  saveImage(outputImage, orderedOutputFilename, HEIGHT, WIDTH);
+  floydDitherKernel(HEIGHT, WIDTH, inputImage, outputImage);
+
+  for (int i = 0; i < HEIGHT; i++) {
+    outputImage[(i)*WIDTH + 0] = 0;
+    outputImage[(i)*WIDTH + WIDTH - 1] = 0;
+  }
+
+  for (int j = 0; j < WIDTH; j++) {
+    outputImage[(0) * WIDTH + j] = 0;
+    outputImage[(HEIGHT - 1) * WIDTH + j] = 0;
+  }
+
+  saveImage(outputImage, floydOutputFilename, HEIGHT, WIDTH);
+  free(temp);
+  free(outputImage);
+  free(inputImage);
+  return EXIT_SUCCESS;
+}
+
+#ifdef BENCHMARK_LIB
+void BENCHMARK_ORDERED_DITHER(benchmark::State &state) {
+  int height = state.range(0);
+  int width = state.range(0);
+  int m = state.range(1);
+  int n = pow(m, 2);
+  int *outputImage = (int *)malloc(sizeof(int) * height * width);
+  int *temp = (int *)malloc(sizeof(int) * height * width);
+
+  if (outputImage == NULL) {
+    std::cerr << "Insufficient memory\n";
+    exit(1);
+  }
+  /* This call is to warm up the cache */
+  orderedDitherKernel(height, width, inputImage, outputImage, temp, n, m);
+
+  for (auto _ : state) {
+    orderedDitherKernel(height, width, inputImage, outputImage, temp, n, m);
+  }
+  /* Since we are not passing state.range as 20 this if case will always be
+   * false. This call is to make compiler think that outputImage may be used
+   * later so that above kernel calls will not optimize out */
+  if (state.range(0) == 20) {
+    saveImage(outputImage, (const char *)"failedCase.txt", height, width);
+  }
+  free(temp);
+  free(outputImage);
+}
+
+#if (HEIGHT < WIDTH)
+#define MINIMUM_DIM HEIGHT
+#else
+#define MINIMUM_DIM WIDTH
+#endif
+
+static void CustomArguments(benchmark::internal::Benchmark *b) {
+  int limit = MINIMUM_DIM;
+  int start = 1;
+  if (limit > 128) {
+    start = 128;
+  }
+  for (int i = start; i <= limit; i <<= 1) {
+    b->Args({i, 2});
+    b->Args({i, 3});
+    b->Args({i, 4});
+    b->Args({i, 8});
+  }
+}
+BENCHMARK(BENCHMARK_ORDERED_DITHER)
+    ->Apply(CustomArguments)
+    ->Unit(benchmark::kMicrosecond);
+
+void BENCHMARK_FLOYD_DITHER(benchmark::State &state) {
+
+  int height = state.range(0);
+  int width = state.range(0);
+
+  int *outputImage = (int *)malloc(sizeof(int) * height * width);
+
+  if (outputImage == NULL) {
+    std::cerr << "Insufficient memory\n";
+    exit(1);
+  }
+  /* This call is to warm up the cache */
+  floydDitherKernel(height, width, inputImage, outputImage);
+  for (auto _ : state) {
+    floydDitherKernel(height, width, inputImage, outputImage);
+  }
+  /* Since we are not passing state.range as 20 this if case will always be
+   * false. This call is to make compiler think that outputImage may be used
+   * later so that above kernel calls will not optimize out */
+  if (state.range(0) == 20) {
+    saveImage(outputImage, (const char *)"failedCase.txt", height, width);
+  }
+
+  free(outputImage);
+}
+
+#if MINIMUM_DIM > 128
+BENCHMARK(BENCHMARK_FLOYD_DITHER)
+    ->RangeMultiplier(2)
+    ->Range(128, MINIMUM_DIM)
+    ->Unit(benchmark::kMicrosecond);
+#else
+BENCHMARK(BENCHMARK_FLOYD_DITHER)
+    ->RangeMultiplier(2)
+    ->Range(1, MINIMUM_DIM)
+    ->Unit(benchmark::kMicrosecond);
+#endif
+
+#endif

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output Mon Aug  6 04:19:13 2018
@@ -0,0 +1 @@
+7b339ccc04bbaebf30f44f4f3129756f

Added: test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c?rev=339006&view=auto
==============================================================================
--- test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c (added)
+++ test-suite/trunk/MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.c Mon Aug  6 04:19:13 2018
@@ -0,0 +1,72 @@
+/**
+  Source: github -> https://github.com/brianwu02/ImageProcessing.git
+  Modified by Pankaj Kukreja (github.com/proton0001)
+  Indian Institute of Technology Hyderabad
+*/
+#include "dither.h"
+#include <math.h> // pow
+
+#define GAMMA 0.5
+
+void orderedDitherKernel(int height, int width, int inputImage[HEIGHT][WIDTH],
+                         int outputImage[height][width],
+                         int temp[height][width], int n, int m) {
+  int scale;
+
+  for (int i = 0; i < height; i++) {
+    for (int j = 0; j < width; j++) {
+      temp[i][j] =
+          (int)(pow((double)inputImage[i][j] / 255.0, (1.0 / GAMMA)) * 255.0);
+    }
+  }
+
+  scale = 256 / n;
+  for (int i = 0; i < height; i++) {
+    for (int j = 0; j < width; j++) {
+      outputImage[i][j] = (int)(scale * (temp[i][j] / scale)) / scale;
+    }
+  }
+
+  if (m == 2) {
+    int dither[2][2] = {{0, 2}, {3, 1}};
+    for (int y = 0; y < height; y++) {
+      for (int x = 0; x < width; x++) {
+        int i = x % m;
+        int j = y % m;
+        outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+      }
+    }
+  } else if (m == 3) {
+    int dither[3][3] = {{6, 8, 4}, {1, 0, 3}, {5, 2, 7}};
+    for (int y = 0; y < height; y++) {
+      for (int x = 0; x < width; x++) {
+        int i = x % m;
+        int j = y % m;
+        outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+      }
+    }
+  } else if (m == 4) {
+    int dither[4][4] = {
+        {0, 8, 2, 10}, {12, 4, 14, 6}, {3, 11, 1, 9}, {15, 7, 13, 5}};
+    for (int y = 0; y < height; y++) {
+      for (int x = 0; x < width; x++) {
+        int i = x % m;
+        int j = y % m;
+        outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+      }
+    }
+  } else if (m == 8) {
+    int dither[8][8] = {
+        {0, 48, 12, 60, 3, 51, 15, 63}, {32, 16, 44, 28, 35, 19, 47, 31},
+        {8, 56, 4, 52, 11, 59, 7, 55},  {40, 24, 36, 20, 43, 27, 39, 23},
+        {2, 50, 14, 62, 1, 49, 13, 61}, {34, 18, 46, 30, 33, 17, 45, 29},
+        {10, 58, 6, 54, 9, 57, 5, 53},  {42, 26, 38, 22, 41, 25, 37, 21}};
+    for (int y = 0; y < height; y++) {
+      for (int x = 0; x < width; x++) {
+        int i = x % m;
+        int j = y % m;
+        outputImage[y][x] = ((outputImage[y][x] > dither[i][j]) ? 255 : 0);
+      }
+    }
+  }
+}




More information about the llvm-commits mailing list