Index: MicroBenchmarks/ImageProcessing/Blur/CMakeLists.txt =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/CMakeLists.txt +++ MicroBenchmarks/ImageProcessing/Blur/CMakeLists.txt @@ -0,0 +1,15 @@ +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}/boxBlurOutput.txt") +llvm_test_verify("${FPCMP} ${CMAKE_CURRENT_BINARY_DIR}/boxBlurOutput.txt ${CMAKE_CURRENT_SOURCE_DIR}/boxBlur.reference_output") + +llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh ${CMAKE_CURRENT_BINARY_DIR}/gaussianBlurOutput.txt") +llvm_test_verify("${FPCMP} ${CMAKE_CURRENT_BINARY_DIR}/gaussianBlurOutput.txt ${CMAKE_CURRENT_SOURCE_DIR}/gaussianBlur.reference_output") + +llvm_test_run(WORKDIR ${CMAKE_CURRENT_BINARY_DIR}) + +llvm_test_executable(blur ../utils/ImageHelper.cpp ../utils/glibc_compat_rand.c main.cpp boxBlurKernel.c gaussianBlurKernel.c) + +target_link_libraries(blur benchmark) Index: MicroBenchmarks/ImageProcessing/Blur/blur.h =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/blur.h +++ MicroBenchmarks/ImageProcessing/Blur/blur.h @@ -0,0 +1,15 @@ +/** +Pankaj Kukreja +github.com/proton0001 +Indian Institute of Technology Hyderabad +*/ + +#ifndef _BOX_BLUR_H +#define _BOX_BLUR_H + +#define HEIGHT 1024 +#define WIDTH 1024 + +#define BOX_SIZE 9 + +#endif /* _BOX_BLUR_H */ Index: MicroBenchmarks/ImageProcessing/Blur/boxBlur.reference_output =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/boxBlur.reference_output +++ MicroBenchmarks/ImageProcessing/Blur/boxBlur.reference_output @@ -0,0 +1 @@ +d976614a6d0487da6873eb9de4044480 Index: MicroBenchmarks/ImageProcessing/Blur/boxBlurKernel.c =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/boxBlurKernel.c +++ MicroBenchmarks/ImageProcessing/Blur/boxBlurKernel.c @@ -0,0 +1,26 @@ +/** +Blur an Image using box blur + +Pankaj Kukreja +Indian Institute of Technology Hyderabad +*/ + +#include "blur.h" +void boxBlurKernel(int height, int width, int inputImage[HEIGHT][WIDTH], + int outputImage[height][width]) { + int sum = 0; + int offset = (BOX_SIZE - 1) / 2; + int n = BOX_SIZE * BOX_SIZE; + + for (int i = offset; i < height - offset; i++) { + for (int j = offset; j < width - offset; j++) { + sum = 0; + for (int k = -1 * offset; k < offset; k++) { + for (int l = -1 * offset; l < offset; l++) { + sum += inputImage[i + k][j + l]; + } + } + outputImage[i][j] = (sum) / (n); + } + } +} \ No newline at end of file Index: MicroBenchmarks/ImageProcessing/Blur/gaussianBlur.reference_output =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/gaussianBlur.reference_output +++ MicroBenchmarks/ImageProcessing/Blur/gaussianBlur.reference_output @@ -0,0 +1 @@ +7f4246596bcfbb5e6e44cd21ddfeaf07 Index: MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.c =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.c +++ MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.c @@ -0,0 +1,45 @@ +/** +Gaussian Blur Kernel + +Pankaj Kukreja +github.com/proton0001 +Indian Institute of Technology Hyderabad +*/ + +#include "blur.h" +#include // For M_PI and exp + +void gaussianBlurKernel(int height, int width, int inputImage[height][width], + int outputImage[height][width]) { + + float sigma = 9; + float s = 2.0 * sigma * sigma; + int offset = (BOX_SIZE - 1) / 2; + + float sum = 0; + float gaussianFilter[BOX_SIZE][BOX_SIZE] = {0}; + + for (int x = -1 * offset; x <= offset; x++) { + for (int y = -1 * offset; y <= offset; y++) { + gaussianFilter[x + offset][y + offset] = + (exp(-(x * x + y * y) / s)) / (M_PI * s); + sum += gaussianFilter[x + offset][y + offset]; + } + } + + float sum_in_current_frame = 0; + for (int i = offset; i < height - offset; i++) { + for (int j = offset; j < width - offset; j++) { + /* Computing sum of (elements * corresponding gaussianFilter) in window + * centered at i,j */ + sum_in_current_frame = 0; + for (int k = -1 * offset; k <= offset; k++) { + for (int l = -1 * offset; l <= offset; l++) { + sum_in_current_frame += (inputImage[i + k][j + l] * + gaussianFilter[k + offset][l + offset]); + } + } + outputImage[i][j] = (sum_in_current_frame) / sum; + } + } +} Index: MicroBenchmarks/ImageProcessing/Blur/main.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/main.cpp +++ MicroBenchmarks/ImageProcessing/Blur/main.cpp @@ -0,0 +1,190 @@ +/** +Pankaj Kukreja +github.com/proton0001 +Indian Institute of Technology Hyderabad +*/ + +#include "ImageHelper.h" +#include "blur.h" +#include + +#define BENCHMARK_LIB +#ifdef BENCHMARK_LIB +#include "benchmark/benchmark.h" +#endif +extern "C" void boxBlurKernel(int height, int width, int *inpImage, + int *outpImage); +extern "C" void gaussianBlurKernel(int height, int width, int *inpImage, + int *outpImage); +int *inputImage; +int main(int argc, char *argv[]) { + +#ifdef BENCHMARK_LIB + ::benchmark::Initialize(&argc, argv); +#endif + + const char *boxBlurOutputFileName = (const char *)"./boxBlurOutput.txt"; + const char *gaussianBlurOutputFileName = + (const char *)"./gaussianBlurOutput.txt"; + + inputImage = (int *)malloc(sizeof(int) * (HEIGHT) * (WIDTH)); + + if (inputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + initializeRandomImage(inputImage, HEIGHT, WIDTH); + +// Run Kernels Using Benchmark Library +#ifdef BENCHMARK_LIB + ::benchmark::RunSpecifiedBenchmarks(); +#endif + + // Run Kernels once more and save output in a file for Verification + int *outputImage; + outputImage = (int *)malloc(sizeof(int) * (HEIGHT) * (WIDTH)); + + if (outputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + boxBlurKernel(HEIGHT, WIDTH, inputImage, outputImage); + + // Blur not applied on edges so we add a black border + // Otherwise we may get garbage value which may create problem in output + // verification + + int offset = (BOX_SIZE - 1) / 2; + // Top Edge + for (int i = 0; i < offset; i++) { + for (int j = 0; j < WIDTH; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + + // Bottom Edge + for (int i = HEIGHT - offset; i < HEIGHT; i++) { + for (int j = 0; j < WIDTH; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + + // Left Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = 0; j < offset; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + // Right Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = WIDTH - offset; j < WIDTH; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + + saveImage(outputImage, boxBlurOutputFileName, HEIGHT, WIDTH); + + gaussianBlurKernel(HEIGHT, WIDTH, inputImage, outputImage); + + // Top Edge + for (int i = 0; i < offset; i++) { + for (int j = 0; j < WIDTH; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + + // Bottom Edge + for (int i = HEIGHT - offset; i < HEIGHT; i++) { + for (int j = 0; j < WIDTH; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + + // Left Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = 0; j < offset; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + // Right Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = WIDTH - offset; j < WIDTH; j++) { + outputImage[i * WIDTH + j] = 0; + } + } + + saveImage(outputImage, gaussianBlurOutputFileName, HEIGHT, WIDTH); + + free(outputImage); + free(inputImage); + return EXIT_SUCCESS; +} + +#ifdef BENCHMARK_LIB +void BENCHMARK_boxBlurKernel(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); + } + + boxBlurKernel(height, width, inputImage, outputImage); + + for (auto _ : state) { + boxBlurKernel(height, width, inputImage, outputImage); + } + + if (state.range(0) == 20) { + saveImage(outputImage, (const char *)"testFailed.txt", height, width); + } + + free(outputImage); +} +BENCHMARK(BENCHMARK_boxBlurKernel) + ->Args({128, 128}) + ->Args({256, 256}) + ->Args({512, 512}) + ->Args({1024, 1024}) + ->Unit(benchmark::kMicrosecond); + +void BENCHMARK_GAUSSIAN_BLUR(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); + } + + gaussianBlurKernel(height, width, inputImage, outputImage); + + for (auto _ : state) { + gaussianBlurKernel(height, width, inputImage, outputImage); + } + + if (state.range(0) == 20) { + saveImage(outputImage, (const char *)"testFailed.txt", height, width); + } + + free(outputImage); +} + +BENCHMARK(BENCHMARK_GAUSSIAN_BLUR) + ->Args({128, 128}) + ->Args({256, 256}) + ->Args({512, 512}) + ->Args({1024, 1024}) + ->Unit(benchmark::kMicrosecond); +#endif Index: MicroBenchmarks/ImageProcessing/CMakeLists.txt =================================================================== --- MicroBenchmarks/ImageProcessing/CMakeLists.txt +++ MicroBenchmarks/ImageProcessing/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Blur)