From e23e8380aa03d3bbf34eb34312fd52053fabf653 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Thu, 12 Jul 2018 14:02:00 +0200 Subject: [PATCH 01/26] Module EPF - Edge-Preserving Filter added --- modules/epf/CMakeLists.txt | 2 + modules/epf/README.md | 6 + modules/epf/doc/epf.bib | 14 + modules/epf/doc/epf.rst | 6 + modules/epf/include/opencv2/epf.hpp | 84 ++++++ modules/epf/samples/.clang-format | 46 +++ modules/epf/samples/epf_demo.cpp | 99 +++++++ modules/epf/src/epf.cpp | 442 ++++++++++++++++++++++++++++ modules/epf/src/precomp.hpp | 62 ++++ 9 files changed, 761 insertions(+) create mode 100644 modules/epf/CMakeLists.txt create mode 100644 modules/epf/README.md create mode 100644 modules/epf/doc/epf.bib create mode 100644 modules/epf/doc/epf.rst create mode 100644 modules/epf/include/opencv2/epf.hpp create mode 100644 modules/epf/samples/.clang-format create mode 100644 modules/epf/samples/epf_demo.cpp create mode 100644 modules/epf/src/epf.cpp create mode 100644 modules/epf/src/precomp.hpp diff --git a/modules/epf/CMakeLists.txt b/modules/epf/CMakeLists.txt new file mode 100644 index 00000000000..db5ff1f1de6 --- /dev/null +++ b/modules/epf/CMakeLists.txt @@ -0,0 +1,2 @@ +set(the_description "Plot function for Mat data.") +ocv_define_module(plot opencv_core opencv_imgproc WRAP python java) diff --git a/modules/epf/README.md b/modules/epf/README.md new file mode 100644 index 00000000000..0799601589a --- /dev/null +++ b/modules/epf/README.md @@ -0,0 +1,6 @@ +Edge-Preserving Filter Module +=========== + +Created by Simon Reich + +This module allows you to smooth input data. It reduces Gaussian as well as salt & pepper noise. It runs in real-time. diff --git a/modules/epf/doc/epf.bib b/modules/epf/doc/epf.bib new file mode 100644 index 00000000000..2b18db159e3 --- /dev/null +++ b/modules/epf/doc/epf.bib @@ -0,0 +1,14 @@ + @inproceedings{reichwoergoetterdellen2018, + author = {Reich, S. and Wörgötter, F. and Dellen, B.}, + title = {A Real-Time Edge-Preserving Denoising Filter}, + pages = {85-94}, + booktitle = {Proceedings of the 13th International Joint Conference on Computer Vision, Imaging and Computer Graphics Theory and Applications (VISIGRAPP): Visapp}, + year = {2018}, + volume= {4}, + location = {Funchal, Madeira (Portugal)}, + month = {January 27-29}, + organization = {INSTICC}, + publisher = {SciTePress}, + doi = {10.5220/0006509000850094}, + abstract = {Even in todays world, where augmented reality glasses and 3d sensors become rapidly less expensive and widely more used, the most important sensor remains the 2d RGB camera. Every camera is an optical device and prone to sensor noise, especially in dark environments or environments with extreme high dynamic range. The here introduced filter removes a wide variation of noise, for example Gaussian noise and salt-and-pepper noise, but preserves edges. Due to the highly parallel structure of the method, the implementation on a GPU runs in real-time, allowing us to process standard images within tens of milliseconds. The filter is first tested on 2d image data and based on the Berkeley Image Dataset and Coco Dataset we outperform other standard methods. Afterwards, we show a generalization to arbitrary dimensions using noisy low level sensor data. As a result the filter can be used not only for image enhancement, but also for noise reduction on sensors like acceleremoters, gyroscopes, or GPS-trackers, which are widely used in robotic applications.} + } diff --git a/modules/epf/doc/epf.rst b/modules/epf/doc/epf.rst new file mode 100644 index 00000000000..1adb5f408cb --- /dev/null +++ b/modules/epf/doc/epf.rst @@ -0,0 +1,6 @@ +EPF - Edge-Preserving Filter +========================== + +.. highlight:: cpp + +This module allows you to smooth image data. It uses a local method to preserve edges while doing so. Please see attached bib file for further details. diff --git a/modules/epf/include/opencv2/epf.hpp b/modules/epf/include/opencv2/epf.hpp new file mode 100644 index 00000000000..d11ef616757 --- /dev/null +++ b/modules/epf/include/opencv2/epf.hpp @@ -0,0 +1,84 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ +//################################################################################ +// +// Created by Simon Reich +// +//################################################################################ + +#ifndef _OPENCV_EPF_H_ +#define _OPENCV_EPF_H_ +#ifdef __cplusplus + +#include + +/** +@defgroup epf Smoothing function for noisy data +*/ + +namespace cv +{ + namespace epf + { + //! @addtogroup epf + //! @{ + + class CV_EXPORTS_W edgepreservingFilter : public Algorithm + { + public: + + /** + * @brief Creates EPF object + * + * @param src Source 8-bit 3-channel image. + * @param dst Destination image of the same size and type as src. + * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3.. + * @param threshold Threshold, which distinguishes between noise, outliers, and data. + */ + CV_WRAP static Ptr create(const cv::Mat *src, cv::Mat *dst, int d, int threshold); + }; + //! @} + } +} + +#endif +#endif diff --git a/modules/epf/samples/.clang-format b/modules/epf/samples/.clang-format new file mode 100644 index 00000000000..8baff9ea526 --- /dev/null +++ b/modules/epf/samples/.clang-format @@ -0,0 +1,46 @@ +--- +AccessModifierOffset: -2 +ConstructorInitializerIndentWidth: 4 +AlignEscapedNewlinesLeft: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakTemplateDeclarations: false +AlwaysBreakBeforeMultilineStrings: false +BreakBeforeBinaryOperators: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BinPackParameters: true +ColumnLimit: 80 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +DerivePointerBinding: false +ExperimentalAutoDetectBinPacking: false +IndentCaseLabels: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCSpaceBeforeProtocolList: true +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 60 +PenaltyBreakString: 1000 +PenaltyBreakFirstLessLess: 120 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerBindsToType: false +SpacesBeforeTrailingComments: 1 +Cpp11BracedListStyle: false +Standard: Cpp11 +IndentWidth: 8 +TabWidth: 8 +UseTab: ForIndentation +BreakBeforeBraces: Allman +IndentFunctionDeclarationAfterType: false +SpacesInParentheses: false +SpacesInAngles: false +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpaceAfterControlStatementKeyword: true +SpaceBeforeAssignmentOperators: true +ContinuationIndentWidth: 4 +... + diff --git a/modules/epf/samples/epf_demo.cpp b/modules/epf/samples/epf_demo.cpp new file mode 100644 index 00000000000..c2d6a43c0a2 --- /dev/null +++ b/modules/epf/samples/epf_demo.cpp @@ -0,0 +1,99 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ +//################################################################################ +// +// Created by Simon Reich +// +//################################################################################ + +#include +#include +#include +#include + +using namespace cv; + +int showWindow(cv::Mat image, std::string title); + +int showWindow(cv::Mat image, std::string title) +{ + namedWindow(title); + imshow(title, image); + + waitKey(0); + + return 0; +} + +int main(int argc, char **argv) +{ + // Help text + if (argc != 2) + { + std::cout << "usage: " << argv[0] << " image.jpg" << std::endl; + std::cout << "image.jpg contains image, which will be smoothed." + << std::endl; + return -1; + } + + // Load image from first parameter + std::string filename = argv[1]; + Mat image = imread(filename, 1), res; + + if (!image.data) + { + std::cerr << "No image data at " << argv[2] << std::endl; + throw; + } + + // Before filtering + showWindow(image, "Original image"); + + // Initialize filter. Kernel size 5x5, threshold 20 + Ptr filter = + epf::edgepreservingFilter::create(&image, &res, 5, 20); + + // After filtering + showWindow(res, "Filtered image"); + + return 0; +} diff --git a/modules/epf/src/epf.cpp b/modules/epf/src/epf.cpp new file mode 100644 index 00000000000..10cb2e79e4a --- /dev/null +++ b/modules/epf/src/epf.cpp @@ -0,0 +1,442 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ +//################################################################################ +// +// Created by Simon Reich +// +//################################################################################ + + +#include "precomp.hpp" + +namespace cv +{ +namespace epf +{ +using namespace std; + +class edgepreservingFilterImpl CV_FINAL : public edgepreservingFilter +{ + public: + edgepreservingFilterImpl(){}; + ~edgepreservingFilterImpl(){}; + + edgepreservingFilterImpl(const cv::Mat *src, cv::Mat *dst, int d, + int threshold) + { + + CV_Assert(src->type() == CV_8UC3 && src->data != dst->data); + + if (d < 3) + d = 3; + int subwindowX = d, subwindowY = d; + + if (threshold < 0) + threshold = 0; + + // number of image channels + int nChannel = src->channels(); + + src->copyTo(*dst); + + vector pixel(nChannel, 0); + vector> line1(src->rows, pixel); + vector>> weight(src->cols, + line1); // global weights + vector>> imageResult( + src->cols, line1); // global normalized image + + // do algorithm + cv::Mat subwindow; + for (int posX = 0; posX < src->cols - subwindowX; posX++) + { + for (int posY = 0; posY < src->rows - subwindowY; + posY++) + { + cv::Rect roi = cv::Rect(posX, posY, subwindowX, + subwindowY); + subwindow = (*src)(roi); + cv::Mat subwindow1 = (*src)(roi); + cv::GaussianBlur(subwindow1, subwindow, + cv::Size(5, 5), 0.3, 0.3); + + // compute arithmetic mean of subwindow + int nCounter = 0; + vector colorValue(nChannel, 0); + + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + for (int subPosY = 0; + subPosY < subwindow.rows; + subPosY++) + { + cv::Vec3b intensity = + subwindow.at( + subPosY, subPosX); + colorValue[0] += + (int)intensity.val[0]; + colorValue[1] += + (int)intensity.val[1]; + colorValue[2] += + (int)intensity.val[2]; + nCounter++; + }; + }; + + vector ArithmeticMean(nChannel); + ArithmeticMean[0] = + colorValue[0] / nCounter; // B + ArithmeticMean[1] = + colorValue[1] / nCounter; // G + ArithmeticMean[2] = + colorValue[2] / nCounter; // R + + // compute pixelwise distance + vector> pixelwiseDist; + + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + vector line; + for (int subPosY = 0; + subPosY < subwindow.rows; + subPosY++) + { + cv::Vec3b intensity = + subwindow.at( + subPosY, subPosX); + double distance = + ((double)intensity.val[0] - + ArithmeticMean[0]) * + ((double) + intensity.val[0] - + ArithmeticMean[0]) + + ((double)intensity.val[1] - + ArithmeticMean[1]) * + ((double) + intensity.val[1] - + ArithmeticMean[1]) + + ((double)intensity.val[2] - + ArithmeticMean[2]) * + ((double) + intensity.val[2] - + ArithmeticMean[2]); + distance = sqrt(distance); + + line.push_back(distance); + }; + + pixelwiseDist.push_back(line); + }; + + // compute mean pixelwise distance + double meanPixelwiseDist = 0; + + for (int i = 0; i < (int)pixelwiseDist.size(); + i++) + for (int j = 0; + j < (int)pixelwiseDist[i].size(); + j++) + meanPixelwiseDist += + pixelwiseDist[i][j]; + + meanPixelwiseDist /= + ((int)pixelwiseDist.size() * + (int)pixelwiseDist[0].size()); + + // detect edge + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + for (int subPosY = 0; + subPosY < subwindow.rows; + subPosY++) + { + if (meanPixelwiseDist <= + threshold && + pixelwiseDist[subPosX] + [subPosY] <= + threshold) + { + // global Position + int globalPosX = + posX + subPosX; + int globalPosY = + posY + subPosY; + + // compute global weight + cv::Vec3b intensity = + subwindow + .at( + subPosY, + subPosX); + weight[globalPosX] + [globalPosY][0] += + intensity.val[0] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]); + weight[globalPosX] + [globalPosY][1] += + intensity.val[1] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]); + weight[globalPosX] + [globalPosY][2] += + intensity.val[2] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]); + + // compute final image + imageResult[globalPosX] + [globalPosY] + [0] += + intensity.val[0] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + ArithmeticMean[0]; + imageResult[globalPosX] + [globalPosY] + [1] += + intensity.val[1] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + ArithmeticMean[1]; + imageResult[globalPosX] + [globalPosY] + [2] += + intensity.val[2] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + ArithmeticMean[2]; + } + else if (meanPixelwiseDist <= + threshold && + pixelwiseDist + [subPosX] + [subPosY] > + threshold) + { + // global Position + int globalPosX = + posX + subPosX; + int globalPosY = + posY + subPosY; + + // compute global weight + cv::Vec3b intensity = + subwindow + .at( + subPosY, + subPosX); + weight[globalPosX] + [globalPosY][0] += + intensity.val[0] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]); + weight[globalPosX] + [globalPosY][1] += + intensity.val[1] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]); + weight[globalPosX] + [globalPosY][2] += + intensity.val[2] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]); + + // compute final image + imageResult[globalPosX] + [globalPosY] + [0] += + intensity.val[0] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + ArithmeticMean[0]; + imageResult[globalPosX] + [globalPosY] + [1] += + intensity.val[1] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + ArithmeticMean[1]; + imageResult[globalPosX] + [globalPosY] + [2] += + intensity.val[2] * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + (threshold - + pixelwiseDist + [subPosX] + [subPosY]) * + ArithmeticMean[2]; + }; + }; + }; + }; + }; + + // compute final image + for (int globalPosX = 0; globalPosX < (int)imageResult.size(); + globalPosX++) + { + for (int globalPosY = 0; + globalPosY < (int)imageResult[globalPosX].size(); + globalPosY++) + { + // cout << "globalPosX: " << globalPosX << "/" + // << dst->cols << "," << imageResult.size () << + // "\tglobalPosY: " << globalPosY << "/" << + // dst->rows << "," <at(globalPosY, globalPosX); + imageResult[globalPosX][globalPosY][0] += + (double)intensity.val[0]; + imageResult[globalPosX][globalPosY][1] += + (double)intensity.val[1]; + imageResult[globalPosX][globalPosY][2] += + (double)intensity.val[2]; + + // normalize using weight + imageResult[globalPosX][globalPosY][0] /= + (weight[globalPosX][globalPosY][0] + 1); + imageResult[globalPosX][globalPosY][1] /= + (weight[globalPosX][globalPosY][1] + 1); + imageResult[globalPosX][globalPosY][2] /= + (weight[globalPosX][globalPosY][2] + 1); + + // copy to output image frame + dst->at(globalPosY, globalPosX)[0] = + (uchar) + imageResult[globalPosX][globalPosY][0]; + dst->at(globalPosY, globalPosX)[1] = + (uchar) + imageResult[globalPosX][globalPosY][1]; + dst->at(globalPosY, globalPosX)[2] = + (uchar) + imageResult[globalPosX][globalPosY][2]; + }; + }; + } +}; + +Ptr edgepreservingFilter::create(const cv::Mat *src, + cv::Mat *dst, int d, + int threshold) +{ + return Ptr( + new edgepreservingFilterImpl(src, dst, d, threshold)); +} +} // namespace epf +} // namespace cv diff --git a/modules/epf/src/precomp.hpp b/modules/epf/src/precomp.hpp new file mode 100644 index 00000000000..58e54a115ac --- /dev/null +++ b/modules/epf/src/precomp.hpp @@ -0,0 +1,62 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ +//################################################################################ +// +// Created by Simon Reich +// +//################################################################################ + +#ifndef __OPENCV_PRECOMP_H__ +#define __OPENCV_PRECOMP_H__ + +#include "opencv2/epf.hpp" +#include "opencv2/opencv_modules.hpp" +#include +#include + +#include +#include +#include +#include +#include + +#endif From 3891dd5f11fb026bd6cee80736ee470656837ae7 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Thu, 12 Jul 2018 14:15:07 +0200 Subject: [PATCH 02/26] Changed name from template to epf --- modules/epf/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/epf/CMakeLists.txt b/modules/epf/CMakeLists.txt index db5ff1f1de6..055af827a35 100644 --- a/modules/epf/CMakeLists.txt +++ b/modules/epf/CMakeLists.txt @@ -1,2 +1,2 @@ -set(the_description "Plot function for Mat data.") -ocv_define_module(plot opencv_core opencv_imgproc WRAP python java) +set(the_description "Esge-Preserving filter for images.") +ocv_define_module(epf opencv_core opencv_imgproc WRAP python java) From 538049f403a209010ffd46d24a4b7f977875e4fa Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Thu, 12 Jul 2018 14:16:28 +0200 Subject: [PATCH 03/26] Removed clang-format file --- modules/epf/samples/.clang-format | 46 ------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 modules/epf/samples/.clang-format diff --git a/modules/epf/samples/.clang-format b/modules/epf/samples/.clang-format deleted file mode 100644 index 8baff9ea526..00000000000 --- a/modules/epf/samples/.clang-format +++ /dev/null @@ -1,46 +0,0 @@ ---- -AccessModifierOffset: -2 -ConstructorInitializerIndentWidth: 4 -AlignEscapedNewlinesLeft: false -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AlwaysBreakTemplateDeclarations: false -AlwaysBreakBeforeMultilineStrings: false -BreakBeforeBinaryOperators: false -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BinPackParameters: true -ColumnLimit: 80 -ConstructorInitializerAllOnOneLineOrOnePerLine: false -DerivePointerBinding: false -ExperimentalAutoDetectBinPacking: false -IndentCaseLabels: false -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCSpaceBeforeProtocolList: true -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 60 -PenaltyBreakString: 1000 -PenaltyBreakFirstLessLess: 120 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerBindsToType: false -SpacesBeforeTrailingComments: 1 -Cpp11BracedListStyle: false -Standard: Cpp11 -IndentWidth: 8 -TabWidth: 8 -UseTab: ForIndentation -BreakBeforeBraces: Allman -IndentFunctionDeclarationAfterType: false -SpacesInParentheses: false -SpacesInAngles: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false -SpaceAfterControlStatementKeyword: true -SpaceBeforeAssignmentOperators: true -ContinuationIndentWidth: 4 -... - From 0d96f6d6b5a5cb35c38a7e0dec29f82af1a94098 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Thu, 12 Jul 2018 15:13:49 +0200 Subject: [PATCH 04/26] Added header Files. Eliminated showWindow function. Used CommandLineParser. --- modules/epf/samples/epf_demo.cpp | 51 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/modules/epf/samples/epf_demo.cpp b/modules/epf/samples/epf_demo.cpp index c2d6a43c0a2..62f82601a11 100644 --- a/modules/epf/samples/epf_demo.cpp +++ b/modules/epf/samples/epf_demo.cpp @@ -45,55 +45,58 @@ // //################################################################################ +#include "precomp.hpp" + +namespace cv +{ +namespace epf #include -#include -#include +#include +#include #include +#include +#include +#include +#include +#include using namespace cv; -int showWindow(cv::Mat image, std::string title); - -int showWindow(cv::Mat image, std::string title) -{ - namedWindow(title); - imshow(title, image); - - waitKey(0); - - return 0; -} - int main(int argc, char **argv) { + CV_TRACE_FUNCTION(); + // Help text - if (argc != 2) + cv::CommandLineParser parser( + argc, argv, + "{help h ? | | help message }" + "{@image | | Path to image file to process }"); + if (parser.has("help") || !parser.has("@image")) { - std::cout << "usage: " << argv[0] << " image.jpg" << std::endl; - std::cout << "image.jpg contains image, which will be smoothed." - << std::endl; - return -1; + parser.printMessage(); + return 0; } // Load image from first parameter std::string filename = argv[1]; Mat image = imread(filename, 1), res; - if (!image.data) { - std::cerr << "No image data at " << argv[2] << std::endl; - throw; + std::cerr << "No image data at " << filename << std::endl; + return -1; } // Before filtering - showWindow(image, "Original image"); + imshow("Original image", image); + waitKey(0); // Initialize filter. Kernel size 5x5, threshold 20 Ptr filter = epf::edgepreservingFilter::create(&image, &res, 5, 20); // After filtering - showWindow(res, "Filtered image"); + imshow("Filtered image", res); + waitKey(0); return 0; } From c272800e274e092be8cb0e6d82c786652c6b90aa Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Thu, 12 Jul 2018 16:04:41 +0200 Subject: [PATCH 05/26] Moved filter from epf module to ximgproc --- modules/epf/CMakeLists.txt | 2 - modules/epf/README.md | 6 -- modules/epf/doc/epf.bib | 14 --- modules/epf/doc/epf.rst | 6 -- modules/epf/include/opencv2/epf.hpp | 84 --------------- modules/epf/samples/epf_demo.cpp | 102 ------------------ modules/epf/src/precomp.hpp | 62 ----------- modules/ximgproc/include/opencv2/ximgproc.hpp | 1 + .../ximgproc/edgepreserving_filter.hpp | 31 ++++++ .../samples/edgepreserving_filter_demo.cpp | 47 ++++++++ .../src/edgepreserving_filter.cpp} | 67 ++---------- 11 files changed, 85 insertions(+), 337 deletions(-) delete mode 100644 modules/epf/CMakeLists.txt delete mode 100644 modules/epf/README.md delete mode 100644 modules/epf/doc/epf.bib delete mode 100644 modules/epf/doc/epf.rst delete mode 100644 modules/epf/include/opencv2/epf.hpp delete mode 100644 modules/epf/samples/epf_demo.cpp delete mode 100644 modules/epf/src/precomp.hpp create mode 100644 modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp create mode 100644 modules/ximgproc/samples/edgepreserving_filter_demo.cpp rename modules/{epf/src/epf.cpp => ximgproc/src/edgepreserving_filter.cpp} (77%) diff --git a/modules/epf/CMakeLists.txt b/modules/epf/CMakeLists.txt deleted file mode 100644 index 055af827a35..00000000000 --- a/modules/epf/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -set(the_description "Esge-Preserving filter for images.") -ocv_define_module(epf opencv_core opencv_imgproc WRAP python java) diff --git a/modules/epf/README.md b/modules/epf/README.md deleted file mode 100644 index 0799601589a..00000000000 --- a/modules/epf/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Edge-Preserving Filter Module -=========== - -Created by Simon Reich - -This module allows you to smooth input data. It reduces Gaussian as well as salt & pepper noise. It runs in real-time. diff --git a/modules/epf/doc/epf.bib b/modules/epf/doc/epf.bib deleted file mode 100644 index 2b18db159e3..00000000000 --- a/modules/epf/doc/epf.bib +++ /dev/null @@ -1,14 +0,0 @@ - @inproceedings{reichwoergoetterdellen2018, - author = {Reich, S. and Wörgötter, F. and Dellen, B.}, - title = {A Real-Time Edge-Preserving Denoising Filter}, - pages = {85-94}, - booktitle = {Proceedings of the 13th International Joint Conference on Computer Vision, Imaging and Computer Graphics Theory and Applications (VISIGRAPP): Visapp}, - year = {2018}, - volume= {4}, - location = {Funchal, Madeira (Portugal)}, - month = {January 27-29}, - organization = {INSTICC}, - publisher = {SciTePress}, - doi = {10.5220/0006509000850094}, - abstract = {Even in todays world, where augmented reality glasses and 3d sensors become rapidly less expensive and widely more used, the most important sensor remains the 2d RGB camera. Every camera is an optical device and prone to sensor noise, especially in dark environments or environments with extreme high dynamic range. The here introduced filter removes a wide variation of noise, for example Gaussian noise and salt-and-pepper noise, but preserves edges. Due to the highly parallel structure of the method, the implementation on a GPU runs in real-time, allowing us to process standard images within tens of milliseconds. The filter is first tested on 2d image data and based on the Berkeley Image Dataset and Coco Dataset we outperform other standard methods. Afterwards, we show a generalization to arbitrary dimensions using noisy low level sensor data. As a result the filter can be used not only for image enhancement, but also for noise reduction on sensors like acceleremoters, gyroscopes, or GPS-trackers, which are widely used in robotic applications.} - } diff --git a/modules/epf/doc/epf.rst b/modules/epf/doc/epf.rst deleted file mode 100644 index 1adb5f408cb..00000000000 --- a/modules/epf/doc/epf.rst +++ /dev/null @@ -1,6 +0,0 @@ -EPF - Edge-Preserving Filter -========================== - -.. highlight:: cpp - -This module allows you to smooth image data. It uses a local method to preserve edges while doing so. Please see attached bib file for further details. diff --git a/modules/epf/include/opencv2/epf.hpp b/modules/epf/include/opencv2/epf.hpp deleted file mode 100644 index d11ef616757..00000000000 --- a/modules/epf/include/opencv2/epf.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ -//################################################################################ -// -// Created by Simon Reich -// -//################################################################################ - -#ifndef _OPENCV_EPF_H_ -#define _OPENCV_EPF_H_ -#ifdef __cplusplus - -#include - -/** -@defgroup epf Smoothing function for noisy data -*/ - -namespace cv -{ - namespace epf - { - //! @addtogroup epf - //! @{ - - class CV_EXPORTS_W edgepreservingFilter : public Algorithm - { - public: - - /** - * @brief Creates EPF object - * - * @param src Source 8-bit 3-channel image. - * @param dst Destination image of the same size and type as src. - * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3.. - * @param threshold Threshold, which distinguishes between noise, outliers, and data. - */ - CV_WRAP static Ptr create(const cv::Mat *src, cv::Mat *dst, int d, int threshold); - }; - //! @} - } -} - -#endif -#endif diff --git a/modules/epf/samples/epf_demo.cpp b/modules/epf/samples/epf_demo.cpp deleted file mode 100644 index 62f82601a11..00000000000 --- a/modules/epf/samples/epf_demo.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ -//################################################################################ -// -// Created by Simon Reich -// -//################################################################################ - -#include "precomp.hpp" - -namespace cv -{ -namespace epf -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace cv; - -int main(int argc, char **argv) -{ - CV_TRACE_FUNCTION(); - - // Help text - cv::CommandLineParser parser( - argc, argv, - "{help h ? | | help message }" - "{@image | | Path to image file to process }"); - if (parser.has("help") || !parser.has("@image")) - { - parser.printMessage(); - return 0; - } - - // Load image from first parameter - std::string filename = argv[1]; - Mat image = imread(filename, 1), res; - if (!image.data) - { - std::cerr << "No image data at " << filename << std::endl; - return -1; - } - - // Before filtering - imshow("Original image", image); - waitKey(0); - - // Initialize filter. Kernel size 5x5, threshold 20 - Ptr filter = - epf::edgepreservingFilter::create(&image, &res, 5, 20); - - // After filtering - imshow("Filtered image", res); - waitKey(0); - - return 0; -} diff --git a/modules/epf/src/precomp.hpp b/modules/epf/src/precomp.hpp deleted file mode 100644 index 58e54a115ac..00000000000 --- a/modules/epf/src/precomp.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ -//################################################################################ -// -// Created by Simon Reich -// -//################################################################################ - -#ifndef __OPENCV_PRECOMP_H__ -#define __OPENCV_PRECOMP_H__ - -#include "opencv2/epf.hpp" -#include "opencv2/opencv_modules.hpp" -#include -#include - -#include -#include -#include -#include -#include - -#endif diff --git a/modules/ximgproc/include/opencv2/ximgproc.hpp b/modules/ximgproc/include/opencv2/ximgproc.hpp index 874bf63e041..5ff7b3f70bc 100644 --- a/modules/ximgproc/include/opencv2/ximgproc.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc.hpp @@ -57,6 +57,7 @@ #include "ximgproc/ridgefilter.hpp" #include "ximgproc/brightedges.hpp" #include "ximgproc/run_length_morphology.hpp" +#include "ximgproc/edgepreserving_filter.hpp" /** @defgroup ximgproc Extended Image Processing diff --git a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp new file mode 100644 index 00000000000..e71503a5f73 --- /dev/null +++ b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp @@ -0,0 +1,31 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#ifndef __OPENCV_EDGEPRESERVINGFILTER_HPP__ +#define __OPENCV_EDGEPRESERVINGFILTER_HPP__ + +#include + +namespace cv { namespace ximgproc { + + //! @addtogroup ximgproc + //! @{ + + /** + * @brief Smoothes an image using the Edge-Preserving filter. + * + * The function smoothes Gaussian noise as well as salt & pepper noise. + * For more details about this implementation, please see + * [ReiWoe18] Reich, S. and Wörgötter, F. and Dellen, B. (2018). A Real-Time Edge-Preserving Denoising Filter. Proceedings of the 13th International Joint Conference on Computer Vision, Imaging and Computer Graphics Theory and Applications (VISIGRAPP): Visapp, 85-94, 4. DOI: 10.5220/0006509000850094. + * + * @param src Source 8-bit 3-channel image. + * @param dst Destination image of the same size and type as src. + * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3.. + * @param threshold Threshold, which distinguishes between noise, outliers, and data. + */ + CV_EXPORTS_W void edgepreservingFilter( const InputArray *src, OutputArray *dst, int d, int threshold ); + +}} // namespace + +#endif diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp new file mode 100644 index 00000000000..c76890c2dd9 --- /dev/null +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include + + +using namespace cv; + + +int main(int argc, char **argv) +{ + cv::CommandLineParser parser(argc, argv, + "{help h ? | | help message}" + "{@image | | Image filename to process }" + ); + if (parser.has("help") || !parser.has("image")) + { + parser.printMessage(); + return 0; + } + + // Load image from first parameter + std::string filename = parser.get("@image"); + Mat image = imread(filename, 1), res; + + if (!image.data) + { + std::cerr << "No image data at " << filename << std::endl; + throw; + } + + // Before filtering + imshow("Original image", image); + waitKey(0); + + // Initialize filter. Kernel size 5x5, threshold 20 + ximgproc::edgepreservingFilter(&image, &res, 5, 20); + + // After filtering + imshow("Filtered image", res); + waitKey(0); + + return 0; +} diff --git a/modules/epf/src/epf.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp similarity index 77% rename from modules/epf/src/epf.cpp rename to modules/ximgproc/src/edgepreserving_filter.cpp index 10cb2e79e4a..0ce0788e739 100644 --- a/modules/epf/src/epf.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -1,66 +1,20 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. -// Copyright (C) 2009, Willow Garage Inc., all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ -//################################################################################ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. // // Created by Simon Reich // -//################################################################################ #include "precomp.hpp" namespace cv { -namespace epf +namespace ximgproc { using namespace std; -class edgepreservingFilterImpl CV_FINAL : public edgepreservingFilter -{ - public: - edgepreservingFilterImpl(){}; - ~edgepreservingFilterImpl(){}; - - edgepreservingFilterImpl(const cv::Mat *src, cv::Mat *dst, int d, + edgepreservingFilter(const InputArray *src, OutputArray *dst, int d, int threshold) { @@ -429,14 +383,5 @@ class edgepreservingFilterImpl CV_FINAL : public edgepreservingFilter }; }; } -}; - -Ptr edgepreservingFilter::create(const cv::Mat *src, - cv::Mat *dst, int d, - int threshold) -{ - return Ptr( - new edgepreservingFilterImpl(src, dst, d, threshold)); -} -} // namespace epf +} // namespace ximgproc } // namespace cv From 23d45a6a010acc1547ba6a4dc8514ff8cba4cd0e Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Fri, 13 Jul 2018 12:12:23 +0200 Subject: [PATCH 06/26] Removed header files from sample --- modules/ximgproc/samples/edgepreserving_filter_demo.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp index c76890c2dd9..b891f9a7cd2 100644 --- a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -1,10 +1,6 @@ #include #include -#include -#include #include -#include -#include using namespace cv; From 82dfa23ce11768e6ac0ed5d62a056e0336d31bd3 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Fri, 13 Jul 2018 12:47:59 +0200 Subject: [PATCH 07/26] Minor bug fix in demo. Pointers in demo removed. --- modules/ximgproc/samples/edgepreserving_filter_demo.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp index b891f9a7cd2..f718a4faee6 100644 --- a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -1,5 +1,6 @@ #include #include +#include #include @@ -12,14 +13,14 @@ int main(int argc, char **argv) "{help h ? | | help message}" "{@image | | Image filename to process }" ); - if (parser.has("help") || !parser.has("image")) + if (parser.has("help") || !parser.has("@image")) { parser.printMessage(); return 0; } // Load image from first parameter - std::string filename = parser.get("@image"); + std::string filename = parser.get("@image"); Mat image = imread(filename, 1), res; if (!image.data) @@ -33,7 +34,7 @@ int main(int argc, char **argv) waitKey(0); // Initialize filter. Kernel size 5x5, threshold 20 - ximgproc::edgepreservingFilter(&image, &res, 5, 20); + ximgproc::edgepreservingFilter(image, res, 9, 20); // After filtering imshow("Filtered image", res); From 88ce7a7eaadf903c0a17740ca047d131f5500bf6 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Fri, 13 Jul 2018 12:48:38 +0200 Subject: [PATCH 08/26] Pointers removed. InputArray/OutputArray added --- .../ximgproc/edgepreserving_filter.hpp | 2 +- .../ximgproc/src/edgepreserving_filter.cpp | 51 ++++++++++--------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp index e71503a5f73..c913d63ea28 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp @@ -24,7 +24,7 @@ namespace cv { namespace ximgproc { * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3.. * @param threshold Threshold, which distinguishes between noise, outliers, and data. */ - CV_EXPORTS_W void edgepreservingFilter( const InputArray *src, OutputArray *dst, int d, int threshold ); + CV_EXPORTS_W void edgepreservingFilter( const InputArray src, OutputArray dst, int d, int threshold ); }} // namespace diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 0ce0788e739..ca6373658a8 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -14,11 +14,16 @@ namespace ximgproc { using namespace std; - edgepreservingFilter(const InputArray *src, OutputArray *dst, int d, + void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, int threshold) { + Mat src = _src.getMat(); - CV_Assert(src->type() == CV_8UC3 && src->data != dst->data); + // [re]create the output array so that it has the proper size and type. + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + + CV_Assert(src.type() == CV_8UC3); if (d < 3) d = 3; @@ -28,34 +33,32 @@ using namespace std; threshold = 0; // number of image channels - int nChannel = src->channels(); - - src->copyTo(*dst); + int nChannel = src.channels(); - vector pixel(nChannel, 0); - vector> line1(src->rows, pixel); - vector>> weight(src->cols, + vector pixel(nChannel, 0); + vector < vector > line1(src.rows, pixel); + vector < vector > > weight(src.cols, line1); // global weights - vector>> imageResult( - src->cols, line1); // global normalized image + vector < vector < vector > > imageResult( + src.cols, line1); // global normalized image // do algorithm cv::Mat subwindow; - for (int posX = 0; posX < src->cols - subwindowX; posX++) + for (int posX = 0; posX < src.cols - subwindowX; posX++) { - for (int posY = 0; posY < src->rows - subwindowY; + for (int posY = 0; posY < src.rows - subwindowY; posY++) { cv::Rect roi = cv::Rect(posX, posY, subwindowX, subwindowY); - subwindow = (*src)(roi); - cv::Mat subwindow1 = (*src)(roi); + subwindow = src(roi); + cv::Mat subwindow1 = src(roi); cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), 0.3, 0.3); // compute arithmetic mean of subwindow int nCounter = 0; - vector colorValue(nChannel, 0); + vector colorValue(nChannel, 0); for (int subPosX = 0; subPosX < subwindow.cols; subPosX++) @@ -77,7 +80,7 @@ using namespace std; }; }; - vector ArithmeticMean(nChannel); + vector ArithmeticMean(nChannel); ArithmeticMean[0] = colorValue[0] / nCounter; // B ArithmeticMean[1] = @@ -86,12 +89,12 @@ using namespace std; colorValue[2] / nCounter; // R // compute pixelwise distance - vector> pixelwiseDist; + vector < vector > pixelwiseDist; for (int subPosX = 0; subPosX < subwindow.cols; subPosX++) { - vector line; + vector line; for (int subPosY = 0; subPosY < subwindow.rows; subPosY++) @@ -347,14 +350,14 @@ using namespace std; globalPosY++) { // cout << "globalPosX: " << globalPosX << "/" - // << dst->cols << "," << imageResult.size () << + // << dst.cols << "," << imageResult.size () << // "\tglobalPosY: " << globalPosY << "/" << - // dst->rows << "," <at(globalPosY, globalPosX); + src.at(globalPosY, globalPosX); imageResult[globalPosX][globalPosY][0] += (double)intensity.val[0]; imageResult[globalPosX][globalPosY][1] += @@ -371,13 +374,13 @@ using namespace std; (weight[globalPosX][globalPosY][2] + 1); // copy to output image frame - dst->at(globalPosY, globalPosX)[0] = + dst.at(globalPosY, globalPosX)[0] = (uchar) imageResult[globalPosX][globalPosY][0]; - dst->at(globalPosY, globalPosX)[1] = + dst.at(globalPosY, globalPosX)[1] = (uchar) imageResult[globalPosX][globalPosY][1]; - dst->at(globalPosY, globalPosX)[2] = + dst.at(globalPosY, globalPosX)[2] = (uchar) imageResult[globalPosX][globalPosY][2]; }; From 1f115b64fad01bebc88e3bbbc8c1b7a1238280df Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Tue, 31 Jul 2018 09:31:26 +0200 Subject: [PATCH 09/26] License header added --- .../include/opencv2/ximgproc/edgepreserving_filter.hpp | 2 +- modules/ximgproc/samples/edgepreserving_filter_demo.cpp | 8 ++++++++ modules/ximgproc/src/edgepreserving_filter.cpp | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp index c913d63ea28..d40e5d253f7 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp @@ -24,7 +24,7 @@ namespace cv { namespace ximgproc { * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3.. * @param threshold Threshold, which distinguishes between noise, outliers, and data. */ - CV_EXPORTS_W void edgepreservingFilter( const InputArray src, OutputArray dst, int d, int threshold ); + CV_EXPORTS_W void edgepreservingFilter( const InputArray src, OutputArray dst, int d, double threshold ); }} // namespace diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp index f718a4faee6..07bb9c78913 100644 --- a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -1,3 +1,11 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Created by Simon Reich +// + + #include #include #include diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index ca6373658a8..5a24f231969 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -15,13 +15,15 @@ namespace ximgproc using namespace std; void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, - int threshold) + double threshold) { Mat src = _src.getMat(); // [re]create the output array so that it has the proper size and type. _dst.create(src.size(), src.type()); Mat dst = _dst.getMat(); + src.copyTo(dst); + CV_Assert(src.type() == CV_8UC3); From 19686de0a7dd7f20e4f229626d62b69af5cd76d6 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Tue, 31 Jul 2018 09:32:17 +0200 Subject: [PATCH 10/26] License header from sample file removed --- modules/ximgproc/samples/edgepreserving_filter_demo.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp index 07bb9c78913..f718a4faee6 100644 --- a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -1,11 +1,3 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -// -// Created by Simon Reich -// - - #include #include #include From 9cc391b9fee2a2bab9f4dcfd625bdf54af6e140c Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Tue, 31 Jul 2018 12:54:27 +0200 Subject: [PATCH 11/26] Unit test for performance added --- .../perf/perf_edgepreserving_filter.cpp | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 modules/ximgproc/perf/perf_edgepreserving_filter.cpp diff --git a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp new file mode 100644 index 00000000000..e59614bc52a --- /dev/null +++ b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp @@ -0,0 +1,44 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#include "perf_precomp.hpp" + +namespace opencv_test { namespace { + +/* 1. Define parameter type and test fixture */ +typedef tuple RGFTestParam; +typedef TestBaseWithParam EdgepreservingFilterTest; + +/* 2. Declare the testsuite */ +PERF_TEST_P(EdgepreservingFilterTest, perf, + Combine( + Values(-20, 0, 10), + Values(-100, 0 , 20)) +) +{ + /* 3. Get actual test parameters */ + RGFTestParam params = GetParam(); + int kernelSize = get<0>(params); + double threshold = get<1>(params); + + + /* 4. Allocate and initialize arguments for tested function */ + std::string filename = getDataPath("samples/data/corridor.jpg"); + Mat src = imread(filename, 1); + Mat dst(src.size(), src.type()); + + /* 5. Manifest your expectations about this test */ + declare.in(src, WARMUP_RNG).out(dst); + + /* 6. Collect the samples! */ + TEST_CYCLE_N(1) + { + ximgproc::edgepreservingFilter(src, dst, kernelSize, threshold); + } + + /* 7. Do not check anything */ + SANITY_CHECK_NOTHING(); +} + + +}} // namespace From c411b3934c2bda52fd1a61ae39a77e51c0227ae7 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Tue, 31 Jul 2018 13:11:51 +0200 Subject: [PATCH 12/26] Replaced manual mean computation with cv::mean --- .../ximgproc/src/edgepreserving_filter.cpp | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 5a24f231969..6ec6f360b95 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -59,36 +59,7 @@ using namespace std; cv::Size(5, 5), 0.3, 0.3); // compute arithmetic mean of subwindow - int nCounter = 0; - vector colorValue(nChannel, 0); - - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) - { - for (int subPosY = 0; - subPosY < subwindow.rows; - subPosY++) - { - cv::Vec3b intensity = - subwindow.at( - subPosY, subPosX); - colorValue[0] += - (int)intensity.val[0]; - colorValue[1] += - (int)intensity.val[1]; - colorValue[2] += - (int)intensity.val[2]; - nCounter++; - }; - }; - - vector ArithmeticMean(nChannel); - ArithmeticMean[0] = - colorValue[0] / nCounter; // B - ArithmeticMean[1] = - colorValue[1] / nCounter; // G - ArithmeticMean[2] = - colorValue[2] / nCounter; // R + cv::Scalar ArithmeticMean = cv::mean(subwindow); // compute pixelwise distance vector < vector > pixelwiseDist; From 55766d986ee2ee8defaf0545bd14f7734688ae37 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Tue, 31 Jul 2018 13:14:56 +0200 Subject: [PATCH 13/26] Beautified code via clang-format and https://raw.githubusercontent.com/opencv/opencv_contrib/master/modules/cvv/.clang-format --- .../perf/perf_edgepreserving_filter.cpp | 61 +- .../samples/edgepreserving_filter_demo.cpp | 22 +- .../ximgproc/src/edgepreserving_filter.cpp | 573 ++++++++---------- 3 files changed, 299 insertions(+), 357 deletions(-) diff --git a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp index e59614bc52a..2caf3e9222f 100644 --- a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp +++ b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp @@ -1,9 +1,12 @@ // This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. #include "perf_precomp.hpp" -namespace opencv_test { namespace { +namespace opencv_test +{ +namespace +{ /* 1. Define parameter type and test fixture */ typedef tuple RGFTestParam; @@ -11,34 +14,30 @@ typedef TestBaseWithParam EdgepreservingFilterTest; /* 2. Declare the testsuite */ PERF_TEST_P(EdgepreservingFilterTest, perf, - Combine( - Values(-20, 0, 10), - Values(-100, 0 , 20)) -) + Combine(Values(-20, 0, 10), Values(-100, 0, 20))) { - /* 3. Get actual test parameters */ - RGFTestParam params = GetParam(); - int kernelSize = get<0>(params); - double threshold = get<1>(params); - - - /* 4. Allocate and initialize arguments for tested function */ - std::string filename = getDataPath("samples/data/corridor.jpg"); - Mat src = imread(filename, 1); - Mat dst(src.size(), src.type()); - - /* 5. Manifest your expectations about this test */ - declare.in(src, WARMUP_RNG).out(dst); - - /* 6. Collect the samples! */ - TEST_CYCLE_N(1) - { - ximgproc::edgepreservingFilter(src, dst, kernelSize, threshold); - } - - /* 7. Do not check anything */ - SANITY_CHECK_NOTHING(); + /* 3. Get actual test parameters */ + RGFTestParam params = GetParam(); + int kernelSize = get<0>(params); + double threshold = get<1>(params); + + /* 4. Allocate and initialize arguments for tested function */ + std::string filename = getDataPath("samples/data/corridor.jpg"); + Mat src = imread(filename, 1); + Mat dst(src.size(), src.type()); + + /* 5. Manifest your expectations about this test */ + declare.in(src, WARMUP_RNG).out(dst); + + /* 6. Collect the samples! */ + TEST_CYCLE_N(1) + { + ximgproc::edgepreservingFilter(src, dst, kernelSize, threshold); + } + + /* 7. Do not check anything */ + SANITY_CHECK_NOTHING(); } - -}} // namespace +} // namespace +} // namespace opencv_test diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp index f718a4faee6..4fb1ba5bfb0 100644 --- a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -1,23 +1,21 @@ #include -#include #include #include - +#include using namespace cv; - int main(int argc, char **argv) { - cv::CommandLineParser parser(argc, argv, - "{help h ? | | help message}" - "{@image | | Image filename to process }" - ); - if (parser.has("help") || !parser.has("@image")) - { - parser.printMessage(); - return 0; - } + cv::CommandLineParser parser( + argc, argv, + "{help h ? | | help message}" + "{@image | | Image filename to process }"); + if (parser.has("help") || !parser.has("@image")) + { + parser.printMessage(); + return 0; + } // Load image from first parameter std::string filename = parser.get("@image"); diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 6ec6f360b95..8bf5697067b 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -1,11 +1,10 @@ // This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. +// It is subject to the license terms in the LICENSE file found in the top-level +// directory of this distribution and at http://opencv.org/license.html. // // Created by Simon Reich // - #include "precomp.hpp" namespace cv @@ -14,350 +13,296 @@ namespace ximgproc { using namespace std; - void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, - double threshold) - { - Mat src = _src.getMat(); - - // [re]create the output array so that it has the proper size and type. - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - src.copyTo(dst); +void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, + double threshold) +{ + Mat src = _src.getMat(); + // [re]create the output array so that it has the proper size and type. + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + src.copyTo(dst); - CV_Assert(src.type() == CV_8UC3); + CV_Assert(src.type() == CV_8UC3); - if (d < 3) - d = 3; - int subwindowX = d, subwindowY = d; + if (d < 3) + d = 3; + int subwindowX = d, subwindowY = d; - if (threshold < 0) - threshold = 0; + if (threshold < 0) + threshold = 0; - // number of image channels - int nChannel = src.channels(); + // number of image channels + int nChannel = src.channels(); - vector pixel(nChannel, 0); - vector < vector > line1(src.rows, pixel); - vector < vector > > weight(src.cols, - line1); // global weights - vector < vector < vector > > imageResult( - src.cols, line1); // global normalized image + vector pixel(nChannel, 0); + vector> line1(src.rows, pixel); + vector>> weight(src.cols, + line1); // global weights + vector>> imageResult( + src.cols, line1); // global normalized image - // do algorithm - cv::Mat subwindow; - for (int posX = 0; posX < src.cols - subwindowX; posX++) + // do algorithm + cv::Mat subwindow; + for (int posX = 0; posX < src.cols - subwindowX; posX++) + { + for (int posY = 0; posY < src.rows - subwindowY; posY++) { - for (int posY = 0; posY < src.rows - subwindowY; - posY++) - { - cv::Rect roi = cv::Rect(posX, posY, subwindowX, - subwindowY); - subwindow = src(roi); - cv::Mat subwindow1 = src(roi); - cv::GaussianBlur(subwindow1, subwindow, - cv::Size(5, 5), 0.3, 0.3); + cv::Rect roi = + cv::Rect(posX, posY, subwindowX, subwindowY); + subwindow = src(roi); + cv::Mat subwindow1 = src(roi); + cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), + 0.3, 0.3); - // compute arithmetic mean of subwindow - cv::Scalar ArithmeticMean = cv::mean(subwindow); + // compute arithmetic mean of subwindow + cv::Scalar ArithmeticMean = cv::mean(subwindow); - // compute pixelwise distance - vector < vector > pixelwiseDist; + // compute pixelwise distance + vector> pixelwiseDist; - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + vector line; + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) { - vector line; - for (int subPosY = 0; - subPosY < subwindow.rows; - subPosY++) - { - cv::Vec3b intensity = - subwindow.at( - subPosY, subPosX); - double distance = - ((double)intensity.val[0] - - ArithmeticMean[0]) * - ((double) - intensity.val[0] - - ArithmeticMean[0]) + - ((double)intensity.val[1] - - ArithmeticMean[1]) * - ((double) - intensity.val[1] - - ArithmeticMean[1]) + - ((double)intensity.val[2] - - ArithmeticMean[2]) * - ((double) - intensity.val[2] - - ArithmeticMean[2]); - distance = sqrt(distance); - - line.push_back(distance); - }; + cv::Vec3b intensity = + subwindow.at(subPosY, + subPosX); + double distance = + ((double)intensity.val[0] - + ArithmeticMean[0]) * + ((double)intensity.val[0] - + ArithmeticMean[0]) + + ((double)intensity.val[1] - + ArithmeticMean[1]) * + ((double)intensity.val[1] - + ArithmeticMean[1]) + + ((double)intensity.val[2] - + ArithmeticMean[2]) * + ((double)intensity.val[2] - + ArithmeticMean[2]); + distance = sqrt(distance); - pixelwiseDist.push_back(line); + line.push_back(distance); }; - // compute mean pixelwise distance - double meanPixelwiseDist = 0; + pixelwiseDist.push_back(line); + }; + + // compute mean pixelwise distance + double meanPixelwiseDist = 0; - for (int i = 0; i < (int)pixelwiseDist.size(); - i++) - for (int j = 0; - j < (int)pixelwiseDist[i].size(); - j++) - meanPixelwiseDist += - pixelwiseDist[i][j]; + for (int i = 0; i < (int)pixelwiseDist.size(); i++) + for (int j = 0; + j < (int)pixelwiseDist[i].size(); j++) + meanPixelwiseDist += + pixelwiseDist[i][j]; - meanPixelwiseDist /= - ((int)pixelwiseDist.size() * - (int)pixelwiseDist[0].size()); + meanPixelwiseDist /= ((int)pixelwiseDist.size() * + (int)pixelwiseDist[0].size()); - // detect edge - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) + // detect edge + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) { - for (int subPosY = 0; - subPosY < subwindow.rows; - subPosY++) + if (meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] <= + threshold) { - if (meanPixelwiseDist <= - threshold && - pixelwiseDist[subPosX] - [subPosY] <= - threshold) - { - // global Position - int globalPosX = - posX + subPosX; - int globalPosY = - posY + subPosY; + // global Position + int globalPosX = posX + subPosX; + int globalPosY = posY + subPosY; - // compute global weight - cv::Vec3b intensity = - subwindow - .at( - subPosY, - subPosX); - weight[globalPosX] - [globalPosY][0] += - intensity.val[0] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]); - weight[globalPosX] - [globalPosY][1] += - intensity.val[1] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]); - weight[globalPosX] - [globalPosY][2] += - intensity.val[2] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]); + // compute global weight + cv::Vec3b intensity = + subwindow.at( + subPosY, subPosX); + weight[globalPosX][globalPosY] + [0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); - // compute final image - imageResult[globalPosX] - [globalPosY] - [0] += - intensity.val[0] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - ArithmeticMean[0]; - imageResult[globalPosX] - [globalPosY] - [1] += - intensity.val[1] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - ArithmeticMean[1]; - imageResult[globalPosX] - [globalPosY] - [2] += - intensity.val[2] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - ArithmeticMean[2]; - } - else if (meanPixelwiseDist <= - threshold && - pixelwiseDist - [subPosX] - [subPosY] > - threshold) - { - // global Position - int globalPosX = - posX + subPosX; - int globalPosY = - posY + subPosY; + // compute final image + imageResult[globalPosX] + [globalPosY][0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[0]; + imageResult[globalPosX] + [globalPosY][1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[1]; + imageResult[globalPosX] + [globalPosY][2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[2]; + } + else if (meanPixelwiseDist <= + threshold && + pixelwiseDist[subPosX] + [subPosY] > + threshold) + { + // global Position + int globalPosX = posX + subPosX; + int globalPosY = posY + subPosY; - // compute global weight - cv::Vec3b intensity = - subwindow - .at( - subPosY, - subPosX); - weight[globalPosX] - [globalPosY][0] += - intensity.val[0] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]); - weight[globalPosX] - [globalPosY][1] += - intensity.val[1] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]); - weight[globalPosX] - [globalPosY][2] += - intensity.val[2] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]); + // compute global weight + cv::Vec3b intensity = + subwindow.at( + subPosY, subPosX); + weight[globalPosX][globalPosY] + [0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); - // compute final image - imageResult[globalPosX] - [globalPosY] - [0] += - intensity.val[0] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - ArithmeticMean[0]; - imageResult[globalPosX] - [globalPosY] - [1] += - intensity.val[1] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - ArithmeticMean[1]; - imageResult[globalPosX] - [globalPosY] - [2] += - intensity.val[2] * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - (threshold - - pixelwiseDist - [subPosX] - [subPosY]) * - ArithmeticMean[2]; - }; + // compute final image + imageResult[globalPosX] + [globalPosY][0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[0]; + imageResult[globalPosX] + [globalPosY][1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[1]; + imageResult[globalPosX] + [globalPosY][2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[2]; }; }; }; }; + }; - // compute final image - for (int globalPosX = 0; globalPosX < (int)imageResult.size(); - globalPosX++) + // compute final image + for (int globalPosX = 0; globalPosX < (int)imageResult.size(); + globalPosX++) + { + for (int globalPosY = 0; + globalPosY < (int)imageResult[globalPosX].size(); + globalPosY++) { - for (int globalPosY = 0; - globalPosY < (int)imageResult[globalPosX].size(); - globalPosY++) - { - // cout << "globalPosX: " << globalPosX << "/" - // << dst.cols << "," << imageResult.size () << - // "\tglobalPosY: " << globalPosY << "/" << - // dst.rows << "," <(globalPosY, globalPosX); - imageResult[globalPosX][globalPosY][0] += - (double)intensity.val[0]; - imageResult[globalPosX][globalPosY][1] += - (double)intensity.val[1]; - imageResult[globalPosX][globalPosY][2] += - (double)intensity.val[2]; + // add image to result + cv::Vec3b intensity = + src.at(globalPosY, globalPosX); + imageResult[globalPosX][globalPosY][0] += + (double)intensity.val[0]; + imageResult[globalPosX][globalPosY][1] += + (double)intensity.val[1]; + imageResult[globalPosX][globalPosY][2] += + (double)intensity.val[2]; - // normalize using weight - imageResult[globalPosX][globalPosY][0] /= - (weight[globalPosX][globalPosY][0] + 1); - imageResult[globalPosX][globalPosY][1] /= - (weight[globalPosX][globalPosY][1] + 1); - imageResult[globalPosX][globalPosY][2] /= - (weight[globalPosX][globalPosY][2] + 1); + // normalize using weight + imageResult[globalPosX][globalPosY][0] /= + (weight[globalPosX][globalPosY][0] + 1); + imageResult[globalPosX][globalPosY][1] /= + (weight[globalPosX][globalPosY][1] + 1); + imageResult[globalPosX][globalPosY][2] /= + (weight[globalPosX][globalPosY][2] + 1); - // copy to output image frame - dst.at(globalPosY, globalPosX)[0] = - (uchar) - imageResult[globalPosX][globalPosY][0]; - dst.at(globalPosY, globalPosX)[1] = - (uchar) - imageResult[globalPosX][globalPosY][1]; - dst.at(globalPosY, globalPosX)[2] = - (uchar) - imageResult[globalPosX][globalPosY][2]; - }; + // copy to output image frame + dst.at(globalPosY, globalPosX)[0] = + (uchar)imageResult[globalPosX][globalPosY][0]; + dst.at(globalPosY, globalPosX)[1] = + (uchar)imageResult[globalPosX][globalPosY][1]; + dst.at(globalPosY, globalPosX)[2] = + (uchar)imageResult[globalPosX][globalPosY][2]; }; - } + }; +} } // namespace ximgproc } // namespace cv From 7e89c3d312d5e9ac98743a3506ad26f2fc025462 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Tue, 31 Jul 2018 13:22:39 +0200 Subject: [PATCH 14/26] Merged historic if... else if statement into one if statement --- .../ximgproc/src/edgepreserving_filter.cpp | 83 ++----------------- 1 file changed, 6 insertions(+), 77 deletions(-) diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 8bf5697067b..0cda6f3aed2 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -111,83 +111,12 @@ void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, for (int subPosY = 0; subPosY < subwindow.rows; subPosY++) { - if (meanPixelwiseDist <= threshold && - pixelwiseDist[subPosX][subPosY] <= - threshold) - { - // global Position - int globalPosX = posX + subPosX; - int globalPosY = posY + subPosY; - - // compute global weight - cv::Vec3b intensity = - subwindow.at( - subPosY, subPosX); - weight[globalPosX][globalPosY] - [0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - - // compute final image - imageResult[globalPosX] - [globalPosY][0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[0]; - imageResult[globalPosX] - [globalPosY][1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[1]; - imageResult[globalPosX] - [globalPosY][2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[2]; - } - else if (meanPixelwiseDist <= - threshold && - pixelwiseDist[subPosX] - [subPosY] > - threshold) + if ((meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] <= + threshold) || + (meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] > + threshold)) { // global Position int globalPosX = posX + subPosX; From 1b079bd2fbdfc7db32b8479f710e92bcb4cf1730 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 08:17:28 +0200 Subject: [PATCH 15/26] Trailing whitespace removed and .. changed into . --- .../include/opencv2/ximgproc/edgepreserving_filter.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp index d40e5d253f7..4caa8b4df61 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp @@ -17,11 +17,11 @@ namespace cv { namespace ximgproc { * * The function smoothes Gaussian noise as well as salt & pepper noise. * For more details about this implementation, please see - * [ReiWoe18] Reich, S. and Wörgötter, F. and Dellen, B. (2018). A Real-Time Edge-Preserving Denoising Filter. Proceedings of the 13th International Joint Conference on Computer Vision, Imaging and Computer Graphics Theory and Applications (VISIGRAPP): Visapp, 85-94, 4. DOI: 10.5220/0006509000850094. + * [ReiWoe18] Reich, S. and Wörgötter, F. and Dellen, B. (2018). A Real-Time Edge-Preserving Denoising Filter. Proceedings of the 13th International Joint Conference on Computer Vision, Imaging and Computer Graphics Theory and Applications (VISIGRAPP): Visapp, 85-94, 4. DOI: 10.5220/0006509000850094. * * @param src Source 8-bit 3-channel image. * @param dst Destination image of the same size and type as src. - * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3.. + * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3. * @param threshold Threshold, which distinguishes between noise, outliers, and data. */ CV_EXPORTS_W void edgepreservingFilter( const InputArray src, OutputArray dst, int d, double threshold ); From 16ee637ddbfc7c901116513a2df71869250504dd Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 08:50:35 +0200 Subject: [PATCH 16/26] Tabs replaced with 4 spaces. --- .../perf/perf_edgepreserving_filter.cpp | 41 +- .../samples/edgepreserving_filter_demo.cpp | 64 +-- .../ximgproc/src/edgepreserving_filter.cpp | 432 +++++++++--------- 3 files changed, 268 insertions(+), 269 deletions(-) diff --git a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp index 2caf3e9222f..8c58a4af300 100644 --- a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp +++ b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp @@ -16,27 +16,26 @@ typedef TestBaseWithParam EdgepreservingFilterTest; PERF_TEST_P(EdgepreservingFilterTest, perf, Combine(Values(-20, 0, 10), Values(-100, 0, 20))) { - /* 3. Get actual test parameters */ - RGFTestParam params = GetParam(); - int kernelSize = get<0>(params); - double threshold = get<1>(params); - - /* 4. Allocate and initialize arguments for tested function */ - std::string filename = getDataPath("samples/data/corridor.jpg"); - Mat src = imread(filename, 1); - Mat dst(src.size(), src.type()); - - /* 5. Manifest your expectations about this test */ - declare.in(src, WARMUP_RNG).out(dst); - - /* 6. Collect the samples! */ - TEST_CYCLE_N(1) - { - ximgproc::edgepreservingFilter(src, dst, kernelSize, threshold); - } - - /* 7. Do not check anything */ - SANITY_CHECK_NOTHING(); + /* 3. Get actual test parameters */ + RGFTestParam params = GetParam(); + int kernelSize = get<0>(params); + double threshold = get<1>(params); + + /* 4. Allocate and initialize arguments for tested function */ + std::string filename = getDataPath("testdata/perf/320x260.png"); + Mat src = imread(filename, 1); + Mat dst(src.size(), src.type()); + + /* 5. Manifest your expectations about this test */ + declare.in(src).out(dst); + + /* 6. Collect the samples! */ + PERF_SAMPLE_BEGIN(); + ximgproc::edgepreservingFilter(src, dst, kernelSize, threshold); + PERF_SAMPLE_END(); + + /* 7. Do not check anything */ + SANITY_CHECK_NOTHING(); } } // namespace diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp index 4fb1ba5bfb0..e7513214b12 100644 --- a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -7,36 +7,36 @@ using namespace cv; int main(int argc, char **argv) { - cv::CommandLineParser parser( - argc, argv, - "{help h ? | | help message}" - "{@image | | Image filename to process }"); - if (parser.has("help") || !parser.has("@image")) - { - parser.printMessage(); - return 0; - } - - // Load image from first parameter - std::string filename = parser.get("@image"); - Mat image = imread(filename, 1), res; - - if (!image.data) - { - std::cerr << "No image data at " << filename << std::endl; - throw; - } - - // Before filtering - imshow("Original image", image); - waitKey(0); - - // Initialize filter. Kernel size 5x5, threshold 20 - ximgproc::edgepreservingFilter(image, res, 9, 20); - - // After filtering - imshow("Filtered image", res); - waitKey(0); - - return 0; + cv::CommandLineParser parser( + argc, argv, + "{help h ? | | help message}" + "{@image | | Image filename to process }"); + if (parser.has("help") || !parser.has("@image")) + { + parser.printMessage(); + return 0; + } + + // Load image from first parameter + std::string filename = parser.get("@image"); + Mat image = imread(filename, 1), res; + + if (!image.data) + { + std::cerr << "No image data at " << filename << std::endl; + throw; + } + + // Before filtering + imshow("Original image", image); + waitKey(0); + + // Initialize filter. Kernel size 5x5, threshold 20 + ximgproc::edgepreservingFilter(image, res, 9, 20); + + // After filtering + imshow("Filtered image", res); + waitKey(0); + + return 0; } diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 0cda6f3aed2..3ea2e91ff5a 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -16,222 +16,222 @@ using namespace std; void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, double threshold) { - Mat src = _src.getMat(); - - // [re]create the output array so that it has the proper size and type. - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - src.copyTo(dst); - - CV_Assert(src.type() == CV_8UC3); - - if (d < 3) - d = 3; - int subwindowX = d, subwindowY = d; - - if (threshold < 0) - threshold = 0; - - // number of image channels - int nChannel = src.channels(); - - vector pixel(nChannel, 0); - vector> line1(src.rows, pixel); - vector>> weight(src.cols, - line1); // global weights - vector>> imageResult( - src.cols, line1); // global normalized image - - // do algorithm - cv::Mat subwindow; - for (int posX = 0; posX < src.cols - subwindowX; posX++) - { - for (int posY = 0; posY < src.rows - subwindowY; posY++) - { - cv::Rect roi = - cv::Rect(posX, posY, subwindowX, subwindowY); - subwindow = src(roi); - cv::Mat subwindow1 = src(roi); - cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), - 0.3, 0.3); - - // compute arithmetic mean of subwindow - cv::Scalar ArithmeticMean = cv::mean(subwindow); - - // compute pixelwise distance - vector> pixelwiseDist; - - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) - { - vector line; - for (int subPosY = 0; subPosY < subwindow.rows; - subPosY++) - { - cv::Vec3b intensity = - subwindow.at(subPosY, - subPosX); - double distance = - ((double)intensity.val[0] - - ArithmeticMean[0]) * - ((double)intensity.val[0] - - ArithmeticMean[0]) + - ((double)intensity.val[1] - - ArithmeticMean[1]) * - ((double)intensity.val[1] - - ArithmeticMean[1]) + - ((double)intensity.val[2] - - ArithmeticMean[2]) * - ((double)intensity.val[2] - - ArithmeticMean[2]); - distance = sqrt(distance); - - line.push_back(distance); - }; - - pixelwiseDist.push_back(line); - }; - - // compute mean pixelwise distance - double meanPixelwiseDist = 0; - - for (int i = 0; i < (int)pixelwiseDist.size(); i++) - for (int j = 0; - j < (int)pixelwiseDist[i].size(); j++) - meanPixelwiseDist += - pixelwiseDist[i][j]; - - meanPixelwiseDist /= ((int)pixelwiseDist.size() * - (int)pixelwiseDist[0].size()); - - // detect edge - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) - { - for (int subPosY = 0; subPosY < subwindow.rows; - subPosY++) - { - if ((meanPixelwiseDist <= threshold && - pixelwiseDist[subPosX][subPosY] <= - threshold) || - (meanPixelwiseDist <= threshold && - pixelwiseDist[subPosX][subPosY] > - threshold)) - { - // global Position - int globalPosX = posX + subPosX; - int globalPosY = posY + subPosY; - - // compute global weight - cv::Vec3b intensity = - subwindow.at( - subPosY, subPosX); - weight[globalPosX][globalPosY] - [0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - - // compute final image - imageResult[globalPosX] - [globalPosY][0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[0]; - imageResult[globalPosX] - [globalPosY][1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[1]; - imageResult[globalPosX] - [globalPosY][2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[2]; - }; - }; - }; - }; - }; - - // compute final image - for (int globalPosX = 0; globalPosX < (int)imageResult.size(); - globalPosX++) - { - for (int globalPosY = 0; - globalPosY < (int)imageResult[globalPosX].size(); - globalPosY++) - { - // cout << "globalPosX: " << globalPosX << "/" - // << dst.cols << "," << imageResult.size () << - // "\tglobalPosY: " << globalPosY << "/" << - // dst.rows << "," <(globalPosY, globalPosX); - imageResult[globalPosX][globalPosY][0] += - (double)intensity.val[0]; - imageResult[globalPosX][globalPosY][1] += - (double)intensity.val[1]; - imageResult[globalPosX][globalPosY][2] += - (double)intensity.val[2]; - - // normalize using weight - imageResult[globalPosX][globalPosY][0] /= - (weight[globalPosX][globalPosY][0] + 1); - imageResult[globalPosX][globalPosY][1] /= - (weight[globalPosX][globalPosY][1] + 1); - imageResult[globalPosX][globalPosY][2] /= - (weight[globalPosX][globalPosY][2] + 1); - - // copy to output image frame - dst.at(globalPosY, globalPosX)[0] = - (uchar)imageResult[globalPosX][globalPosY][0]; - dst.at(globalPosY, globalPosX)[1] = - (uchar)imageResult[globalPosX][globalPosY][1]; - dst.at(globalPosY, globalPosX)[2] = - (uchar)imageResult[globalPosX][globalPosY][2]; - }; - }; + Mat src = _src.getMat(); + + // [re]create the output array so that it has the proper size and type. + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + src.copyTo(dst); + + CV_Assert(src.type() == CV_8UC3); + + if (d < 3) + d = 3; + int subwindowX = d, subwindowY = d; + + if (threshold < 0) + threshold = 0; + + // number of image channels + int nChannel = src.channels(); + + vector pixel(nChannel, 0); + vector> line1(src.rows, pixel); + vector>> weight(src.cols, + line1); // global weights + vector>> imageResult( + src.cols, line1); // global normalized image + + // do algorithm + cv::Mat subwindow; + for (int posX = 0; posX < src.cols - subwindowX; posX++) + { + for (int posY = 0; posY < src.rows - subwindowY; posY++) + { + cv::Rect roi = + cv::Rect(posX, posY, subwindowX, subwindowY); + subwindow = src(roi); + cv::Mat subwindow1 = src(roi); + cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), + 0.3, 0.3); + + // compute arithmetic mean of subwindow + cv::Scalar ArithmeticMean = cv::mean(subwindow); + + // compute pixelwise distance + vector> pixelwiseDist; + + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + vector line; + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) + { + cv::Vec3b intensity = + subwindow.at(subPosY, + subPosX); + double distance = + ((double)intensity.val[0] - + ArithmeticMean[0]) * + ((double)intensity.val[0] - + ArithmeticMean[0]) + + ((double)intensity.val[1] - + ArithmeticMean[1]) * + ((double)intensity.val[1] - + ArithmeticMean[1]) + + ((double)intensity.val[2] - + ArithmeticMean[2]) * + ((double)intensity.val[2] - + ArithmeticMean[2]); + distance = sqrt(distance); + + line.push_back(distance); + }; + + pixelwiseDist.push_back(line); + }; + + // compute mean pixelwise distance + double meanPixelwiseDist = 0; + + for (int i = 0; i < (int)pixelwiseDist.size(); i++) + for (int j = 0; + j < (int)pixelwiseDist[i].size(); j++) + meanPixelwiseDist += + pixelwiseDist[i][j]; + + meanPixelwiseDist /= ((int)pixelwiseDist.size() * + (int)pixelwiseDist[0].size()); + + // detect edge + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) + { + if ((meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] <= + threshold) || + (meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] > + threshold)) + { + // global Position + int globalPosX = posX + subPosX; + int globalPosY = posY + subPosY; + + // compute global weight + cv::Vec3b intensity = + subwindow.at( + subPosY, subPosX); + weight[globalPosX][globalPosY] + [0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + + // compute final image + imageResult[globalPosX] + [globalPosY][0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[0]; + imageResult[globalPosX] + [globalPosY][1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[1]; + imageResult[globalPosX] + [globalPosY][2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[2]; + }; + }; + }; + }; + }; + + // compute final image + for (int globalPosX = 0; globalPosX < (int)imageResult.size(); + globalPosX++) + { + for (int globalPosY = 0; + globalPosY < (int)imageResult[globalPosX].size(); + globalPosY++) + { + // cout << "globalPosX: " << globalPosX << "/" + // << dst.cols << "," << imageResult.size () << + // "\tglobalPosY: " << globalPosY << "/" << + // dst.rows << "," <(globalPosY, globalPosX); + imageResult[globalPosX][globalPosY][0] += + (double)intensity.val[0]; + imageResult[globalPosX][globalPosY][1] += + (double)intensity.val[1]; + imageResult[globalPosX][globalPosY][2] += + (double)intensity.val[2]; + + // normalize using weight + imageResult[globalPosX][globalPosY][0] /= + (weight[globalPosX][globalPosY][0] + 1); + imageResult[globalPosX][globalPosY][1] /= + (weight[globalPosX][globalPosY][1] + 1); + imageResult[globalPosX][globalPosY][2] /= + (weight[globalPosX][globalPosY][2] + 1); + + // copy to output image frame + dst.at(globalPosY, globalPosX)[0] = + (uchar)imageResult[globalPosX][globalPosY][0]; + dst.at(globalPosY, globalPosX)[1] = + (uchar)imageResult[globalPosX][globalPosY][1]; + dst.at(globalPosY, globalPosX)[2] = + (uchar)imageResult[globalPosX][globalPosY][2]; + }; + }; } } // namespace ximgproc } // namespace cv From 3216c787044f78a84773f40e9705d0a0bae0b60c Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 09:01:14 +0200 Subject: [PATCH 17/26] Removed subwindow = src(roi); --- modules/ximgproc/src/edgepreserving_filter.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 3ea2e91ff5a..86ee4d01c00 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -43,15 +43,14 @@ void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, src.cols, line1); // global normalized image // do algorithm - cv::Mat subwindow; + cv::Mat subwindow, subwindow1; for (int posX = 0; posX < src.cols - subwindowX; posX++) { for (int posY = 0; posY < src.rows - subwindowY; posY++) { cv::Rect roi = cv::Rect(posX, posY, subwindowX, subwindowY); - subwindow = src(roi); - cv::Mat subwindow1 = src(roi); + subwindow1 = src(roi); cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), 0.3, 0.3); From 5fa0aba5f83c0e4082cdba123ca955dfa1344770 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 09:02:39 +0200 Subject: [PATCH 18/26] Moved type test to beginning of code --- .../ximgproc/src/edgepreserving_filter.cpp | 431 +++++++++--------- 1 file changed, 216 insertions(+), 215 deletions(-) diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 86ee4d01c00..0cda6f3aed2 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -16,221 +16,222 @@ using namespace std; void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, double threshold) { - Mat src = _src.getMat(); - - // [re]create the output array so that it has the proper size and type. - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - src.copyTo(dst); - - CV_Assert(src.type() == CV_8UC3); - - if (d < 3) - d = 3; - int subwindowX = d, subwindowY = d; - - if (threshold < 0) - threshold = 0; - - // number of image channels - int nChannel = src.channels(); - - vector pixel(nChannel, 0); - vector> line1(src.rows, pixel); - vector>> weight(src.cols, - line1); // global weights - vector>> imageResult( - src.cols, line1); // global normalized image - - // do algorithm - cv::Mat subwindow, subwindow1; - for (int posX = 0; posX < src.cols - subwindowX; posX++) - { - for (int posY = 0; posY < src.rows - subwindowY; posY++) - { - cv::Rect roi = - cv::Rect(posX, posY, subwindowX, subwindowY); - subwindow1 = src(roi); - cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), - 0.3, 0.3); - - // compute arithmetic mean of subwindow - cv::Scalar ArithmeticMean = cv::mean(subwindow); - - // compute pixelwise distance - vector> pixelwiseDist; - - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) - { - vector line; - for (int subPosY = 0; subPosY < subwindow.rows; - subPosY++) - { - cv::Vec3b intensity = - subwindow.at(subPosY, - subPosX); - double distance = - ((double)intensity.val[0] - - ArithmeticMean[0]) * - ((double)intensity.val[0] - - ArithmeticMean[0]) + - ((double)intensity.val[1] - - ArithmeticMean[1]) * - ((double)intensity.val[1] - - ArithmeticMean[1]) + - ((double)intensity.val[2] - - ArithmeticMean[2]) * - ((double)intensity.val[2] - - ArithmeticMean[2]); - distance = sqrt(distance); - - line.push_back(distance); - }; - - pixelwiseDist.push_back(line); - }; - - // compute mean pixelwise distance - double meanPixelwiseDist = 0; - - for (int i = 0; i < (int)pixelwiseDist.size(); i++) - for (int j = 0; - j < (int)pixelwiseDist[i].size(); j++) - meanPixelwiseDist += - pixelwiseDist[i][j]; - - meanPixelwiseDist /= ((int)pixelwiseDist.size() * - (int)pixelwiseDist[0].size()); - - // detect edge - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) - { - for (int subPosY = 0; subPosY < subwindow.rows; - subPosY++) - { - if ((meanPixelwiseDist <= threshold && - pixelwiseDist[subPosX][subPosY] <= - threshold) || - (meanPixelwiseDist <= threshold && - pixelwiseDist[subPosX][subPosY] > - threshold)) - { - // global Position - int globalPosX = posX + subPosX; - int globalPosY = posY + subPosY; - - // compute global weight - cv::Vec3b intensity = - subwindow.at( - subPosY, subPosX); - weight[globalPosX][globalPosY] - [0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - - // compute final image - imageResult[globalPosX] - [globalPosY][0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[0]; - imageResult[globalPosX] - [globalPosY][1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[1]; - imageResult[globalPosX] - [globalPosY][2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[2]; - }; - }; - }; - }; - }; - - // compute final image - for (int globalPosX = 0; globalPosX < (int)imageResult.size(); - globalPosX++) - { - for (int globalPosY = 0; - globalPosY < (int)imageResult[globalPosX].size(); - globalPosY++) - { - // cout << "globalPosX: " << globalPosX << "/" - // << dst.cols << "," << imageResult.size () << - // "\tglobalPosY: " << globalPosY << "/" << - // dst.rows << "," <(globalPosY, globalPosX); - imageResult[globalPosX][globalPosY][0] += - (double)intensity.val[0]; - imageResult[globalPosX][globalPosY][1] += - (double)intensity.val[1]; - imageResult[globalPosX][globalPosY][2] += - (double)intensity.val[2]; - - // normalize using weight - imageResult[globalPosX][globalPosY][0] /= - (weight[globalPosX][globalPosY][0] + 1); - imageResult[globalPosX][globalPosY][1] /= - (weight[globalPosX][globalPosY][1] + 1); - imageResult[globalPosX][globalPosY][2] /= - (weight[globalPosX][globalPosY][2] + 1); - - // copy to output image frame - dst.at(globalPosY, globalPosX)[0] = - (uchar)imageResult[globalPosX][globalPosY][0]; - dst.at(globalPosY, globalPosX)[1] = - (uchar)imageResult[globalPosX][globalPosY][1]; - dst.at(globalPosY, globalPosX)[2] = - (uchar)imageResult[globalPosX][globalPosY][2]; - }; - }; + Mat src = _src.getMat(); + + // [re]create the output array so that it has the proper size and type. + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + src.copyTo(dst); + + CV_Assert(src.type() == CV_8UC3); + + if (d < 3) + d = 3; + int subwindowX = d, subwindowY = d; + + if (threshold < 0) + threshold = 0; + + // number of image channels + int nChannel = src.channels(); + + vector pixel(nChannel, 0); + vector> line1(src.rows, pixel); + vector>> weight(src.cols, + line1); // global weights + vector>> imageResult( + src.cols, line1); // global normalized image + + // do algorithm + cv::Mat subwindow; + for (int posX = 0; posX < src.cols - subwindowX; posX++) + { + for (int posY = 0; posY < src.rows - subwindowY; posY++) + { + cv::Rect roi = + cv::Rect(posX, posY, subwindowX, subwindowY); + subwindow = src(roi); + cv::Mat subwindow1 = src(roi); + cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), + 0.3, 0.3); + + // compute arithmetic mean of subwindow + cv::Scalar ArithmeticMean = cv::mean(subwindow); + + // compute pixelwise distance + vector> pixelwiseDist; + + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + vector line; + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) + { + cv::Vec3b intensity = + subwindow.at(subPosY, + subPosX); + double distance = + ((double)intensity.val[0] - + ArithmeticMean[0]) * + ((double)intensity.val[0] - + ArithmeticMean[0]) + + ((double)intensity.val[1] - + ArithmeticMean[1]) * + ((double)intensity.val[1] - + ArithmeticMean[1]) + + ((double)intensity.val[2] - + ArithmeticMean[2]) * + ((double)intensity.val[2] - + ArithmeticMean[2]); + distance = sqrt(distance); + + line.push_back(distance); + }; + + pixelwiseDist.push_back(line); + }; + + // compute mean pixelwise distance + double meanPixelwiseDist = 0; + + for (int i = 0; i < (int)pixelwiseDist.size(); i++) + for (int j = 0; + j < (int)pixelwiseDist[i].size(); j++) + meanPixelwiseDist += + pixelwiseDist[i][j]; + + meanPixelwiseDist /= ((int)pixelwiseDist.size() * + (int)pixelwiseDist[0].size()); + + // detect edge + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) + { + if ((meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] <= + threshold) || + (meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] > + threshold)) + { + // global Position + int globalPosX = posX + subPosX; + int globalPosY = posY + subPosY; + + // compute global weight + cv::Vec3b intensity = + subwindow.at( + subPosY, subPosX); + weight[globalPosX][globalPosY] + [0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + + // compute final image + imageResult[globalPosX] + [globalPosY][0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[0]; + imageResult[globalPosX] + [globalPosY][1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[1]; + imageResult[globalPosX] + [globalPosY][2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[2]; + }; + }; + }; + }; + }; + + // compute final image + for (int globalPosX = 0; globalPosX < (int)imageResult.size(); + globalPosX++) + { + for (int globalPosY = 0; + globalPosY < (int)imageResult[globalPosX].size(); + globalPosY++) + { + // cout << "globalPosX: " << globalPosX << "/" + // << dst.cols << "," << imageResult.size () << + // "\tglobalPosY: " << globalPosY << "/" << + // dst.rows << "," <(globalPosY, globalPosX); + imageResult[globalPosX][globalPosY][0] += + (double)intensity.val[0]; + imageResult[globalPosX][globalPosY][1] += + (double)intensity.val[1]; + imageResult[globalPosX][globalPosY][2] += + (double)intensity.val[2]; + + // normalize using weight + imageResult[globalPosX][globalPosY][0] /= + (weight[globalPosX][globalPosY][0] + 1); + imageResult[globalPosX][globalPosY][1] /= + (weight[globalPosX][globalPosY][1] + 1); + imageResult[globalPosX][globalPosY][2] /= + (weight[globalPosX][globalPosY][2] + 1); + + // copy to output image frame + dst.at(globalPosY, globalPosX)[0] = + (uchar)imageResult[globalPosX][globalPosY][0]; + dst.at(globalPosY, globalPosX)[1] = + (uchar)imageResult[globalPosX][globalPosY][1]; + dst.at(globalPosY, globalPosX)[2] = + (uchar)imageResult[globalPosX][globalPosY][2]; + }; + }; } } // namespace ximgproc } // namespace cv From 845d807459b7c240be19e7c024caf6dd71cb65d7 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 09:05:26 +0200 Subject: [PATCH 19/26] Removed indentation from namespace and added //! @} --- .../include/opencv2/ximgproc/edgepreserving_filter.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp index 4caa8b4df61..62bccbc7438 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp @@ -9,8 +9,8 @@ namespace cv { namespace ximgproc { - //! @addtogroup ximgproc - //! @{ +//! @addtogroup ximgproc +//! @{ /** * @brief Smoothes an image using the Edge-Preserving filter. @@ -28,4 +28,6 @@ namespace cv { namespace ximgproc { }} // namespace +//! @} + #endif From c6ea43fe97b6a1ea14a17d4048dc189dd10d61cf Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 09:14:52 +0200 Subject: [PATCH 20/26] Added name to header --- modules/ximgproc/perf/perf_edgepreserving_filter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp index 8c58a4af300..f4f44bd15fa 100644 --- a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp +++ b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp @@ -1,6 +1,9 @@ // This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level // directory of this distribution and at http://opencv.org/license.html. +// +// Created by Simon Reich +// #include "perf_precomp.hpp" namespace opencv_test From a91e629966a2b3c2dc46e88f7e54299b58fdd5e7 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 09:15:46 +0200 Subject: [PATCH 21/26] git cleanup introduced some errors fixed here --- .../ximgproc/src/edgepreserving_filter.cpp | 431 +++++++++--------- 1 file changed, 215 insertions(+), 216 deletions(-) diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 0cda6f3aed2..9822529bec4 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -16,222 +16,221 @@ using namespace std; void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, double threshold) { - Mat src = _src.getMat(); - - // [re]create the output array so that it has the proper size and type. - _dst.create(src.size(), src.type()); - Mat dst = _dst.getMat(); - src.copyTo(dst); - - CV_Assert(src.type() == CV_8UC3); - - if (d < 3) - d = 3; - int subwindowX = d, subwindowY = d; - - if (threshold < 0) - threshold = 0; - - // number of image channels - int nChannel = src.channels(); - - vector pixel(nChannel, 0); - vector> line1(src.rows, pixel); - vector>> weight(src.cols, - line1); // global weights - vector>> imageResult( - src.cols, line1); // global normalized image - - // do algorithm - cv::Mat subwindow; - for (int posX = 0; posX < src.cols - subwindowX; posX++) - { - for (int posY = 0; posY < src.rows - subwindowY; posY++) - { - cv::Rect roi = - cv::Rect(posX, posY, subwindowX, subwindowY); - subwindow = src(roi); - cv::Mat subwindow1 = src(roi); - cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), - 0.3, 0.3); - - // compute arithmetic mean of subwindow - cv::Scalar ArithmeticMean = cv::mean(subwindow); - - // compute pixelwise distance - vector> pixelwiseDist; - - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) - { - vector line; - for (int subPosY = 0; subPosY < subwindow.rows; - subPosY++) - { - cv::Vec3b intensity = - subwindow.at(subPosY, - subPosX); - double distance = - ((double)intensity.val[0] - - ArithmeticMean[0]) * - ((double)intensity.val[0] - - ArithmeticMean[0]) + - ((double)intensity.val[1] - - ArithmeticMean[1]) * - ((double)intensity.val[1] - - ArithmeticMean[1]) + - ((double)intensity.val[2] - - ArithmeticMean[2]) * - ((double)intensity.val[2] - - ArithmeticMean[2]); - distance = sqrt(distance); - - line.push_back(distance); - }; - - pixelwiseDist.push_back(line); - }; - - // compute mean pixelwise distance - double meanPixelwiseDist = 0; - - for (int i = 0; i < (int)pixelwiseDist.size(); i++) - for (int j = 0; - j < (int)pixelwiseDist[i].size(); j++) - meanPixelwiseDist += - pixelwiseDist[i][j]; - - meanPixelwiseDist /= ((int)pixelwiseDist.size() * - (int)pixelwiseDist[0].size()); - - // detect edge - for (int subPosX = 0; subPosX < subwindow.cols; - subPosX++) - { - for (int subPosY = 0; subPosY < subwindow.rows; - subPosY++) - { - if ((meanPixelwiseDist <= threshold && - pixelwiseDist[subPosX][subPosY] <= - threshold) || - (meanPixelwiseDist <= threshold && - pixelwiseDist[subPosX][subPosY] > - threshold)) - { - // global Position - int globalPosX = posX + subPosX; - int globalPosY = posY + subPosY; - - // compute global weight - cv::Vec3b intensity = - subwindow.at( - subPosY, subPosX); - weight[globalPosX][globalPosY] - [0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - weight[globalPosX][globalPosY] - [2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]); - - // compute final image - imageResult[globalPosX] - [globalPosY][0] += - intensity.val[0] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[0]; - imageResult[globalPosX] - [globalPosY][1] += - intensity.val[1] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[1]; - imageResult[globalPosX] - [globalPosY][2] += - intensity.val[2] * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - (threshold - - pixelwiseDist[subPosX] - [subPosY]) * - ArithmeticMean[2]; - }; - }; - }; - }; - }; - - // compute final image - for (int globalPosX = 0; globalPosX < (int)imageResult.size(); - globalPosX++) - { - for (int globalPosY = 0; - globalPosY < (int)imageResult[globalPosX].size(); - globalPosY++) - { - // cout << "globalPosX: " << globalPosX << "/" - // << dst.cols << "," << imageResult.size () << - // "\tglobalPosY: " << globalPosY << "/" << - // dst.rows << "," <(globalPosY, globalPosX); - imageResult[globalPosX][globalPosY][0] += - (double)intensity.val[0]; - imageResult[globalPosX][globalPosY][1] += - (double)intensity.val[1]; - imageResult[globalPosX][globalPosY][2] += - (double)intensity.val[2]; - - // normalize using weight - imageResult[globalPosX][globalPosY][0] /= - (weight[globalPosX][globalPosY][0] + 1); - imageResult[globalPosX][globalPosY][1] /= - (weight[globalPosX][globalPosY][1] + 1); - imageResult[globalPosX][globalPosY][2] /= - (weight[globalPosX][globalPosY][2] + 1); - - // copy to output image frame - dst.at(globalPosY, globalPosX)[0] = - (uchar)imageResult[globalPosX][globalPosY][0]; - dst.at(globalPosY, globalPosX)[1] = - (uchar)imageResult[globalPosX][globalPosY][1]; - dst.at(globalPosY, globalPosX)[2] = - (uchar)imageResult[globalPosX][globalPosY][2]; - }; - }; + CV_Assert(_src.type() == CV_8UC3); + + Mat src = _src.getMat(); + + // [re]create the output array so that it has the proper size and type. + _dst.create(src.size(), src.type()); + Mat dst = _dst.getMat(); + src.copyTo(dst); + + if (d < 3) + d = 3; + int subwindowX = d, subwindowY = d; + + if (threshold < 0) + threshold = 0; + + // number of image channels + int nChannel = src.channels(); + + vector pixel(nChannel, 0); + vector> line1(src.rows, pixel); + vector>> weight(src.cols, + line1); // global weights + vector>> imageResult( + src.cols, line1); // global normalized image + + // do algorithm + cv::Mat subwindow, subwindow1; + for (int posX = 0; posX < src.cols - subwindowX; posX++) + { + for (int posY = 0; posY < src.rows - subwindowY; posY++) + { + cv::Rect roi = + cv::Rect(posX, posY, subwindowX, subwindowY); + cv::Mat subwindow1 = src(roi); + cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), + 0.3, 0.3); + + // compute arithmetic mean of subwindow + cv::Scalar ArithmeticMean = cv::mean(subwindow); + + // compute pixelwise distance + vector> pixelwiseDist; + + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + vector line; + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) + { + cv::Vec3b intensity = + subwindow.at(subPosY, + subPosX); + double distance = + ((double)intensity.val[0] - + ArithmeticMean[0]) * + ((double)intensity.val[0] - + ArithmeticMean[0]) + + ((double)intensity.val[1] - + ArithmeticMean[1]) * + ((double)intensity.val[1] - + ArithmeticMean[1]) + + ((double)intensity.val[2] - + ArithmeticMean[2]) * + ((double)intensity.val[2] - + ArithmeticMean[2]); + distance = sqrt(distance); + + line.push_back(distance); + }; + + pixelwiseDist.push_back(line); + }; + + // compute mean pixelwise distance + double meanPixelwiseDist = 0; + + for (int i = 0; i < (int)pixelwiseDist.size(); i++) + for (int j = 0; + j < (int)pixelwiseDist[i].size(); j++) + meanPixelwiseDist += + pixelwiseDist[i][j]; + + meanPixelwiseDist /= ((int)pixelwiseDist.size() * + (int)pixelwiseDist[0].size()); + + // detect edge + for (int subPosX = 0; subPosX < subwindow.cols; + subPosX++) + { + for (int subPosY = 0; subPosY < subwindow.rows; + subPosY++) + { + if ((meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] <= + threshold) || + (meanPixelwiseDist <= threshold && + pixelwiseDist[subPosX][subPosY] > + threshold)) + { + // global Position + int globalPosX = posX + subPosX; + int globalPosY = posY + subPosY; + + // compute global weight + cv::Vec3b intensity = + subwindow.at( + subPosY, subPosX); + weight[globalPosX][globalPosY] + [0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + weight[globalPosX][globalPosY] + [2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]); + + // compute final image + imageResult[globalPosX] + [globalPosY][0] += + intensity.val[0] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[0]; + imageResult[globalPosX] + [globalPosY][1] += + intensity.val[1] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[1]; + imageResult[globalPosX] + [globalPosY][2] += + intensity.val[2] * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + (threshold - + pixelwiseDist[subPosX] + [subPosY]) * + ArithmeticMean[2]; + }; + }; + }; + }; + }; + + // compute final image + for (int globalPosX = 0; globalPosX < (int)imageResult.size(); + globalPosX++) + { + for (int globalPosY = 0; + globalPosY < (int)imageResult[globalPosX].size(); + globalPosY++) + { + // cout << "globalPosX: " << globalPosX << "/" + // << dst.cols << "," << imageResult.size () << + // "\tglobalPosY: " << globalPosY << "/" << + // dst.rows << "," <(globalPosY, globalPosX); + imageResult[globalPosX][globalPosY][0] += + (double)intensity.val[0]; + imageResult[globalPosX][globalPosY][1] += + (double)intensity.val[1]; + imageResult[globalPosX][globalPosY][2] += + (double)intensity.val[2]; + + // normalize using weight + imageResult[globalPosX][globalPosY][0] /= + (weight[globalPosX][globalPosY][0] + 1); + imageResult[globalPosX][globalPosY][1] /= + (weight[globalPosX][globalPosY][1] + 1); + imageResult[globalPosX][globalPosY][2] /= + (weight[globalPosX][globalPosY][2] + 1); + + // copy to output image frame + dst.at(globalPosY, globalPosX)[0] = + (uchar)imageResult[globalPosX][globalPosY][0]; + dst.at(globalPosY, globalPosX)[1] = + (uchar)imageResult[globalPosX][globalPosY][1]; + dst.at(globalPosY, globalPosX)[2] = + (uchar)imageResult[globalPosX][globalPosY][2]; + }; + }; } } // namespace ximgproc } // namespace cv From 7e7d1087e369ba02167f50f33e7cf1d965776a21 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 10:44:19 +0200 Subject: [PATCH 22/26] Changed path testdata/perf/320x260.png to perf/320x260.png --- modules/ximgproc/perf/perf_edgepreserving_filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp index f4f44bd15fa..2744a5764a3 100644 --- a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp +++ b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp @@ -25,7 +25,7 @@ PERF_TEST_P(EdgepreservingFilterTest, perf, double threshold = get<1>(params); /* 4. Allocate and initialize arguments for tested function */ - std::string filename = getDataPath("testdata/perf/320x260.png"); + std::string filename = getDataPath("perf/320x260.png"); Mat src = imread(filename, 1); Mat dst(src.size(), src.type()); From acb5b27fa90146a604ffe7fa275b00922700264d Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 11:03:56 +0200 Subject: [PATCH 23/26] Fixed warning declaration of 'subwindow1' hides previous local declaration --- modules/ximgproc/src/edgepreserving_filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 9822529bec4..22660b53d4f 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -50,7 +50,7 @@ void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, { cv::Rect roi = cv::Rect(posX, posY, subwindowX, subwindowY); - cv::Mat subwindow1 = src(roi); + subwindow1 = src(roi); cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), 0.3, 0.3); From c7e4c3aa0e69b92d5ea9560b16f499fdb2247490 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 11:20:49 +0200 Subject: [PATCH 24/26] Fixed warning 'const' qualifier on reference type 'cv::InputArray' (aka 'const cv::_InputArray &') has no effect --- .../ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp | 2 +- modules/ximgproc/src/edgepreserving_filter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp index 62bccbc7438..420ee304fd9 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp @@ -24,7 +24,7 @@ namespace cv { namespace ximgproc { * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3. * @param threshold Threshold, which distinguishes between noise, outliers, and data. */ - CV_EXPORTS_W void edgepreservingFilter( const InputArray src, OutputArray dst, int d, double threshold ); + CV_EXPORTS_W void edgepreservingFilter( InputArray src, OutputArray dst, int d, double threshold ); }} // namespace diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index 22660b53d4f..d865e27cc0b 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -13,7 +13,7 @@ namespace ximgproc { using namespace std; -void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, +void edgepreservingFilter(InputArray _src, OutputArray _dst, int d, double threshold) { CV_Assert(_src.type() == CV_8UC3); From fee65734c6ec7e677e596492ea877466dac9e3a7 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Wed, 1 Aug 2018 12:26:43 +0200 Subject: [PATCH 25/26] Accuracy test added/ --- .../test/test_edgepreserving_filter.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 modules/ximgproc/test/test_edgepreserving_filter.cpp diff --git a/modules/ximgproc/test/test_edgepreserving_filter.cpp b/modules/ximgproc/test/test_edgepreserving_filter.cpp new file mode 100644 index 00000000000..95c88b61d0f --- /dev/null +++ b/modules/ximgproc/test/test_edgepreserving_filter.cpp @@ -0,0 +1,35 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +// +// Created by Simon Reich +// +#include "test_precomp.hpp" + +namespace opencv_test { namespace { + +TEST(ximgproc_EdgepreservingFilter, regression) +{ + // Load original image + std::string filename = string(cvtest::TS::ptr()->get_data_path()) + "perf/320x260.png"; + cv::Mat src, dst, noise, original = imread(filename, 1); + + ASSERT_FALSE(original.empty()) << "Could not load input image " << filename; + ASSERT_EQ(3, original.channels()) << "Load color input image " << filename; + + // add noise + noise = Mat(original.size(), original.type()); + cv::randn(noise, 0, 5); + src = original + noise; + + // Filter + int kernel = 9; + double threshold = 20; + ximgproc::edgepreservingFilter(src, dst, kernel, threshold); + + double psnr = cvtest::PSNR(original, dst); + //printf("psnr=%.2f\n", psnr); + ASSERT_LT(psnr, 25.0); +} + +}} // namespace From 5795c0a0a6a1fd45325e552278f4065cfc431f24 Mon Sep 17 00:00:00 2001 From: Simon Reich Date: Thu, 2 Aug 2018 08:19:50 +0200 Subject: [PATCH 26/26] Renamed void edgepreservingFilter to void edgePreservingFilter --- .../ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp | 2 +- modules/ximgproc/perf/perf_edgepreserving_filter.cpp | 2 +- modules/ximgproc/samples/edgepreserving_filter_demo.cpp | 2 +- modules/ximgproc/src/edgepreserving_filter.cpp | 2 +- modules/ximgproc/test/test_edgepreserving_filter.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp index 420ee304fd9..f5685ce39bb 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/edgepreserving_filter.hpp @@ -24,7 +24,7 @@ namespace cv { namespace ximgproc { * @param d Diameter of each pixel neighborhood that is used during filtering. Must be greater or equal 3. * @param threshold Threshold, which distinguishes between noise, outliers, and data. */ - CV_EXPORTS_W void edgepreservingFilter( InputArray src, OutputArray dst, int d, double threshold ); + CV_EXPORTS_W void edgePreservingFilter( InputArray src, OutputArray dst, int d, double threshold ); }} // namespace diff --git a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp index 2744a5764a3..7d86d165f25 100644 --- a/modules/ximgproc/perf/perf_edgepreserving_filter.cpp +++ b/modules/ximgproc/perf/perf_edgepreserving_filter.cpp @@ -34,7 +34,7 @@ PERF_TEST_P(EdgepreservingFilterTest, perf, /* 6. Collect the samples! */ PERF_SAMPLE_BEGIN(); - ximgproc::edgepreservingFilter(src, dst, kernelSize, threshold); + ximgproc::edgePreservingFilter(src, dst, kernelSize, threshold); PERF_SAMPLE_END(); /* 7. Do not check anything */ diff --git a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp index e7513214b12..faa89b43d8d 100644 --- a/modules/ximgproc/samples/edgepreserving_filter_demo.cpp +++ b/modules/ximgproc/samples/edgepreserving_filter_demo.cpp @@ -32,7 +32,7 @@ int main(int argc, char **argv) waitKey(0); // Initialize filter. Kernel size 5x5, threshold 20 - ximgproc::edgepreservingFilter(image, res, 9, 20); + ximgproc::edgePreservingFilter(image, res, 9, 20); // After filtering imshow("Filtered image", res); diff --git a/modules/ximgproc/src/edgepreserving_filter.cpp b/modules/ximgproc/src/edgepreserving_filter.cpp index d865e27cc0b..ea9dfb65e70 100644 --- a/modules/ximgproc/src/edgepreserving_filter.cpp +++ b/modules/ximgproc/src/edgepreserving_filter.cpp @@ -13,7 +13,7 @@ namespace ximgproc { using namespace std; -void edgepreservingFilter(InputArray _src, OutputArray _dst, int d, +void edgePreservingFilter(InputArray _src, OutputArray _dst, int d, double threshold) { CV_Assert(_src.type() == CV_8UC3); diff --git a/modules/ximgproc/test/test_edgepreserving_filter.cpp b/modules/ximgproc/test/test_edgepreserving_filter.cpp index 95c88b61d0f..8f6059b7d07 100644 --- a/modules/ximgproc/test/test_edgepreserving_filter.cpp +++ b/modules/ximgproc/test/test_edgepreserving_filter.cpp @@ -25,7 +25,7 @@ TEST(ximgproc_EdgepreservingFilter, regression) // Filter int kernel = 9; double threshold = 20; - ximgproc::edgepreservingFilter(src, dst, kernel, threshold); + ximgproc::edgePreservingFilter(src, dst, kernel, threshold); double psnr = cvtest::PSNR(original, dst); //printf("psnr=%.2f\n", psnr);