ximpgroc module added (structured forests for fast edge detection by Piotr Dollar)

pull/25/head
Bellaktris 11 years ago
parent f6a80b191a
commit 974b71fffa
  1. 3
      modules/ximpgroc/CMakeLists.txt
  2. 70
      modules/ximpgroc/doc/structured_edge_detection/index.rst
  3. 8
      modules/ximpgroc/doc/ximpgroc.rst
  4. 48
      modules/ximpgroc/include/opencv2/ximpgroc.hpp
  5. 127
      modules/ximpgroc/include/opencv2/ximpgroc/structured_edge_detection.hpp
  6. 70
      modules/ximpgroc/samples/structured_edge_detection.cpp
  7. 87
      modules/ximpgroc/src/advanced_types.hpp
  8. 694
      modules/ximpgroc/src/structured_edge_detection.cpp
  9. 39
      modules/ximpgroc/test/structured_edge_detection.cpp
  10. 3
      modules/ximpgroc/test/test_main.cpp
  11. 20
      modules/ximpgroc/test/test_precomp.hpp
  12. BIN
      modules/ximpgroc/testdata/model.yml.gz
  13. BIN
      modules/ximpgroc/testdata/results/01.png
  14. BIN
      modules/ximpgroc/testdata/results/02.png
  15. BIN
      modules/ximpgroc/testdata/results/03.png
  16. BIN
      modules/ximpgroc/testdata/results/04.png
  17. BIN
      modules/ximpgroc/testdata/results/05.png
  18. BIN
      modules/ximpgroc/testdata/results/06.png
  19. BIN
      modules/ximpgroc/testdata/results/07.png
  20. BIN
      modules/ximpgroc/testdata/results/08.png
  21. BIN
      modules/ximpgroc/testdata/results/09.png
  22. BIN
      modules/ximpgroc/testdata/results/10.png
  23. BIN
      modules/ximpgroc/testdata/results/11.png
  24. BIN
      modules/ximpgroc/testdata/results/12.png
  25. BIN
      modules/ximpgroc/testdata/sources/01.png
  26. BIN
      modules/ximpgroc/testdata/sources/02.png
  27. BIN
      modules/ximpgroc/testdata/sources/03.png
  28. BIN
      modules/ximpgroc/testdata/sources/04.png
  29. BIN
      modules/ximpgroc/testdata/sources/05.png
  30. BIN
      modules/ximpgroc/testdata/sources/06.png
  31. BIN
      modules/ximpgroc/testdata/sources/07.png
  32. BIN
      modules/ximpgroc/testdata/sources/08.png
  33. BIN
      modules/ximpgroc/testdata/sources/09.png
  34. BIN
      modules/ximpgroc/testdata/sources/10.png
  35. BIN
      modules/ximpgroc/testdata/sources/11.png
  36. BIN
      modules/ximpgroc/testdata/sources/12.png

@ -0,0 +1,3 @@
set(the_description "Advanced edge-detection algorithms")
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef)
ocv_define_module(ximpgroc opencv_core opencv_imgproc OPTIONAL opencv_highgui)

@ -0,0 +1,70 @@
Structured forests for fast edge detection
******************************************
.. highlight:: cpp
...
StructuredEdgeDetection
-----------------------
.. ocv:class:: StructuredEdgeDetection : public Algorithm
Class implementing edge detection algorithm from [Dollar2013]_ ::
/*! \class StructuredEdgeDetection
Prediction part of [P. Dollar and C. L. Zitnick. Structured Forests for Fast Edge Detection, 2013].
*/
class CV_EXPORTS_W StructuredEdgeDetection : public Algorithm
{
public:
/*!
* The function detects edges in src and draw them to dst
*
* \param src : source image (RGB, float, in [0;1]) to detect edges
* \param dst : destination image (grayscale, float, in [0;1])
* where edges are drawn
*/
CV_WRAP virtual void detectEdges(const Mat src, Mat dst) = 0;
};
/*!
* The only available constructor loading data from model file
*
* \param model : name of the file where the model is stored
*/
CV_EXPORTS_W Ptr<StructuredEdgeDetection> createStructuredEdgeDetection(const String &model);
StructuredEdgeDetection::detectEdges
++++++++++++++++++++++++++++++++++++
.. ocv:function:: void detectEdges(const Mat src, Mat dst)
The function detects edges in src and draw them to dst. The algorithm underlies this function
is much more robust to texture presence, than common approaches, e.g. Sobel
:param src : source image (RGB, float, in [0;1]) to detect edges
:param dst : destination image (grayscale, float, in [0;1])
where edges are drawn
.. seealso::
:ocv:class:`Sobel`,
:ocv:class:`Canny`
createStructuredEdgeDetection
+++++++++++++++++++++++++++++
.. ocv:function:: Ptr<cv::StructuredEdgeDetection> createStructuredEdgeDetection(String model)
The only available constructor
:param model: model file name
Literature
----------
.. [Dollar2013] Dollár P., Zitnick C. L., "Structured forests for fast edge detection",
IEEE International Conference on Computer Vision (ICCV), 2013,
pp. 1841-1848. `DOI <http://dx.doi.org/10.1109/ICCV.2013.231>`_

@ -0,0 +1,8 @@
********************************************
ximpgroc. Advanced edge-detection algorithms
********************************************
.. toctree::
:maxdepth: 2
Structured forests for fast edge detection <structured_edge_detection/index>

@ -0,0 +1,48 @@
/*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*/
#ifndef __OPENCV_EDGEDETECTION_HPP__
#define __OPENCV_EDGEDETECTION_HPP__
#include "opencv2/core.hpp"
#include "opencv2/ximpgroc/structured_edge_detection.hpp"
#endif

@ -0,0 +1,127 @@
/*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-2011, 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*/
#ifndef __OPENCV_STRUCTURED_EDGE_DETECTION_HPP__
#define __OPENCV_STRUCTURED_EDGE_DETECTION_HPP__
/*
* structured_edge_detection.hpp
*
* Created on: Jun 17, 2014
* Author: Yury Gitman
*/
#include <opencv2/core.hpp>
/*! \namespace cv
Namespace where all the C++ OpenCV functionality resides
*/
namespace cv
{
/*! \class RFFeatureGetter
Helper class for training part of [P. Dollar and C. L. Zitnick. Structured Forests for Fast Edge Detection, 2013].
*/
class CV_EXPORTS_W RFFeatureGetter : public Algorithm
{
public:
/*!
* This functions extracts feature channels from src.
* Than StructureEdgeDetection uses this feature space
* to detect edges.
*
* \param src : source image to extract features
* \param features : output n-channel floating point feature matrix.
*
* \param gnrmRad : __rf.options.gradientNormalizationRadius
* \param gsmthRad : __rf.options.gradientSmoothingRadius
* \param shrink : __rf.options.shrinkNumber
* \param outNum : __rf.options.numberOfOutputChannels
* \param gradNum : __rf.options.numberOfGradientOrientations
*/
CV_WRAP virtual void getFeatures(const Mat &src, Mat &features,
const int gnrmRad,
const int gsmthRad,
const int shrink,
const int outNum,
const int gradNum) const = 0;
};
/*!
* ...
*/
CV_EXPORTS_W Ptr<RFFeatureGetter> createRFFeatureGetter(void);
/*! \class StructuredEdgeDetection
Prediction part of [P. Dollar and C. L. Zitnick. Structured Forests for Fast Edge Detection, 2013].
*/
class CV_EXPORTS_W StructuredEdgeDetection : public Algorithm
{
public:
/*!
* The function detects edges in src and draw them to dst
*
* \param src : source image (RGB, float, in [0;1]) to detect edges
* \param dst : destination image (grayscale, float, in [0;1])
* where edges are drawn
*/
CV_WRAP virtual void detectEdges(const Mat &src, Mat &dst) const = 0;
};
/*!
* The only constructor
*
* \param model : name of the file where the model is stored
* \param howToGetFeatures : optional object inheriting from RFFeatureGetter.
* You need it only if you would like to train your
* own forest, pass NULL otherwise
*/
CV_EXPORTS_W Ptr<StructuredEdgeDetection> createStructuredEdgeDetection(const String &model,
const RFFeatureGetter *howToGetFeatures = NULL);
}
#endif /* __OPENCV_STRUCTURED_EDGE_DETECTION_HPP__ */

@ -0,0 +1,70 @@
#include "opencv2/ximpgroc/structured_edge_detection.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc/types_c.h"
#include <iostream>
const char* keys =
{
"{i || input image name}"
"{m || model name}"
"{o || output image name}"
};
int main( int argc, const char** argv )
{
bool printHelp = ( argc == 1 );
printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "--help" );
printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "-h" );
if ( printHelp )
{
printf("\nThis sample demonstrates structured forests for fast edge detection\n"
"Call:\n"
" structured_edge_detection -i=in_image_name -m=model_name [-o=out_image_name]\n\n");
return 0;
}
cv::CommandLineParser parser(argc, argv, keys);
if ( !parser.check() )
{
parser.printErrors();
return -1;
}
std::string modelFilename = parser.get<std::string>("m");
std::string inFilename = parser.get<std::string>("i");
std::string outFilename = parser.get<std::string>("o");
cv::Mat image = cv::imread(inFilename, 1);
if ( image.empty() )
{
printf("Cannot read image file: %s\n", inFilename.c_str());
return -1;
}
cv::cvtColor(image, image, CV_BGR2RGB);
image.convertTo(image, cv::DataType<float>::type, 1/255.0);
cv::Mat edges(image.size(), image.type());
cv::Ptr<cv::StructuredEdgeDetection> pDollar =
cv::createStructuredEdgeDetection(modelFilename);
pDollar->detectEdges(image, edges);
if ( outFilename == "" )
{
cv::namedWindow("edges", 1);
cv::imshow("edges", edges);
cv::waitKey(0);
}
else
cv::imwrite(outFilename, 255*edges);
return 0;
}

@ -0,0 +1,87 @@
/*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-2011, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// * 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 Intel Corporation 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*/
#ifndef __ADVANCED_TYPES_HPP__
#define __ADVANCED_TYPES_HPP__
#include <opencv2/core.hpp>
/********************* Defines *********************/
#ifndef CV_SQR
# define CV_SQR(x) ((x)*(x))
#endif
#ifndef CV_CUBE
# define CV_CUBE(x) ((x)*(x)*(x))
#endif
#ifndef CV_INIT_VECTOR
# define CV_INIT_VECTOR(vname, type, ...) \
static const type vname##_a[] = __VA_ARGS__; \
std::vector <type> vname(vname##_a, \
vname##_a + sizeof(vname##_a) / sizeof(*vname##_a))
#endif
/********************* Types *********************/
/*! fictitious type to highlight that function
* can process n-channels arguments */
typedef cv::Mat NChannelsMat;
/********************* Functions *********************/
namespace cv
{
template <typename _Tp, typename _Tp2> inline
cv::Size_<_Tp> operator * (const _Tp2 &x, const cv::Size_<_Tp> &sz)
{
return cv::Size_<_Tp>(cv::saturate_cast<_Tp>(x*sz.width), cv::saturate_cast<_Tp>(x*sz.height));
}
template <typename _Tp, typename _Tp2> inline
cv::Size_<_Tp> operator / (const cv::Size_<_Tp> &sz, const _Tp2 &x)
{
return cv::Size_<_Tp>(cv::saturate_cast<_Tp>(sz.width/x), cv::saturate_cast<_Tp>(sz.height/x));
}
} // cv
#endif /* __ADVANCED_TYPES_HPP__ */

@ -0,0 +1,694 @@
/*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-2011, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// * 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 Intel Corporation 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*/
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include "opencv2/ximpgroc/structured_edge_detection.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/core.hpp"
#include "opencv2/core/core_c.h"
#include "advanced_types.hpp"
#include "opencv2/core/types.hpp"
#include "opencv2/core/types_c.h"
/********************* Helper functions *********************/
/*!
* Lightweight wrapper over cv::resize
*
* \param src : source image to resize
* \param dst : destination image size
* \return resized image
*/
static cv::Mat imresize(const cv::Mat &src, const cv::Size &nSize)
{
cv::Mat dst;
if (nSize.width < src.size().width
&& nSize.height < src.size().height)
cv::resize(src, dst, nSize, 0.0, 0.0, cv::INTER_AREA);
else
cv::resize(src, dst, nSize, 0.0, 0.0, cv::INTER_LINEAR);
return dst;
}
/*!
* The function filters src with triangle filter with radius equal rad
*
* \param src : source image to filter
* \param rad : radius of filtering kernel
* \return filtering result
*/
static cv::Mat imsmooth(const cv::Mat &src, const int rad)
{
if (rad == 0)
return src;
else
{
const float p = 12/rad/(rad + 2) - 2;
cv::Mat dst;
if (rad <= 1)
{
CV_INIT_VECTOR(kernelXY, float, {1/(p + 2), p/(p + 2), 1/(p + 2)});
cv::sepFilter2D(src, dst, -1, kernelXY, kernelXY);
}
else
{
float nrml = CV_SQR(rad + 1);
std::vector <float> kernelXY(2*rad + 1);
for (int i = 0; i <= rad; ++i)
{
kernelXY[2*rad - i] = (i + 1) / nrml;
kernelXY[i] = (i + 1) / nrml;
}
sepFilter2D(src, dst, -1, kernelXY, kernelXY);
}
return dst;
}
}
/*!
* The function implements rgb to luv conversion in a way similar
* to UCSD computer vision toolbox
*
* \param src : source image (RGB, float, in [0;1]) to convert
* \return converted image in luv colorspace
*/
static cv::Mat rgb2luv(const cv::Mat &src)
{
cv::Mat dst(src.size(), src.type());
const float a = CV_CUBE(29.0f)/27;
const float y0 = 8.0f/a;
const float mX[] = {0.430574f, 0.341550f, 0.178325f};
const float mY[] = {0.222015f, 0.706655f, 0.071330f};
const float mZ[] = {0.020183f, 0.129553f, 0.939180f};
const float maxi= 1.0f/270;
const float minu= -88*maxi;
const float minv= -134*maxi;
const float un = 0.197833f;
const float vn = 0.468331f;
// build (padded) lookup table for y->l conversion assuming y in [0,1]
std::vector <float> lTable(1024);
for (int i = 0; i < 1024; ++i)
{
float y = i/1024.0f;
float l = y > y0 ? 116*powf(y, 1.0f/3.0f) - 16 : y*a;
lTable[i] = l*maxi;
}
for (int i = 0; i < 40; ++i)
lTable.push_back(*--lTable.end());
const int nchannels = 3;
for (int i = 0; i < src.rows; ++i)
{
const float *pSrc = src.ptr<float>(i);
float *pDst = dst.ptr<float>(i);
for (int j = 0; j < src.cols*nchannels; j += nchannels)
{
const float rgb[] = {pSrc[j + 0], pSrc[j + 1], pSrc[j + 2]};
const float xyz[] = {mX[0]*rgb[0] + mX[1]*rgb[1] + mX[2]*rgb[2],
mY[0]*rgb[0] + mY[1]*rgb[1] + mY[2]*rgb[2],
mZ[0]*rgb[0] + mZ[1]*rgb[1] + mZ[2]*rgb[2]};
const float nz = 1.0f/(xyz[0] + 15*xyz[1] + 3*xyz[2] + 1e-35);
const float l = pDst[j] = lTable[cvFloor(1024*xyz[1])];
pDst[j + 1] = l * (13*4*xyz[0]*nz - 13*un) - minu;;
pDst[j + 2] = l * (13*9*xyz[1]*nz - 13*vn) - minv;
}
}
return dst;
}
/*!
* The function computes gradient magnitude and weighted (with magnitude)
* orientation histogram. Magnitude is additionally normalized
* by dividing on imsmooth(M, gnrmRad) + 0.01;
*
* \param src : source image
* \param magnitude : gradient magnitude
* \param histogram : gradient orientation nBins-channels histogram
* \param nBins : number of gradient orientations
* \param pSize : factor to downscale histogram
* \param gnrmRad : radius for magnitude normalization
*/
static void gradientHist(const cv::Mat &src, cv::Mat &magnitude, cv::Mat &histogram,
const int nBins, const int pSize, const int gnrmRad)
{
cv::Mat phase, Dx, Dy;
magnitude.create( src.size(), cv::DataType<float>::type );
phase.create( src.size(), cv::DataType<float>::type );
histogram.create( src.size()/float(pSize),
CV_MAKETYPE(cv::DataType<float>::type, nBins) );
histogram.setTo(0);
cv::Sobel( src, Dx, cv::DataType<float>::type,
1, 0, 1, 1.0, 0.0, cv::BORDER_REFLECT );
cv::Sobel( src, Dy, cv::DataType<float>::type,
0, 1, 1, 1.0, 0.0, cv::BORDER_REFLECT );
int nchannels = src.channels();
for (int i = 0; i < src.rows; ++i)
{
const float *pDx = Dx.ptr<float>(i);
const float *pDy = Dy.ptr<float>(i);
float *pMagnitude = magnitude.ptr<float>(i);
float *pPhase = phase.ptr<float>(i);
for (int j = 0; j < src.cols*nchannels; j += nchannels)
{
float fMagn = -1e-5, fdx, fdy;
for (int k = 0; k < nchannels; ++k)
{
float cMagn = CV_SQR( pDx[j + k] ) + CV_SQR( pDy[j + k] );
if (cMagn > fMagn)
{
fMagn = cMagn;
fdx = pDx[j + k];
fdy = pDy[j + k];
}
}
pMagnitude[j/nchannels] = std::sqrtf(fMagn);
float angle = cv::fastAtan2(fdy, fdx) / 180.0f - 1.0f * (fdy < 0);
if (std::fabs(fdx) + std::fabs(fdy) < 1e-5)
angle = 0.5f;
pPhase[j/nchannels] = angle;
}
}
magnitude /= imsmooth( magnitude, gnrmRad )
+ 0.01*cv::Mat::ones( magnitude.size(), magnitude.type() );
for (int i = 0; i < phase.rows; ++i)
{
const float *pPhase = phase.ptr<float>(i);
const float *pMagn = magnitude.ptr<float>(i);
float *pHist = histogram.ptr<float>(i/pSize);
for (int j = 0; j < phase.cols; ++j)
pHist[cvRound((j/pSize + pPhase[j])*nBins)] += pMagn[j] / CV_SQR(pSize);
}
}
/********************* RFFeatureGetter class *********************/
namespace cv
{
class RFFeatureGetterImpl : public RFFeatureGetter
{
public:
/*!
* Default constructor
*/
RFFeatureGetterImpl() : name("RFFeatureGetter"){}
/*!
* The method extracts features from img and store them to features.
* Extracted features are appropriate for StructuredEdgeDetection::predictEdges.
*
* \param src : source image (RGB, float, in [0;1]) to extract features
* \param features : destination feature image
*
* \param gnrmRad : __rf.options.gradientNormalizationRadius
* \param gsmthRad : __rf.options.gradientSmoothingRadius
* \param shrink : __rf.options.shrinkNumber
* \param outNum : __rf.options.numberOfOutputChannels
* \param gradNum : __rf.options.numberOfGradientOrientations
*/
virtual void getFeatures(const cv::Mat &src, NChannelsMat &features,
const int gnrmRad, const int gsmthRad,
const int shrink, const int outNum, const int gradNum) const
{
cv::Mat luvImg = rgb2luv(src);
std::vector <cv::Mat> featureArray;
cv::Size nSize = src.size() / float(shrink);
split( imresize(luvImg, nSize), featureArray );
CV_INIT_VECTOR(scales, float, {1.0f, 0.5f});
for (size_t i = 0; i < scales.size(); ++i)
{
int pSize = std::max( 1, int(shrink*scales[i]) );
cv::Mat magnitude, histogram;
gradientHist(/**/ imsmooth(imresize(luvImg, scales[i]*src.size()), gsmthRad),
magnitude, histogram, gradNum, pSize, gnrmRad /**/);
featureArray.push_back(/**/ imresize( magnitude, nSize ).clone() /**/);
featureArray.push_back(/**/ imresize( histogram, nSize ).clone() /**/);
}
// Mixing
int resType = CV_MAKETYPE(cv::DataType<float>::type, outNum);
features.create(nSize, resType);
std::vector <int> fromTo;
for (int i = 0; i < 2*outNum; ++i)
fromTo.push_back(i/2);
mixChannels(featureArray, features, fromTo);
}
protected:
/*! algorithm name */
String name;
};
Ptr<RFFeatureGetter> createRFFeatureGetter(void)
{
return makePtr<RFFeatureGetterImpl>();
}
};
/********************* StructuredEdgeDetection class *********************/
namespace cv
{
class StructuredEdgeDetectionImpl : public StructuredEdgeDetection
{
public:
/*!
* This constructor loads __rf model from filename
*
* \param filename : name of the file where the model is stored
*/
StructuredEdgeDetectionImpl(const cv::String &filename,
const RFFeatureGetter *howToGetFeatures)
: name("StructuredEdgeDetection"),
howToGetFeatures( howToGetFeatures != NULL
? howToGetFeatures
: createRFFeatureGetter() )
{
cv::FileStorage modelFile(filename, FileStorage::READ);
CV_Assert( modelFile.isOpened() );
__rf.options.stride
= modelFile["options"]["stride"];
__rf.options.shrinkNumber
= modelFile["options"]["shrinkNumber"];
__rf.options.patchSize
= modelFile["options"]["patchSize"];
__rf.options.patchInnerSize
= modelFile["options"]["patchInnerSize"];
__rf.options.numberOfGradientOrientations
= modelFile["options"]["numberOfGradientOrientations"];
__rf.options.gradientSmoothingRadius
= modelFile["options"]["gradientSmoothingRadius"];
__rf.options.regFeatureSmoothingRadius
= modelFile["options"]["regFeatureSmoothingRadius"];
__rf.options.ssFeatureSmoothingRadius
= modelFile["options"]["ssFeatureSmoothingRadius"];
__rf.options.gradientNormalizationRadius
= modelFile["options"]["gradientNormalizationRadius"];
__rf.options.selfsimilarityGridSize
= modelFile["options"]["selfsimilarityGridSize"];
__rf.options.numberOfTrees
= modelFile["options"]["numberOfTrees"];
__rf.options.numberOfTreesToEvaluate
= modelFile["options"]["numberOfTreesToEvaluate"];
__rf.options.numberOfOutputChannels =
2*(__rf.options.numberOfGradientOrientations + 1) + 3;
//--------------------------------------------
cv::FileNode childs = modelFile["childs"];
cv::FileNode featureIds = modelFile["featureIds"];
std::vector <int> currentTree;
for(cv::FileNodeIterator it = childs.begin();
it != childs.end(); ++it)
{
(*it) >> currentTree;
std::copy(currentTree.begin(), currentTree.end(),
std::back_inserter(__rf.childs));
}
for(cv::FileNodeIterator it = featureIds.begin();
it != featureIds.end(); ++it)
{
(*it) >> currentTree;
std::copy(currentTree.begin(), currentTree.end(),
std::back_inserter(__rf.featureIds));
}
cv::FileNode thresholds = modelFile["thresholds"];
std::vector <float> fcurrentTree;
for(cv::FileNodeIterator it = thresholds.begin();
it != thresholds.end(); ++it)
{
(*it) >> fcurrentTree;
std::copy(fcurrentTree.begin(), fcurrentTree.end(),
std::back_inserter(__rf.thresholds));
}
cv::FileNode edgeBoundaries = modelFile["edgeBoundaries"];
cv::FileNode edgeBins = modelFile["edgeBins"];
for(cv::FileNodeIterator it = edgeBoundaries.begin();
it != edgeBoundaries.end(); ++it)
{
(*it) >> currentTree;
std::copy(currentTree.begin(), currentTree.end(),
std::back_inserter(__rf.edgeBoundaries));
}
for(cv::FileNodeIterator it = edgeBins.begin();
it != edgeBins.end(); ++it)
{
(*it) >> currentTree;
std::copy(currentTree.begin(), currentTree.end(),
std::back_inserter(__rf.edgeBins));
}
__rf.numberOfTreeNodes = int( __rf.childs.size() ) / __rf.options.numberOfTrees;
}
/*!
* The function detects edges in src and draw them to dst
*
* \param src : source image (RGB, float, in [0;1]) to detect edges
* \param dst : destination image (grayscale, float, in [0;1])
* where edges are drawn
*/
void detectEdges(const cv::Mat &src, cv::Mat &dst) const
{
CV_Assert( src.type() == CV_32FC3 );
dst.create( src.size(), cv::DataType<float>::type );
int padding = ( __rf.options.patchSize
- __rf.options.patchInnerSize )/2;
cv::Mat nSrc;
copyMakeBorder( src, nSrc, padding, padding,
padding, padding, BORDER_REFLECT );
NChannelsMat features;
createRFFeatureGetter()->getFeatures( nSrc, features,
__rf.options.gradientNormalizationRadius,
__rf.options.gradientSmoothingRadius,
__rf.options.shrinkNumber,
__rf.options.numberOfOutputChannels,
__rf.options.numberOfGradientOrientations );
predictEdges( features, dst );
}
protected:
/*!
* Private method used by process method. The function
* predict edges in n-channel feature image and store them to dst.
*
* \param features : source image (n-channels, float) to detect edges
* \param dst : destination image (grayscale, float, in [0;1]) where edges are drawn
*/
void predictEdges(const NChannelsMat &features, cv::Mat &dst) const
{
int shrink = __rf.options.shrinkNumber;
int rfs = __rf.options.regFeatureSmoothingRadius;
int sfs = __rf.options.ssFeatureSmoothingRadius;
int nTreesEval = __rf.options.numberOfTreesToEvaluate;
int nTrees = __rf.options.numberOfTrees;
int nTreesNodes = __rf.numberOfTreeNodes;
const int nchannels = features.channels();
int pSize = __rf.options.patchSize;
int nFeatures = CV_SQR(pSize/shrink)*nchannels;
int outNum = __rf.options.numberOfOutputChannels;
int stride = __rf.options.stride;
int ipSize = __rf.options.patchInnerSize;
int gridSize = __rf.options.selfsimilarityGridSize;
const int height = cvCeil( double(features.rows*shrink - pSize) / stride );
const int width = cvCeil( double(features.cols*shrink - pSize) / stride );
// image size in patches with overlapping
//-------------------------------------------------------------------------
NChannelsMat regFeatures = imsmooth(features, cvRound(rfs / float(shrink)));
NChannelsMat ssFeatures = imsmooth(features, cvRound(sfs / float(shrink)));
NChannelsMat indexes(height, width, CV_MAKETYPE(DataType<int>::type, nTreesEval));
std::vector <int> offsetI(/**/ CV_SQR(pSize/shrink)*nchannels, 0);
for (int i = 0; i < CV_SQR(pSize/shrink)*nchannels; ++i)
{
int z = i / CV_SQR(pSize/shrink);
int y = ( i % CV_SQR(pSize/shrink) )/(pSize/shrink);
int x = ( i % CV_SQR(pSize/shrink) )%(pSize/shrink);
offsetI[i] = x*features.cols*nchannels + y*nchannels + z;
}
// lookup table for mapping linear index to offsets
std::vector <int> offsetE(/**/ CV_SQR(ipSize)*outNum, 0);
for (int i = 0; i < CV_SQR(ipSize)*outNum; ++i)
{
int z = i / CV_SQR(ipSize);
int y = ( i % CV_SQR(ipSize) )/ipSize;
int x = ( i % CV_SQR(ipSize) )%ipSize;
offsetE[i] = x*dst.cols*outNum + y*outNum + z;
}
// lookup table for mapping linear index to offsets
std::vector <int> offsetX( CV_SQR(gridSize)*(CV_SQR(gridSize) - 1)/2 * nchannels, 0);
std::vector <int> offsetY( CV_SQR(gridSize)*(CV_SQR(gridSize) - 1)/2 * nchannels, 0);
int hc = cvRound( (pSize/shrink) / (2.0*gridSize) );
// half of cell
std::vector <int> gridPositions;
for(int i = 0; i < gridSize; i++)
gridPositions.push_back( (i+1)*(pSize/shrink + 2*hc - 1)/(gridSize + 1.0) - hc + 0.5 );
for (int i = 0, n = 0; i < CV_SQR(gridSize)*nchannels; ++i)
for (int j = (i%CV_SQR(gridSize)) + 1; j < CV_SQR(gridSize); ++j, ++n)
{
int z = i / CV_SQR(gridSize);
int x1 = gridPositions[i%CV_SQR(gridSize)%gridSize];
int y1 = gridPositions[i%CV_SQR(gridSize)/gridSize];
int x2 = gridPositions[j%gridSize];
int y2 = gridPositions[j/gridSize];
offsetX[n] = x1*features.cols*nchannels + y1*nchannels + z;
offsetY[n] = x2*features.cols*nchannels + y2*nchannels + z;
}
// lookup tables for mapping linear index to offset pairs
for (int i = 0; i < height; ++i)
{
float *regFeaturesPtr = regFeatures.ptr<float>(i*stride/shrink);
float *ssFeaturesPtr = ssFeatures.ptr<float>(i*stride/shrink);
int *indexPtr = indexes.ptr<int>(i);
for (int j = 0, k = 0; j < width; ++k, j += !(k %= nTreesEval))
// for j,k in [0;width)x[0;nTreesEval)
{
int baseNode = ( ((i + j)%(2*nTreesEval) + k)%nTrees )*nTreesNodes;
int currentNode = baseNode;
// select root node of the tree to evaluate
int offset = (j*stride/shrink)*nchannels;
while ( __rf.childs[currentNode] != 0 )
{
int currentId = __rf.featureIds[currentNode];
float currentFeature;
if (currentId >= nFeatures)
{
int xIndex = offsetX[currentId - nFeatures];
float A = ssFeaturesPtr[offset + xIndex];
int yIndex = offsetY[currentId - nFeatures];
float B = ssFeaturesPtr[offset + yIndex];
currentFeature = A - B;
}
else
currentFeature = regFeaturesPtr[offset + offsetI[currentId]];
// compare feature to threshold and move left or right accordingly
if (currentFeature < __rf.thresholds[currentNode])
currentNode = baseNode + __rf.childs[currentNode] - 1;
else
currentNode = baseNode + __rf.childs[currentNode];
}
indexPtr[j*nTreesEval + k] = currentNode;
}
}
NChannelsMat dstM(dst.size(),
CV_MAKETYPE(DataType<float>::type, outNum));
dstM.setTo(0);
float step = 2.0f * CV_SQR(stride) / CV_SQR(ipSize) / nTreesEval;
for (int i = 0; i < height; ++i)
{
int *pIndex = indexes.ptr<int>(i);
float *pDst = dstM.ptr<float>(i*stride);
for (int j = 0, k = 0; j < width; ++k, j += !(k %= nTreesEval))
{// for j,k in [0;width)x[0;nTreesEval)
int currentNode = pIndex[j*nTreesEval + k];
int start = __rf.edgeBoundaries[currentNode];
int finish = __rf.edgeBoundaries[currentNode + 1];
if (start == finish)
continue;
int offset = j*stride*outNum;
for (int p = start; p < finish; ++p)
pDst[offset + offsetE[__rf.edgeBins[p]]] += step;
}
}
cv::reduce( dstM.reshape(1, dstM.total() ), dstM, 2, CV_REDUCE_SUM);
imsmooth( dstM.reshape(1, dst.rows), 1 ).copyTo(dst);
}
/********************* Members *********************/
protected:
/*! algorithm name */
String name;
/*! optional feature getter (getFeatures method) */
const RFFeatureGetter *howToGetFeatures;
/*! random forest used to detect edges */
struct RandomForest
{
/*! random forest options, e.g. number of trees */
struct RandomForestOptions
{
// model params
int numberOfOutputChannels; /*!< number of edge orientation bins for output */
int patchSize; /*!< width of image patches */
int patchInnerSize; /*!< width of predicted part inside patch*/
// feature params
int regFeatureSmoothingRadius; /*!< radius for smoothing of regular features
* (using convolution with triangle filter) */
int ssFeatureSmoothingRadius; /*!< radius for smoothing of additional features
* (using convolution with triangle filter) */
int shrinkNumber; /*!< amount to shrink channels */
int numberOfGradientOrientations; /*!< number of orientations per gradient scale */
int gradientSmoothingRadius; /*!< radius for smoothing of gradients
* (using convolution with triangle filter) */
int gradientNormalizationRadius; /*!< gradient normalization radius */
int selfsimilarityGridSize; /*!< number of self similarity cells */
// detection params
int numberOfTrees; /*!< number of trees in forest to train */
int numberOfTreesToEvaluate; /*!< number of trees to evaluate per location */
int stride; /*!< stride at which to compute edges */
} options;
int numberOfTreeNodes;
std::vector <int> featureIds; /*!< feature coordinate thresholded at k-th node */
std::vector <float> thresholds; /*!< threshold applied to featureIds[k] at k-th node */
std::vector <int> childs; /*!< k --> child[k] - 1, child[k] */
std::vector <int> edgeBoundaries; /*!< ... */
std::vector <int> edgeBins; /*!< ... */
} __rf;
};
Ptr<StructuredEdgeDetection> createStructuredEdgeDetection(const String &model,
const RFFeatureGetter *howToGetFeatures)
{
return makePtr<StructuredEdgeDetectionImpl>(model, howToGetFeatures);
}
}

@ -0,0 +1,39 @@
#include "test_precomp.hpp"
namespace cvtest
{
TEST(ximpgroc_StructuredEdgeDetection, regression)
{
cv::String dir = "C:/Users/Yury/Projects/opencv/sources/opencv_contrib/modules/ximpgroc/testdata/";//cvtest::TS::ptr()->get_data_path();
int nTests = 12;
float threshold = 0.01;
cv::String modelName = dir + "model.yml.gz";
cv::Ptr<cv::StructuredEdgeDetection> pDollar =
cv::createStructuredEdgeDetection(modelName);
for (int i = 0; i < nTests; ++i)
{
cv::String srcName = dir + cv::format( "sources/%02d.png", i + 1);
cv::Mat src = cv::imread( srcName, 1 );
cv::String previousResultName = dir + cv::format( "results/%02d.png", i + 1 );
cv::Mat previousResult = cv::imread( previousResultName, 0 );
previousResult.convertTo( previousResult, cv::DataType<float>::type, 1/255.0 );
cv::cvtColor( src, src, CV_BGR2RGB );
src.convertTo( src, cv::DataType<float>::type, 1/255.0 );
cv::Mat currentResult( src.size(), src.type() );
pDollar->detectEdges( src, currentResult );
cv::Mat sqrError = ( currentResult - previousResult )
.mul( currentResult - previousResult );
cv::Scalar mse = cv::sum(sqrError) / cv::Scalar::all( sqrError.total() );
EXPECT_LE( mse[0], threshold );
}
}
}

@ -0,0 +1,3 @@
#include "test_precomp.hpp"
CV_TEST_MAIN("ximpgroc")

@ -0,0 +1,20 @@
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wmissing-declarations"
# if defined __clang__ || defined __APPLE__
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
# pragma GCC diagnostic ignored "-Wextra"
# endif
#endif
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgproc/types_c.h"
#include "opencv2/highgui.hpp"
#include "opencv2/ximpgroc.hpp"
#include "opencv2/ts.hpp"
#include <iostream>
#endif

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Loading…
Cancel
Save