diff --git a/benchmarks/ImageProcessing/BuddySepCorr2DBenchmark.cpp b/benchmarks/ImageProcessing/BuddySepCorr2DBenchmark.cpp new file mode 100644 index 00000000..b6164e95 --- /dev/null +++ b/benchmarks/ImageProcessing/BuddySepCorr2DBenchmark.cpp @@ -0,0 +1,179 @@ +//===- BuddySepCorr2DBenchmark.cpp -------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for SepCorr2D operation. +// +//===----------------------------------------------------------------------===// + +#include "Kernels.h" +#include +#include +#include +#include +#include + +using namespace cv; +using namespace std; + +Mat inputImageBuddySepCorr2D; + +float *kernelDataBuddySepCorr2DX; +float *kernelDataBuddySepCorr2DY; + +int kernelRowsBuddySepCorr2DX, kernelColsBuddySepCorr2DX, kernelRowsBuddySepCorr2DY, kernelColsBuddySepCorr2DY; + +// Define the output size. +int outputRowsBuddySepCorr2D, outputColsBuddySepCorr2D; + +// Define sizes of input, kernel, and output. +intptr_t sizesInputBuddySepCorr2D[2]; +intptr_t sizesKernelBuddySepCorr2DX[2]; +intptr_t sizesKernelBuddySepCorr2DY[2]; +intptr_t sizesOutputBuddySepCorr2D[2]; + +// Declare Boundary Options supported. +enum BoundaryOption { constant_padding, replicate_padding }; + +// Define Boundary option selected. +BoundaryOption BoundaryType2; + +void initializeBuddySepCorr2D(char **argv) { + inputImageBuddySepCorr2D = imread(argv[1], IMREAD_GRAYSCALE); + + kernelDataBuddySepCorr2DX = get<0>(kernelMap[argv[5]]); + kernelRowsBuddySepCorr2DX = get<1>(kernelMap[argv[5]]); + kernelColsBuddySepCorr2DX = get<2>(kernelMap[argv[5]]); + + kernelDataBuddySepCorr2DY = get<0>(kernelMap[argv[6]]); + kernelRowsBuddySepCorr2DY = get<1>(kernelMap[argv[6]]); + kernelColsBuddySepCorr2DY = get<2>(kernelMap[argv[6]]); + + outputRowsBuddySepCorr2D = inputImageBuddySepCorr2D.rows; + outputColsBuddySepCorr2D = inputImageBuddySepCorr2D.cols; + + sizesInputBuddySepCorr2D[0] = inputImageBuddySepCorr2D.rows; + sizesInputBuddySepCorr2D[1] = inputImageBuddySepCorr2D.cols; + + sizesKernelBuddySepCorr2DX[0] = kernelRowsBuddySepCorr2DX; + sizesKernelBuddySepCorr2DX[1] = kernelColsBuddySepCorr2DX; + + sizesKernelBuddySepCorr2DY[0] = kernelRowsBuddySepCorr2DY; + sizesKernelBuddySepCorr2DY[1] = kernelColsBuddySepCorr2DY; + + sizesOutputBuddySepCorr2D[0] = outputRowsBuddySepCorr2D; + sizesOutputBuddySepCorr2D[1] = outputColsBuddySepCorr2D; + + if (static_cast(argv[3]) == "REPLICATE_PADDING") { + BoundaryType2 = replicate_padding; + } else { + BoundaryType2 = constant_padding; + } +} + +static void Buddy_SepCorr2D_Constant_Padding(benchmark::State &state) { + // Define the MemRef descriptor for input, kernel, and output. + Img inputBuddySepCorr2D(inputImageBuddySepCorr2D); + MemRef kernelBuddySepCorr2DX(kernelDataBuddySepCorr2DX, + sizesKernelBuddySepCorr2DX); + MemRef kernelBuddySepCorr2DY(kernelDataBuddySepCorr2DY, + sizesKernelBuddySepCorr2DY); + MemRef outputBuddySepCorr2D(sizesOutputBuddySepCorr2D); + + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + // Call the MLIR Corr2D function. + dip::Sep_Corr2D(&inputBuddySepCorr2D, &kernelBuddySepCorr2DX, &kernelBuddySepCorr2DY, &outputBuddySepCorr2D, + 0 /* Center X */, 0 /* Center Y */, + dip::BOUNDARY_OPTION::CONSTANT_PADDING, + 0.0f /* Constant Value*/); + } + } +} + +static void Buddy_SepCorr2D_Replicate_Padding(benchmark::State &state) { + // Define the MemRef descriptor for input, kernel, and output. + Img inputBuddySepCorr2D(inputImageBuddySepCorr2D); + MemRef kernelBuddySepCorr2DX(kernelDataBuddySepCorr2DX, + sizesKernelBuddySepCorr2DX); + MemRef kernelBuddySepCorr2DY(kernelDataBuddySepCorr2DY, + sizesKernelBuddySepCorr2DY); + MemRef outputBuddySepCorr2D(sizesOutputBuddySepCorr2D); + + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + // Call the MLIR Sep_Corr2D function. + dip::Sep_Corr2D(&inputBuddySepCorr2D, &kernelBuddySepCorr2DX, &kernelBuddySepCorr2DY, &outputBuddySepCorr2D, + 0 /* Center X */, 0 /* Center Y */, + dip::BOUNDARY_OPTION::REPLICATE_PADDING, + 0.0f /* Constant Value*/); + } + } +} + +// Register benchmarking function. +void registerBenchmarkBuddySepCorr2D() { + if (BoundaryType2 == replicate_padding) { + BENCHMARK(Buddy_SepCorr2D_Replicate_Padding) + ->Arg(1) + ->Unit(benchmark::kMillisecond); + } else { + BENCHMARK(Buddy_SepCorr2D_Constant_Padding) + ->Arg(1) + ->Unit(benchmark::kMillisecond); + } +} + +// Generate result image. +void generateResultBuddySepCorr2D(char **argv) { + // Define the MemRef descriptor for input, kernel, and output. + Img input(inputImageBuddySepCorr2D); + MemRef kernelX(kernelDataBuddySepCorr2DX, sizesKernelBuddySepCorr2DX); + MemRef kernelY(kernelDataBuddySepCorr2DY, sizesKernelBuddySepCorr2DY); + MemRef output(sizesOutputBuddySepCorr2D); + // Run the 2D correlation. + if (static_cast(argv[3]) == "REPLICATE_PADDING") { + // Call the MLIR Corr2D function. + dip::Sep_Corr2D(&input, &kernelX, &kernelY, &output, 0 /* Center X */, 0/* Center Y */, + dip::BOUNDARY_OPTION::REPLICATE_PADDING, + 0.0f /* Constant Value*/); + } else { + // Call the MLIR Corr2D function. + dip::Sep_Corr2D(&input, &kernelX, &kernelY, &output, 0 /* Center X */, 0 /* Center Y */, + dip::BOUNDARY_OPTION::CONSTANT_PADDING, + 0.0f /* Constant Value*/); + } + +Mat outputImage(outputRowsBuddySepCorr2D, outputColsBuddySepCorr2D, CV_32FC1, + output.getData()); + + // Choose a PNG compression level + vector compressionParams; + compressionParams.push_back(IMWRITE_PNG_COMPRESSION); + compressionParams.push_back(9); + + // Write output to PNG. + bool result = false; + try { + result = imwrite("ResultBuddySepCorr2D.png", outputImage, compressionParams); + } catch (const cv::Exception &ex) { + fprintf(stderr, "Exception converting image to PNG format: %s\n", + ex.what()); + } + if (result) + cout << "Saved PNG file." << endl; + else + cout << "ERROR: Can't save PNG file." << endl; +} diff --git a/benchmarks/ImageProcessing/CMakeLists.txt b/benchmarks/ImageProcessing/CMakeLists.txt index 12dfb548..396e6aca 100644 --- a/benchmarks/ImageProcessing/CMakeLists.txt +++ b/benchmarks/ImageProcessing/CMakeLists.txt @@ -95,6 +95,8 @@ add_executable(image-processing-benchmark BuddyCorr2DBenchmark.cpp BuddyMorph2DBenchmark.cpp OpenCVMorph2DBenchmark.cpp + OpenCVSepFilter2DBenchmark.cpp + BuddySepCorr2DBenchmark.cpp ) target_include_directories(image-processing-benchmark diff --git a/benchmarks/ImageProcessing/Main.cpp b/benchmarks/ImageProcessing/Main.cpp index 3a66393e..c04909b7 100644 --- a/benchmarks/ImageProcessing/Main.cpp +++ b/benchmarks/ImageProcessing/Main.cpp @@ -28,6 +28,8 @@ void initializeBuddyMorph2D(char **); void initializeOpenCVMorph2D(char **); void initializeOpenCVFilter2D(char **); void initializeEigenConvolve2D(char **); +void initializeOpenCVSepFilter2D(char **); +void initializeBuddySepCorr2D(char **); void generateResultMLIRConv2D(); void generateResultBuddyConv2D(char **); @@ -39,6 +41,7 @@ void generateResultBuddyTopHat2D(char **); void generateResultBuddyBottomHat2D(char **); void generateResultBuddyMorphGrad2D(char **); void generateResultBuddyDilation2D(char **); +void generateResultBuddySepCorr2D(char **); void generateResultOpenCVErode2D(); void generateResultOpenCVDilate2D(); void generateResultOpenCVFilter2D(); @@ -47,6 +50,7 @@ void generateResultOpenCVClosing2D(); void generateResultOpenCVTopHat2D(); void generateResultOpenCVBottomHat2D(); void generateResultOpenCVMorphGrad2D(); +void generateResultOpenCVSepFilter2D(); void generateResultEigenConvolve2D(); void registerBenchmarkBuddyCorr2D(); @@ -57,6 +61,7 @@ void registerBenchmarkBuddyClosing2D(); void registerBenchmarkBuddyTopHat2D(); void registerBenchmarkBuddyBottomHat2D(); void registerBenchmarkBuddyMorphGrad2D(); +void registerBenchmarkBuddySepCorr2D(); void registerBenchmarkOpenCVErode2D(); void registerBenchmarkOpenCVDilate2D(); void registerBenchmarkOpenCVOpening2D(); @@ -65,10 +70,11 @@ void registerBenchmarkOpenCVTopHat2D(); void registerBenchmarkOpenCVBottomHat2D(); void registerBenchmarkOpenCVMorphGrad2D(); void registerBenchmarkOpenCVFilter2D(); +void registerBenchmarkOpenCVSepFilter2D(); // Run benchmarks. int main(int argc, char **argv) { - if (argc != 5) { + if (argc != 7) { throw std::invalid_argument( "Wrong format of command line arguments.\n" "Correct format is ./image-processing-benchmark +#include + +using namespace cv; +using namespace std; + +// Declare input image, kernel and output image. +Mat inputImageSepFilter2D, kernelFilter2DX, kernelFilter2DY, outputSepFilter2D; + +// Declare Boundary Options supported. +enum BoundaryOption { constant_padding, replicate_padding }; + +// Define Boundary option selected. +BoundaryOption OpenCVBoundaryType2; + +void initializeOpenCVSepFilter2D(char **argv) { + inputImageSepFilter2D = imread(argv[1], IMREAD_GRAYSCALE); + + kernelFilter2DX = Mat(get<1>(kernelMap[argv[5]]), get<2>(kernelMap[argv[5]]), + CV_32FC1, get<0>(kernelMap[argv[5]])); + kernelFilter2DY = Mat(get<1>(kernelMap[argv[6]]), get<2>(kernelMap[argv[6]]), + CV_32FC1, get<0>(kernelMap[argv[6]])); + + if (static_cast(argv[3]) == "REPLICATE_PADDING") { + OpenCVBoundaryType2 = replicate_padding; + } else { + OpenCVBoundaryType2 = constant_padding; + } +} + +// Benchmarking function. +static void OpenCV_SepFilter2D_Constant_Padding(benchmark::State &state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + sepFilter2D(inputImageSepFilter2D, outputSepFilter2D, CV_32FC1, kernelFilter2DX, kernelFilter2DY, + cv::Point(0, 0), 0.0, cv::BORDER_CONSTANT); + } + } +} + +static void OpenCV_SepFilter2D_Replicate_Padding(benchmark::State &state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + sepFilter2D(inputImageSepFilter2D, outputSepFilter2D, CV_32FC1, kernelFilter2DX, kernelFilter2DY, + cv::Point(0, 0), 0.0, cv::BORDER_REPLICATE); + } + } +} + +// Register benchmarking function. +void registerBenchmarkOpenCVSepFilter2D() { + if (OpenCVBoundaryType2 == replicate_padding) { + BENCHMARK(OpenCV_SepFilter2D_Replicate_Padding) + ->Arg(1) + ->Unit(benchmark::kMillisecond); + } else { + BENCHMARK(OpenCV_SepFilter2D_Constant_Padding) + ->Arg(1) + ->Unit(benchmark::kMillisecond); + } +} + +// Generate result image. +void generateResultOpenCVSepFilter2D() { + if (OpenCVBoundaryType2 == replicate_padding) { + sepFilter2D(inputImageSepFilter2D, outputSepFilter2D, CV_32FC1, kernelFilter2DX, kernelFilter2DY, + cv::Point(0, 0), 0.0, cv::BORDER_REPLICATE); + } else { + sepFilter2D(inputImageSepFilter2D, outputSepFilter2D, CV_32FC1, kernelFilter2DX, kernelFilter2DY, + cv::Point(0, 0), 0.0, cv::BORDER_CONSTANT); + } + + // Choose a PNG compression level + vector compressionParams; + compressionParams.push_back(IMWRITE_PNG_COMPRESSION); + compressionParams.push_back(9); + + // Write output to PNG. + bool result = false; + try { + result = + imwrite("ResultOpenCVFilter2D.png", outputSepFilter2D, compressionParams); + } catch (const cv::Exception &ex) { + fprintf(stderr, "Exception converting image to PNG format: %s\n", + ex.what()); + } + if (result) + cout << "Saved PNG file." << endl; + else + cout << "ERROR: Can't save PNG file." << endl; +} \ No newline at end of file diff --git a/benchmarks/ImageProcessing/include/Kernels.h b/benchmarks/ImageProcessing/include/Kernels.h index afa3109e..36b00119 100644 --- a/benchmarks/ImageProcessing/include/Kernels.h +++ b/benchmarks/ImageProcessing/include/Kernels.h @@ -141,7 +141,22 @@ static float random13x13KernelAlign[169] = {8, 0, 6, 6, 7, 3, 4, 0, 6, 1, 5, 4, 3, 1, 5, 4, 0, 7, 9, 4, 0, 2, 9, 3, 2, 0, 4, 4, 1, 4, 6, 2, 8, 9, 7, 6, 8, 2, 8, 2, 0, 6, 6, 3, 0, 1, 8, 0, 8, 9, 6, - 9, 1, 5, 2, 6, 8, 8, 2, 1, 4, 9, 3, 2}; + 9, 1, 5, 2, 6, 8, 8, 2, 1, 4, 9, 3, 2}; + +static uint8_t random13x13KernelAlignInt[169] = {8, 0, 6, 6, 7, 3, 4, 0, 6, 1, 5, 4, 3, + 5, 8, 4, 7, 8, 7, 0, 7, 9, 1, 9, 4, 6, + 5, 6, 0, 7, 6, 8, 9, 4, 7, 7, 7, 1, 9, + 3, 4, 7, 8, 8, 4, 8, 4, 2, 6, 3, 4, 3, + 5, 6, 5, 9, 4, 2, 5, 4, 9, 3, 4, 8, 7, + 1, 7, 4, 4, 9, 0, 9, 6, 0, 9, 2, 8, 3, + 4, 7, 8, 1, 2, 3, 7, 9, 4, 3, 1, 9, 7, + 2, 4, 3, 3, 3, 5, 0, 0, 9, 1, 0, 0, 9, + 0, 9, 2, 0, 4, 8, 9, 3, 9, 2, 8, 8, 1, + 3, 1, 5, 4, 0, 7, 9, 4, 0, 2, 9, 3, 2, + 0, 4, 4, 1, 4, 6, 2, 8, 9, 7, 6, 8, 2, + 8, 2, 0, 6, 6, 3, 0, 1, 8, 0, 8, 9, 6, + 9, 1, 5, 2, 6, 8, 8, 2, 1, 4, 9, 3, 2}; + static int random13x13KernelRows = 13; static int random13x13KernelCols = 13; @@ -163,6 +178,22 @@ static float random15x15KernelAlign[225] = {0, 7, 6, 8, 5, 9, 6, 1, 6, 0, 7, 5, static int random15x15KernelRows = 15; static int random15x15KernelCols = 15; +static float sepKernelX[3] = {1, 2, 3}; +static int sepKernelXRows = 1; +static int sepKernelXCols = 3; + +static float sepKernelY[3] = {3, 4, 5}; +static int sepKernelYRows = 3; +static int sepKernelYCols = 1; + +static float sepKernel1x5[5] = {4, 5, 6, 7, 8}; +static float sepKernelRows1x5 = 1; +static float sepKernelCols1x5 = 5; + +static float sepKernel5x1[5] = {4, 5, 7, 8, 10}; +static float sepKernelRows5x1 = 5; +static float sepKernelCols5x1 = 1; + static std::map> kernelMap = { {"prewittKernelAlign", {prewittKernelAlign, prewittKernelRows, prewittKernelCols}}, {"sobel3x3KernelAlign", {sobel3x3KernelAlign, sobel3x3KernelRows, sobel3x3KernelCols}}, @@ -177,11 +208,16 @@ static std::map> kernelMap = { {"random9x9KernelAlign", {random9x9KernelAlign, random9x9KernelRows, random9x9KernelCols}}, {"random11x11KernelAlign", {random11x11KernelAlign, random11x11KernelRows, random11x11KernelCols}}, {"random13x13KernelAlign", {random13x13KernelAlign, random13x13KernelRows, random13x13KernelCols}}, - {"random15x15KernelAlign", {random15x15KernelAlign, random15x15KernelRows, random15x15KernelCols}} + {"random15x15KernelAlign", {random15x15KernelAlign, random15x15KernelRows, random15x15KernelCols}}, + {"sepKernelX", {sepKernelX, sepKernelXRows, sepKernelXCols}}, + {"sepKernelY", {sepKernelY, sepKernelYRows, sepKernelYCols}}, + {"sepKernel1x5", {sepKernel1x5, sepKernelRows1x5, sepKernelCols1x5}}, + {"sepKernel5x1", {sepKernel5x1, sepKernelRows5x1, sepKernelCols5x1}} }; static std::map> kernelMap1 = { - {"random3x3KernelAlignInt", {random3x3KernelAlignInt, random3x3KernelRows, random3x3KernelCols}} + {"random3x3KernelAlignInt", {random3x3KernelAlignInt, random3x3KernelRows, random3x3KernelCols}}, + {"random13x13KernelAlignInt", {random13x13KernelAlignInt, random13x13KernelRows, random13x13KernelCols}} }; // clang-format on