-
Notifications
You must be signed in to change notification settings - Fork 5.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds Edge-Preserving Filter #1690
Conversation
Please advise on further steps. Thank you! |
Thank you for contribution!
|
modules/epf/samples/epf_demo.cpp
Outdated
|
||
#include <iostream> | ||
#include <string> | ||
#include <opencv2/opencv.hpp> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opencv2/imgcodecs.hpp
opencv2/highgui.hpp
opencv2/ximgproc.hpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opencv2/imgcodecs.hpp
opencv2/opencv.hpp
'''
do not seem to be necessary and are not included any more.
modules/epf/samples/epf_demo.cpp
Outdated
|
||
int showWindow(cv::Mat image, std::string title); | ||
|
||
int showWindow(cv::Mat image, std::string title) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use "static" to eliminate forward declaration:
static int showWindow(...) { }
Use const reference for input parameters:
const Mat&
const std::string&
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
showWindow function removed.
modules/epf/samples/epf_demo.cpp
Outdated
int main(int argc, char **argv) | ||
{ | ||
// Help text | ||
if (argc != 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better to use OpenCV's CommandLineParser
: similar example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
modules/epf/samples/epf_demo.cpp
Outdated
|
||
// Initialize filter. Kernel size 5x5, threshold 20 | ||
Ptr<epf::edgepreservingFilter> filter = | ||
epf::edgepreservingFilter::create(&image, &res, 5, 20); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like using "filter" object is over-complicated for filtering case. Ptr
is not necessary.
It is better to use just a function, like OpenCV's cv::blur
.
Please use OpenCV's InputArray / OutputArray types for parameters (they are used for Python/Java bindings generation at least)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not know how to implement this properly. It is now a part of ximgproc.
InputArray is used.
No pointers are used.
modules/epf/samples/epf_demo.cpp
Outdated
|
||
int showWindow(cv::Mat image, std::string title) | ||
{ | ||
namedWindow(title); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namedWindow()
is not necessary here.
imshow()
implies namedWindow()
call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
showWindow function removed.
Thanks for the quick reply. I will close this request and resubmit after I added the above changes. |
No need to open a new pull request. Just push changes / new commits into your branch "epf" (probably with "--force" option to override patch). Lets keep discussion in a single place. |
modules/epf/include/opencv2/epf.hpp
Outdated
* @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<edgepreservingFilter> create(const cv::Mat *src, cv::Mat *dst, int d, int threshold); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if i may ask: why is this a class ? (maybe having a simple function, at least in the public interface might be better)
it's not doing anything outside of the constructor, and we'd need to create a new object for different images here, right ?
also, please rather use InputArray and OutputArray instead of raw Mat *
(which cannot be properly wrapped into python / java)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not know how to implement this properly. It is now a part of ximgproc.
InputArray is used.
No pointers are used.
* @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 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you try without the pointers ?
CV_EXPORTS_W void edgepreservingFilter( const InputArray src, OutputArray dst, int d, int threshold );
should be enough. (passing cv::Mat by address is usually a bad idea, since it defeats the internal refcounting)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
#include <opencv2/highgui.hpp> | ||
#include <opencv2/ximgproc.hpp> | ||
#include <opencv2/opencv.hpp> | ||
#include <opencv2/epf.hpp> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this does not exist, right ? ( #include <opencv2/ximgproc.hpp>
should be enough, here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
subPosY < subwindow.rows; | ||
subPosY++) | ||
{ | ||
if (meanPixelwiseDist <= |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i can't see any difference between the if and the else block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Historic reasons of this implementation. Is removed in latest commit.
{ | ||
using namespace std; | ||
|
||
edgepreservingFilter(const InputArray *src, OutputArray *dst, int d, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void edgepreservingFilter(...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cv::GaussianBlur(subwindow1, subwindow, | ||
cv::Size(5, 5), 0.3, 0.3); | ||
|
||
// compute arithmetic mean of subwindow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cv::mean ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented cv::mean instead of manual computation.
Thanks for all the helpful comments and tips! I think I included all of them in the last commits. I am waiting for the build bot to finish and will check for further issues. Please let me know what I should be doing next. |
PERF_TEST_P(EdgepreservingFilterTest, perf, | ||
Combine(Values(-20, 0, 10), Values(-100, 0, 20))) | ||
{ | ||
/* 3. Get actual test parameters */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use 4 spaces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used https://raw.githubusercontent.com/opencv/opencv_contrib/master/modules/cvv/.clang-format for beautification.
Is there a working .clang-format file (or any other code beautifier)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above code should read
PERF_TEST_P(EdgepreservingFilterTest, perf,
Combine(Values(-20, 0, 10), Values(-100, 0, 20)))
{
/* 3. Get actual test parameters */
Instead of
PERF_TEST_P(EdgepreservingFilterTest, perf,
Combine(Values(-20, 0, 10), Values(-100, 0, 20)))
{
/* 3. Get actual test parameters */
Is this correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I did not notice that the above .clang-format file uses tabs instead of 4 spaces.
Please ignore my last comment.
double threshold = get<1>(params); | ||
|
||
/* 4. Allocate and initialize arguments for tested function */ | ||
std::string filename = getDataPath("samples/data/corridor.jpg"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently test framework doesn't search test images in samples/data directory.
Tests using testdata from opencv_extra repository:
https://github.com/opencv/opencv_extra/tree/master/testdata
Please create patch with image here too (the the same name of branch: "epf")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it considered good practice to use https://github.com/opencv/opencv_extra/blob/master/testdata/perf/320x260.png instead of creating my own image?
Thus, no patch would be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reusing existed test images is a good practice.
|
||
/* 2. Declare the testsuite */ | ||
PERF_TEST_P(EdgepreservingFilterTest, perf, | ||
Combine(Values(-20, 0, 10), Values(-100, 0, 20))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be we should start from accuracy test and do some checks?
Performance tests have not any checks usually, they just measure performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any resources on OpenCV on how to write an accuracy test available? I just found lengthy example code at https://github.com/opencv/opencv/wiki/QA_in_OpenCV.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added an accuracy test.
However, some more resources would be helpful.
Mat dst(src.size(), src.type()); | ||
|
||
/* 5. Manifest your expectations about this test */ | ||
declare.in(src, WARMUP_RNG).out(dst); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in(src, WARMUP_RNG)
This code overrides your input image. Do not do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed , WARMUP_RNG
.
/* 6. Collect the samples! */ | ||
TEST_CYCLE_N(1) | ||
{ | ||
ximgproc::edgepreservingFilter(src, dst, kernelSize, threshold); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use this pattern:
PERF_SAMPLE_BEGIN();
Canny(img, edges, thresh_low, thresh_high, aperture, useL2);
PERF_SAMPLE_END();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
int main(int argc, char **argv) | ||
{ | ||
cv::CommandLineParser parser( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 spaces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed '\t ' to " ".
void edgepreservingFilter(const InputArray _src, OutputArray _dst, int d, | ||
double threshold) | ||
{ | ||
Mat src = _src.getMat(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 spaces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed '\t ' to " ".
cv::Rect(posX, posY, subwindowX, subwindowY); | ||
subwindow = src(roi); | ||
cv::Mat subwindow1 = src(roi); | ||
cv::GaussianBlur(subwindow1, subwindow, cv::Size(5, 5), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
subwindow = src(roi);
This line seems useless. Due cv::GaussianBlur()
call behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed subwindow = src(roi);
.
Mat dst = _dst.getMat(); | ||
src.copyTo(dst); | ||
|
||
CV_Assert(src.type() == CV_8UC3); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this check in the beginning of function. Perhaps via _src.type()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
namespace cv { namespace ximgproc { | ||
|
||
//! @addtogroup ximgproc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No indentation in namespaces please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
…ka 'const cv::_InputArray &') has no effect
I worked on all of the above issues. One question remains: Currently, there is one performance test and one accuracy test. Which one should be deleted? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which one should be deleted?
No one. It is OK now.
Accuracy and performance tests have different purposes.
Patch looks good to me. Please check the last one comment below.
* @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 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
edgepreservingFilter
Rename to "edgePreservingFilter". See naming guide for details.
BTW, OpenCV already has some edgePreservingFilter()
function (from photo module). But there is no huge problem due different namespaces.
Thanks for all the help! If I can be of further assistance, please do not hesitate to contact me. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done! Looks good to me 👍
This pullrequest changes
This request adds the Edge-Preserving Filter to the OpenCV libreary as described in
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.
http://fortknox.physik3.gwdg.de/cns/modules/BibtexModule/uploads/PDF/reichwoergoetterdellen2018.pdf