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}/meanFilterBlurOutput.txt") +llvm_test_verify("${FPCMP} ${CMAKE_CURRENT_BINARY_DIR}/meanFilterBlurOutput.txt ${CMAKE_CURRENT_SOURCE_DIR}/meanFilterBlur.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.cpp main.cpp meanFilterBlurKernel.cpp gaussianBlurKernel.cpp) + +target_link_libraries(blur benchmark) Index: MicroBenchmarks/ImageProcessing/Blur/blur.h =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/blur.h +++ MicroBenchmarks/ImageProcessing/Blur/blur.h @@ -0,0 +1,20 @@ +/** +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 + +void meanFilterBlurKernel(int inputImage[HEIGHT][WIDTH], + int outputImage[HEIGHT][WIDTH], int height, int width); +void gaussianBlurKernel(int inputImage[HEIGHT][WIDTH], + int outputImage[HEIGHT][WIDTH], int height, int width); + +#endif /* _BOX_BLUR_H */ Index: MicroBenchmarks/ImageProcessing/Blur/gaussianBlur.reference_output =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/gaussianBlur.reference_output +++ MicroBenchmarks/ImageProcessing/Blur/gaussianBlur.reference_output @@ -0,0 +1 @@ +db123123eeca99903660974f0d8d5951 Index: MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.cpp +++ MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.cpp @@ -0,0 +1,44 @@ +/** +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 inputImage[HEIGHT][WIDTH], + int outputImage[HEIGHT][WIDTH], int height, int 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,186 @@ +/** +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 + +int (*__restrict__ inputImage)[HEIGHT][WIDTH]; +int main(int argc, char *argv[]) { + +#ifdef BENCHMARK_LIB + ::benchmark::Initialize(&argc, argv); +#endif + + char *meanFilterBlurOutputFileName = (char *)"./meanFilterBlurOutput.txt"; + char *gaussianBlurOutputFileName = (char *)"./gaussianBlurOutput.txt"; + + inputImage = (int(*__restrict__)[HEIGHT][WIDTH])malloc(sizeof(int) * + (HEIGHT) * (WIDTH)); + + if (inputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + initializeRandomImage((int *)(*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(*__restrict__ outputImage)[HEIGHT][WIDTH]; + outputImage = (int(*__restrict__)[HEIGHT][WIDTH])malloc(sizeof(int) * + (HEIGHT) * (WIDTH)); + if (outputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + meanFilterBlurKernel(*inputImage, *outputImage, HEIGHT, WIDTH); + + // 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][j] = 0; + } + } + + // Bottom Edge + for (int i = HEIGHT - offset; i < HEIGHT; i++) { + for (int j = 0; j < WIDTH; j++) { + (*outputImage)[i][j] = 0; + } + } + + // Left Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = 0; j < offset; j++) { + (*outputImage)[i][j] = 0; + } + } + // Right Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = WIDTH - offset; j < WIDTH; j++) { + (*outputImage)[i][j] = 0; + } + } + saveImage((int *)(*outputImage), meanFilterBlurOutputFileName, HEIGHT, WIDTH); + + gaussianBlurKernel(*inputImage, *outputImage, HEIGHT, WIDTH); + + // Top Edge + for (int i = 0; i < offset; i++) { + for (int j = 0; j < WIDTH; j++) { + (*outputImage)[i][j] = 0; + } + } + + // Bottom Edge + for (int i = HEIGHT - offset; i < HEIGHT; i++) { + for (int j = 0; j < WIDTH; j++) { + (*outputImage)[i][j] = 0; + } + } + + // Left Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = 0; j < offset; j++) { + (*outputImage)[i][j] = 0; + } + } + // Right Edge + for (int i = 0; i < HEIGHT; i++) { + for (int j = WIDTH - offset; j < WIDTH; j++) { + (*outputImage)[i][j] = 0; + } + } + + saveImage((int *)(*outputImage), gaussianBlurOutputFileName, HEIGHT, WIDTH); + + free((void *)outputImage); + free((void *)inputImage); + return EXIT_SUCCESS; +} + +#ifdef BENCHMARK_LIB +void BENCHMARK_meanFilterBlurKernel(benchmark::State &state) { + + int(*__restrict__ outputImage)[HEIGHT][WIDTH]; + outputImage = (int(*__restrict__)[HEIGHT][WIDTH])malloc(sizeof(int) * + (HEIGHT) * (WIDTH)); + if (outputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + int height = state.range(0); + int width = state.range(1); + + meanFilterBlurKernel(*inputImage, *outputImage, height, width); + + for (auto _ : state) { + meanFilterBlurKernel(*inputImage, *outputImage, height, width); + } + + if (state.range(0) == 20) { + saveImage((int *)(*outputImage), (char *)"testFailed.txt", HEIGHT, WIDTH); + } + + free((void *)outputImage); +} +BENCHMARK(BENCHMARK_meanFilterBlurKernel) + ->Args({128, 128}) + ->Args({256, 256}) + ->Args({512, 512}) + ->Args({1024, 1024}) + ->Unit(benchmark::kMicrosecond); + +void BENCHMARK_gaussianBlurKernel(benchmark::State &state) { + + int(*__restrict__ outputImage)[HEIGHT][WIDTH]; + outputImage = (int(*__restrict__)[HEIGHT][WIDTH])malloc(sizeof(int) * + (HEIGHT) * (WIDTH)); + + if (outputImage == NULL) { + std::cerr << "Insufficient memory\n"; + exit(1); + } + + int height = state.range(0); + int width = state.range(1); + gaussianBlurKernel(*inputImage, *outputImage, height, width); + + for (auto _ : state) { + gaussianBlurKernel(*inputImage, *outputImage, height, width); + } + + if (state.range(0) == 20) { + saveImage((int *)(*outputImage), (char *)"testFailed.txt", HEIGHT, WIDTH); + } + + free((void *)outputImage); +} + +BENCHMARK(BENCHMARK_gaussianBlurKernel) + ->Args({128, 128}) + ->Args({256, 256}) + ->Args({512, 512}) + ->Args({1024, 1024}) + ->Unit(benchmark::kMicrosecond); +#endif Index: MicroBenchmarks/ImageProcessing/Blur/meanFilterBlur.reference_output =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/meanFilterBlur.reference_output +++ MicroBenchmarks/ImageProcessing/Blur/meanFilterBlur.reference_output @@ -0,0 +1 @@ +d976614a6d0487da6873eb9de4044480 Index: MicroBenchmarks/ImageProcessing/Blur/meanFilterBlurKernel.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/meanFilterBlurKernel.cpp +++ MicroBenchmarks/ImageProcessing/Blur/meanFilterBlurKernel.cpp @@ -0,0 +1,26 @@ +/** +Blur an Image using Mean Filter + +Pankaj Kukreja +Indian Institute of Technology Hyderabad +*/ + +#include "blur.h" +void meanFilterBlurKernel(int inputImage[HEIGHT][WIDTH], + int outputImage[HEIGHT][WIDTH], int height, int 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/CMakeLists.txt =================================================================== --- MicroBenchmarks/ImageProcessing/CMakeLists.txt +++ MicroBenchmarks/ImageProcessing/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Blur)