Index: MicroBenchmarks/CMakeLists.txt =================================================================== --- MicroBenchmarks/CMakeLists.txt +++ MicroBenchmarks/CMakeLists.txt @@ -5,5 +5,6 @@ add_subdirectory(XRay) add_subdirectory(LCALS) add_subdirectory(harris) + add_subdirectory(ImageProcessing) endif() 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.cpp main.cpp boxBlurKernel.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 boxBlurKernel(int *inpImage, + int *outpImage, int height, int width); +void gaussianBlurKernel(int *inpImage, + int *outImage, int height, int width); + +#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.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/boxBlurKernel.cpp +++ MicroBenchmarks/ImageProcessing/Blur/boxBlurKernel.cpp @@ -0,0 +1,36 @@ +/** +Blur an Image using box blur + +Pankaj Kukreja +Indian Institute of Technology Hyderabad +*/ + +#include "blur.h" +#include +void boxBlurKernel(int *inpImage, + int *outImage, int height, int width) { + + typedef int matrix[height][width]; + + matrix *inputImage; + inputImage = (matrix*) inpImage; + + matrix *outputImage; + outputImage = (matrix*) outImage; + + 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 @@ +db123123eeca99903660974f0d8d5951 Index: MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.cpp =================================================================== --- MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.cpp +++ MicroBenchmarks/ImageProcessing/Blur/gaussianBlurKernel.cpp @@ -0,0 +1,55 @@ +/** +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 *inpImage, + int *outImage, int height, int width) { + + typedef int matrix[height][width]; + + matrix *inputImage; + inputImage = (matrix*) inpImage; + + matrix *outputImage; + outputImage = (matrix*) outImage; + + + 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,188 @@ +/** +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 * 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(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*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(inputImage, outputImage, HEIGHT, WIDTH); + + // 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(inputImage, outputImage, height, width); + + for (auto _ : state) { + boxBlurKernel(inputImage, outputImage, height, width); + } + + 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_gaussianBlurKernel(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(inputImage, outputImage, height, width); + + for (auto _ : state) { + gaussianBlurKernel(inputImage, outputImage, height, width); + } + + if (state.range(0) == 20) { + saveImage(outputImage, (const char *)"testFailed.txt", height, width); + } + + free(outputImage); +} + +BENCHMARK(BENCHMARK_gaussianBlurKernel) + ->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)