Index: MicroBenchmarks/ImageProcessing/CMakeLists.txt =================================================================== --- MicroBenchmarks/ImageProcessing/CMakeLists.txt +++ MicroBenchmarks/ImageProcessing/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Dither) Index: MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt =================================================================== --- MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt +++ MicroBenchmarks/ImageProcessing/Dither/CMakeLists.txt @@ -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.cpp floydDitherKernel.cpp ../utils/ImageHelper.cpp ../utils/glibc_compat_rand.cpp) + +target_link_libraries(Dither benchmark) Index: MicroBenchmarks/ImageProcessing/Dither/dither.h =================================================================== --- MicroBenchmarks/ImageProcessing/Dither/dither.h +++ MicroBenchmarks/ImageProcessing/Dither/dither.h @@ -0,0 +1,19 @@ +/** + Pankaj Kukreja + github.com/proton0001 + Indian Institute of Technology Hyderabad +*/ +#ifndef _DITHER_H_ +#define _DITHER_H_ + +#define MaxGray 255 +#define MXGRAY 256 + +#define HEIGHT 1024 +#define WIDTH 1024 + +void orderedDitherKernel(int *src, int *dst, int height, int width, int n, + int m); +void floydDitherKernel(int *src, int *dst, int height, int width); + +#endif /* _DITHER_H_ */ Index: MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output =================================================================== --- MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output +++ MicroBenchmarks/ImageProcessing/Dither/floydDither.reference_output @@ -0,0 +1 @@ +b2452309b00bc30360700d48b641f4c3 Index: MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.cpp +++ MicroBenchmarks/ImageProcessing/Dither/floydDitherKernel.cpp @@ -0,0 +1,80 @@ +/** + Source: https://imagej.net/Dithering + + Pankaj Kukreja + github.com/proton0001 + Indian Institute of Technology Hyderabad +*/ +#include "dither.h" +void floydDitherKernel(int *inpImage, int *outImage, int height, int width) { + + typedef int inputMatrix[HEIGHT][WIDTH]; + inputMatrix *inputImage; + inputImage = (inputMatrix *)inpImage; + + typedef int outputMatrix[height][width]; + outputMatrix *outputImage; + outputImage = (outputMatrix *)outImage; + + // Copy InputImage to outputImage + 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; + } + } + } +} Index: MicroBenchmarks/ImageProcessing/Dither/main.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Dither/main.cpp +++ MicroBenchmarks/ImageProcessing/Dither/main.cpp @@ -0,0 +1,130 @@ +/** + Pankaj Kukreja + github.com/proton0001 + Indian Institute of Technology Hyderabad +*/ +#include "ImageHelper.h" +#include "dither.h" +#include // std::cerr + +#define BENCHMARK_LIB +#ifdef BENCHMARK_LIB +#include "benchmark/benchmark.h" +#endif +int *inputImage; +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; + outputImage = (int *)malloc(sizeof(int) * (HEIGHT) * (WIDTH)); + + if (outputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + orderedDitherKernel(inputImage, outputImage, HEIGHT, WIDTH, 16, 4); + saveImage(outputImage, orderedOutputFilename, HEIGHT, WIDTH); + + floydDitherKernel(inputImage, outputImage, HEIGHT, WIDTH); + + 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(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(1); + + int *outputImage; + outputImage = (int *)malloc(sizeof(int) * (height) * (width)); + + if (outputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + orderedDitherKernel(inputImage, outputImage, height, width, 16, 4); + + for (auto _ : state) { + orderedDitherKernel(inputImage, outputImage, height, width, 16, 4); + } + + if (state.range(0) == 20) { + saveImage(outputImage, (const char *)"failedCase.txt", height, width); + } + + free(outputImage); +} +BENCHMARK(BENCHMARK_ORDERED_DITHER) + ->Args({128, 128}) + ->Args({256, 256}) + ->Args({512, 512}) + ->Args({1024, 1024}) + ->Unit(benchmark::kMicrosecond); + +void BENCHMARK_FLOYD_DITHER(benchmark::State &state) { + + int height = state.range(0); + int width = state.range(1); + + int *outputImage; + outputImage = (int *)malloc(sizeof(int) * (height) * (width)); + + if (outputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + floydDitherKernel(inputImage, outputImage, height, width); + + for (auto _ : state) { + floydDitherKernel(inputImage, outputImage, height, width); + } + + if (state.range(0) == 20) { + saveImage(outputImage, (const char *)"failedCase.txt", height, width); + } + + free(outputImage); +} + +BENCHMARK(BENCHMARK_FLOYD_DITHER) + ->Args({256, 256}) + ->Args({512, 512}) + ->Args({1024, 1024}) + ->Unit(benchmark::kMicrosecond); + +#endif Index: MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output =================================================================== --- MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output +++ MicroBenchmarks/ImageProcessing/Dither/orderedDither.reference_output @@ -0,0 +1 @@ +c36c928731bafb3568f0f7c6c24a99be Index: MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.cpp +++ MicroBenchmarks/ImageProcessing/Dither/orderedDitherKernel.cpp @@ -0,0 +1,98 @@ +/** + Source: github -> https://github.com/brianwu02/ImageProcessing.git + + Pankaj Kukreja + github.com/proton0001 + Indian Institute of Technology Hyderabad +*/ +#include "dither.h" +#include // pow +#include // std::cerr + +#define GAMMA 0.5 + +void orderedDitherKernel(int *inpImage, int *outImage, int height, int width, + int n, int m) { + int scale; + + typedef int inputMatrix[HEIGHT][WIDTH]; + inputMatrix *inputImage; + inputImage = (inputMatrix *)inpImage; + + typedef int outputMatrix[height][width]; + outputMatrix *outputImage; + outputImage = (outputMatrix *)outImage; + + outputMatrix *tmp_out; + tmp_out = (outputMatrix *)malloc(sizeof(outputMatrix)); + + if (tmp_out == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + (*tmp_out)[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 * ((*tmp_out)[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); + } + } + } else { + std::cerr << " Error: selected m not allowed, choose m from [2, 3, 4, 8]\n"; + } + free((void *)tmp_out); +}