Commit f6b14349 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #41 from vpisarev/added_text_module

added "text" module; added linemod to rgbd module, fixed compile errors in rgbd
parents 0b8889e0 7968baf2
set(the_description "RGBD algorithms")
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef)
ocv_define_module(rgbd opencv_core opencv_calib3d opencv_contrib opencv_highgui opencv_imgproc)
ocv_define_module(rgbd opencv_core opencv_calib3d opencv_highgui opencv_imgproc)
......@@ -38,12 +38,13 @@
#ifdef __cplusplus
#include <limits>
#include <opencv2/core.hpp>
#include <limits>
namespace cv
{
namespace rgbd
{
/** Checks if the value is a valid depth. For CV_16U or CV_16S, the convention is to be invalid if it is
* a limit. For a float/double, we just check if it is a NaN
* @param depth the depth to check for validity
......@@ -427,7 +428,7 @@ namespace cv
/** Method to compute a transformation from the source frame to the destination one.
* Some odometry algorithms do not used some data of frames (eg. ICP does not use images).
* In such case corresponding arguments can be set as empty cv::Mat.
* In such case corresponding arguments can be set as empty Mat.
* The method returns true if all internal computions were possible (e.g. there were enough correspondences,
* system of equations has a solution, etc) and resulting transformation satisfies some test if it's provided
* by the Odometry inheritor implementation (e.g. thresholds for maximum translation and rotation).
......@@ -507,7 +508,7 @@ namespace cv
computeImpl(const Ptr<OdometryFrame>& srcFrame, const Ptr<OdometryFrame>& dstFrame, Mat& Rt,
const Mat& initRt) const;
// Some params have commented desired type. It's due to cv::AlgorithmInfo::addParams does not support it now.
// Some params have commented desired type. It's due to AlgorithmInfo::addParams does not support it now.
/*float*/
double minDepth, maxDepth, maxDepthDiff;
/*vector<int>*/
......@@ -556,7 +557,7 @@ namespace cv
computeImpl(const Ptr<OdometryFrame>& srcFrame, const Ptr<OdometryFrame>& dstFrame, Mat& Rt,
const Mat& initRt) const;
// Some params have commented desired type. It's due to cv::AlgorithmInfo::addParams does not support it now.
// Some params have commented desired type. It's due to AlgorithmInfo::addParams does not support it now.
/*float*/
double minDepth, maxDepth, maxDepthDiff;
/*float*/
......@@ -569,7 +570,7 @@ namespace cv
double maxTranslation, maxRotation;
mutable cv::Ptr<cv::RgbdNormals> normalsComputer;
mutable Ptr<RgbdNormals> normalsComputer;
};
/** Odometry that merges RgbdOdometry and ICPOdometry by minimize sum of their energy functions.
......@@ -610,7 +611,7 @@ namespace cv
computeImpl(const Ptr<OdometryFrame>& srcFrame, const Ptr<OdometryFrame>& dstFrame, Mat& Rt,
const Mat& initRt) const;
// Some params have commented desired type. It's due to cv::AlgorithmInfo::addParams does not support it now.
// Some params have commented desired type. It's due to AlgorithmInfo::addParams does not support it now.
/*float*/
double minDepth, maxDepth, maxDepthDiff;
/*float*/
......@@ -625,7 +626,7 @@ namespace cv
double maxTranslation, maxRotation;
mutable cv::Ptr<cv::RgbdNormals> normalsComputer;
mutable Ptr<RgbdNormals> normalsComputer;
};
/** Warp the image: compute 3d points from the depth, transform them using given transformation,
......@@ -649,10 +650,12 @@ namespace cv
// TODO Depth interpolation
// Curvature
// Get rescaleDepth return dubles if asked for
} /* namespace rgbd */
} /* namespace cv */
#endif /* __cplusplus */
#include "opencv2/rgbd/linemod.hpp"
#endif /* __cplusplus */
#endif
/* End of file. */
This diff is collapsed.
This diff is collapsed.
......@@ -36,18 +36,45 @@
#include <opencv2/rgbd.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/contrib.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core/utility.hpp>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
using namespace cv::rgbd;
#define BILATERAL_FILTER 0// if 1 then bilateral filter will be used for the depth
class MyTickMeter
{
public:
MyTickMeter() { reset(); }
void start() { startTime = getTickCount(); }
void stop()
{
int64 time = getTickCount();
if ( startTime == 0 )
return;
++counter;
sumTime += ( time - startTime );
startTime = 0;
}
int64 getTimeTicks() const { return sumTime; }
double getTimeSec() const { return (double)getTimeTicks()/getTickFrequency(); }
int64 getCounter() const { return counter; }
void reset() { startTime = sumTime = 0; counter = 0; }
private:
int64 counter;
int64 sumTime;
int64 startTime;
};
static
void writeResults( const string& filename, const vector<string>& timestamps, const vector<Mat>& Rt )
{
......@@ -154,7 +181,7 @@ int main(int argc, char** argv)
}
odometry->set("cameraMatrix", cameraMatrix);
TickMeter gtm;
MyTickMeter gtm;
int count = 0;
for(int i = 0; !file.eof(); i++)
{
......@@ -167,7 +194,7 @@ int main(int argc, char** argv)
// Read one pair (rgb and depth)
// example: 1305031453.359684 rgb/1305031453.359684.png 1305031453.374112 depth/1305031453.374112.png
#if BILATERAL_FILTER
TickMeter tm_bilateral_filter;
MyTickMeter tm_bilateral_filter;
#endif
{
string rgbFilename = str.substr(timestampLength + 1, rgbPathLehgth );
......@@ -213,7 +240,7 @@ int main(int argc, char** argv)
Mat Rt;
if(!Rts.empty())
{
TickMeter tm;
MyTickMeter tm;
tm.start();
gtm.start();
bool res = odometry->compute(frame_curr, frame_prev, Rt);
......
......@@ -33,19 +33,18 @@
*
*/
#include <opencv2/calib3d.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/rgbd.hpp>
#include <iostream>
#include "precomp.hpp"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace
namespace cv
{
namespace rgbd
{
class DepthCleanerImpl
{
public:
DepthCleanerImpl(int window_size, int depth, cv::DepthCleaner::DEPTH_CLEANER_METHOD method)
DepthCleanerImpl(int window_size, int depth, DepthCleaner::DEPTH_CLEANER_METHOD method)
:
depth_(depth),
window_size_(window_size),
......@@ -69,14 +68,11 @@ namespace
protected:
int depth_;
int window_size_;
cv::DepthCleaner::DEPTH_CLEANER_METHOD method_;
DepthCleaner::DEPTH_CLEANER_METHOD method_;
};
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace
{
/** Given a depth image, compute the normals as detailed in the LINEMOD paper
* ``Gradient Response Maps for Real-Time Detection of Texture-Less Objects``
* by S. Hinterstoisser, C. Cagniart, S. Ilic, P. Sturm, N. Navab, P. Fua, and V. Lepetit
......@@ -85,10 +81,10 @@ namespace
class NIL: public DepthCleanerImpl
{
public:
typedef cv::Vec<T, 3> Vec3T;
typedef cv::Matx<T, 3, 3> Mat33T;
typedef Vec<T, 3> Vec3T;
typedef Matx<T, 3, 3> Mat33T;
NIL(int window_size, int depth, cv::DepthCleaner::DEPTH_CLEANER_METHOD method)
NIL(int window_size, int depth, DepthCleaner::DEPTH_CLEANER_METHOD method)
:
DepthCleanerImpl(window_size, depth, method)
{
......@@ -106,27 +102,27 @@ namespace
* @return
*/
void
compute(const cv::Mat& depth_in, cv::Mat& depth_out) const
compute(const Mat& depth_in, Mat& depth_out) const
{
switch (depth_in.depth())
{
case CV_16U:
{
const cv::Mat_<unsigned short> &depth(depth_in);
cv::Mat depth_out_tmp;
const Mat_<unsigned short> &depth(depth_in);
Mat depth_out_tmp;
computeImpl<unsigned short, float>(depth, depth_out_tmp, 0.001f);
depth_out_tmp.convertTo(depth_out, CV_16U);
break;
}
case CV_32F:
{
const cv::Mat_<float> &depth(depth_in);
const Mat_<float> &depth(depth_in);
computeImpl<float, float>(depth, depth_out, 1);
break;
}
case CV_64F:
{
const cv::Mat_<double> &depth(depth_in);
const Mat_<double> &depth(depth_in);
computeImpl<double, double>(depth, depth_out, 1);
break;
}
......@@ -140,7 +136,7 @@ namespace
*/
template<typename DepthDepth, typename ContainerDepth>
void
computeImpl(const cv::Mat_<DepthDepth> &depth_in, cv::Mat & depth_out, ContainerDepth scale) const
computeImpl(const Mat_<DepthDepth> &depth_in, Mat & depth_out, ContainerDepth scale) const
{
const ContainerDepth theta_mean = (float)(30. * CV_PI / 180);
int rows = depth_in.rows;
......@@ -148,14 +144,14 @@ namespace
// Precompute some data
const ContainerDepth sigma_L = (float)(0.8 + 0.035 * theta_mean / (CV_PI / 2 - theta_mean));
cv::Mat_<ContainerDepth> sigma_z(rows, cols);
Mat_<ContainerDepth> sigma_z(rows, cols);
for (int y = 0; y < rows; ++y)
for (int x = 0; x < cols; ++x)
sigma_z(y, x) = (float)(0.0012 + 0.0019 * (depth_in(y, x) * scale - 0.4) * (depth_in(y, x) * scale - 0.4));
ContainerDepth difference_threshold = 10;
cv::Mat_<ContainerDepth> Dw_sum = cv::Mat_<ContainerDepth>::zeros(rows, cols), w_sum =
cv::Mat_<ContainerDepth>::zeros(rows, cols);
Mat_<ContainerDepth> Dw_sum = Mat_<ContainerDepth>::zeros(rows, cols), w_sum =
Mat_<ContainerDepth>::zeros(rows, cols);
for (int y = 0; y < rows - 1; ++y)
{
// Every pixel has had the contribution of previous pixels (in a row-major way)
......@@ -192,15 +188,12 @@ namespace
}
}
}
cv::Mat(Dw_sum / w_sum).copyTo(depth_out);
Mat(Dw_sum / w_sum).copyTo(depth_out);
}
};
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace cv
{
/** Default constructor of the Algorithm class that computes normals
*/
DepthCleaner::DepthCleaner(int depth, int window_size, int method_in)
......@@ -292,12 +285,12 @@ namespace cv
void
DepthCleaner::operator()(InputArray depth_in_array, OutputArray depth_out_array) const
{
cv::Mat depth_in = depth_in_array.getMat();
Mat depth_in = depth_in_array.getMat();
CV_Assert(depth_in.dims == 2);
CV_Assert(depth_in.channels() == 1);
depth_out_array.create(depth_in.size(), depth_);
cv::Mat depth_out = depth_out_array.getMat();
Mat depth_out = depth_out_array.getMat();
// Initialize the pimpl
initialize();
......@@ -324,3 +317,4 @@ namespace cv
}
}
}
}
......@@ -34,12 +34,13 @@
*/
#include <opencv2/rgbd.hpp>
#include <limits>
#include "depth_to_3d.h"
#include "utils.h"
namespace
namespace cv
{
namespace rgbd
{
/**
* @param K
......@@ -47,7 +48,7 @@ namespace
* @param mask the mask of the points to consider (can be empty)
* @param points3d the resulting 3d points, a 3-channel matrix
*/
void
static void
depthTo3d_from_uvz(const cv::Mat& in_K, const cv::Mat& u_mat, const cv::Mat& v_mat, const cv::Mat& z_mat,
cv::Mat& points3d)
{
......@@ -89,7 +90,7 @@ namespace
* @param mask the mask of the points to consider (can be empty)
* @param points3d the resulting 3d points
*/
void
static void
depthTo3dMask(const cv::Mat& depth, const cv::Mat& K, const cv::Mat& mask, cv::Mat& points3d)
{
// Create 3D points in one go.
......@@ -168,13 +169,9 @@ namespace
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
namespace cv
{
/**
* @param K
* @param depth the depth image
......@@ -263,3 +260,4 @@ namespace cv
}
}
}
}
......@@ -39,7 +39,12 @@
#ifdef __cplusplus
#include <opencv2/core.hpp>
#include <limits>
#include <limits.h>
namespace cv
{
namespace rgbd
{
/**
* @param depth the depth image, containing depth with the value T
......@@ -114,6 +119,9 @@ convertDepthToFloat(const cv::Mat& depth, float scale, const cv::Mat &uv_mat, cv
}
}
}
}
#endif /* __cplusplus */
#endif
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*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_PRECOMP_H__
#define __OPENCV_PRECOMP_H__
#include "opencv2/rgbd.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/core/private.hpp"
#include <iostream>
#include <list>
#include <set>
#include <limits>
#endif
......@@ -39,6 +39,8 @@
#include "opencv2/core/private.hpp"
namespace cv
{
namespace rgbd
{
CV_INIT_ALGORITHM(DepthCleaner, "RGBD.DepthCleaner",
obj.info()->addParam(obj, "window_size", obj.window_size_);
......@@ -84,7 +86,7 @@ namespace cv
obj.info()->addParam(obj, "transformType", obj.transformType);
obj.info()->addParam(obj, "maxTranslation", obj.maxTranslation);
obj.info()->addParam(obj, "maxRotation", obj.maxRotation);
obj.info()->addParam<cv::RgbdNormals>(obj, "normalsComputer", obj.normalsComputer, true, NULL, NULL);)
obj.info()->addParam<RgbdNormals>(obj, "normalsComputer", obj.normalsComputer, true, NULL, NULL);)
CV_INIT_ALGORITHM(RgbdICPOdometry, "RGBD.RgbdICPOdometry",
obj.info()->addParam(obj, "cameraMatrix", obj.cameraMatrix);
......@@ -97,7 +99,7 @@ namespace cv
obj.info()->addParam(obj, "transformType", obj.transformType);
obj.info()->addParam(obj, "maxTranslation", obj.maxTranslation);
obj.info()->addParam(obj, "maxRotation", obj.maxRotation);
obj.info()->addParam<cv::RgbdNormals>(obj, "normalsComputer", obj.normalsComputer, true, NULL, NULL);)
obj.info()->addParam<RgbdNormals>(obj, "normalsComputer", obj.normalsComputer, true, NULL, NULL);)
bool
initModule_rgbd(void);
......@@ -113,3 +115,5 @@ namespace cv
return all;
}
}
}
......@@ -40,6 +40,8 @@
namespace cv
{
namespace rgbd
{
/** If the input image is of type CV_16UC1 (like the Kinect one), the image is converted to floats, divided
* by 1000 to get a depth in meters, and the values 0 are converted to std::numeric_limits<float>::quiet_NaN()
* Otherwise, the image is simply converted to floats
......@@ -75,3 +77,5 @@ namespace cv
in.convertTo(out, depth);
}
}
}
......@@ -40,6 +40,11 @@
#include <opencv2/rgbd.hpp>
namespace cv
{
namespace rgbd
{
/** If the input image is of type CV_16UC1 (like the Kinect one), the image is converted to floats, divided
* by 1000 to get a depth in meters, and the values 0 are converted to std::numeric_limits<float>::quiet_NaN()
* Otherwise, the image is simply converted to floats
......@@ -50,22 +55,25 @@
*/
template<typename T>
void
rescaleDepthTemplated(const cv::Mat& in, cv::Mat& out);
rescaleDepthTemplated(const Mat& in, Mat& out);
template<>
inline void
rescaleDepthTemplated<float>(const cv::Mat& in, cv::Mat& out)
rescaleDepthTemplated<float>(const Mat& in, Mat& out)
{
rescaleDepth(in, CV_32F, out);
}
template<>
inline void
rescaleDepthTemplated<double>(const cv::Mat& in, cv::Mat& out)
rescaleDepthTemplated<double>(const Mat& in, Mat& out)
{
rescaleDepth(in, CV_64F, out);
}
}
}
#endif /* __cplusplus */
#endif
......
This diff is collapsed.
......@@ -33,13 +33,16 @@
*
*/
#include "test_precomp.hpp"
#include <opencv2/calib3d.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "test_precomp.hpp"
using namespace cv;
namespace cv
{
namespace rgbd
{
#define SHOW_DEBUG_LOG 0
#define SHOW_DEBUG_IMAGES 0
......@@ -152,7 +155,7 @@ void dilateFrame(Mat& image, Mat& depth)
class CV_OdometryTest : public cvtest::BaseTest
{
public:
CV_OdometryTest(const Ptr<Odometry>& _odometry,
CV_OdometryTest(const Ptr<Odometry>& _odometry,
double _maxError1,
double _maxError5) :
odometry(_odometry),
......@@ -330,21 +333,23 @@ void CV_OdometryTest::run(int)
/****************************************************************************************\
* Tests registrations *
\****************************************************************************************/
}
}
TEST(RGBD_Odometry_Rgbd, algorithmic)
{
CV_OdometryTest test(Algorithm::create<Odometry>("RGBD.RgbdOdometry"), 0.99, 0.94);
cv::rgbd::CV_OdometryTest test(cv::Algorithm::create<cv::rgbd::Odometry>("RGBD.RgbdOdometry"), 0.99, 0.94);
test.safe_run();
}
TEST(RGBD_Odometry_ICP, algorithmic)
{
CV_OdometryTest test(Algorithm::create<Odometry>("RGBD.ICPOdometry"), 0.99, 0.99);
cv::rgbd::CV_OdometryTest test(cv::Algorithm::create<cv::rgbd::Odometry>("RGBD.ICPOdometry"), 0.99, 0.99);
test.safe_run();
}
TEST(RGBD_Odometry_RgbdICP, algorithmic)
{
CV_OdometryTest test(Algorithm::create<Odometry>("RGBD.RgbdICPOdometry"), 0.99, 0.99);
cv::rgbd::CV_OdometryTest test(cv::Algorithm::create<cv::rgbd::Odometry>("RGBD.RgbdICPOdometry"), 0.99, 0.99);
test.safe_run();
}
#include "test_precomp.hpp"
#include <opencv2/calib3d.hpp>
#include "test_precomp.hpp"
namespace cv
{
namespace rgbd
{
class CV_RgbdDepthTo3dTest: public cvtest::BaseTest
{
......@@ -18,31 +23,31 @@ protected:
try
{
// K from a VGA Kinect
cv::Mat K = (cv::Mat_<float>(3, 3) << 525., 0., 319.5, 0., 525., 239.5, 0., 0., 1.);
Mat K = (Mat_<float>(3, 3) << 525., 0., 319.5, 0., 525., 239.5, 0., 0., 1.);
// Create a random depth image
cv::RNG rng;
cv::Mat_<float> depth(480, 640);
rng.fill(depth, cv::RNG::UNIFORM, 0, 100);
RNG rng;
Mat_<float> depth(480, 640);
rng.fill(depth, RNG::UNIFORM, 0, 100);
// Create some 3d points on the plane
int rows = depth.rows, cols = depth.cols;
cv::Mat_<cv::Vec3f> points3d;
cv::depthTo3d(depth, K, points3d);
Mat_<Vec3f> points3d;
depthTo3d(depth, K, points3d);
// Make sure the points belong to the plane
cv::Mat points = points3d.reshape(1, rows*cols);
cv::Mat image_points;
cv::Mat rvec;
cv::Rodrigues(cv::Mat::eye(3,3,CV_32F),rvec);
cv::Mat tvec = (cv::Mat_<float>(1,3) << 0, 0, 0);
cv::projectPoints(points, rvec, tvec, K, cv::Mat(), image_points);
Mat points = points3d.reshape(1, rows*cols);
Mat image_points;
Mat rvec;
Rodrigues(Mat::eye(3,3,CV_32F),rvec);
Mat tvec = (Mat_<float>(1,3) << 0, 0, 0);
projectPoints(points, rvec, tvec, K, Mat(), image_points);
image_points = image_points.reshape(2, rows);
float avg_diff = 0;
for (int y = 0; y < rows; ++y)
for (int x = 0; x < cols; ++x)
avg_diff += (float)cv::norm(image_points.at<cv::Vec2f>(y,x) - cv::Vec2f((float)x,(float)y));
avg_diff += (float)norm(image_points.at<Vec2f>(y,x) - Vec2f((float)x,(float)y));
// Verify the function works
ASSERT_LE(avg_diff/rows/cols, 1e-4) << "Average error for ground truth is: " << (avg_diff / rows / cols);
......@@ -54,8 +59,11 @@ protected:
}
};
}
}
TEST(Rgbd_DepthTo3d, compute)
{
CV_RgbdDepthTo3dTest test;
cv::rgbd::CV_RgbdDepthTo3dTest test;
test.safe_run();
}
set(the_description "Text Detection and Recognition")
ocv_define_module(text opencv_ml opencv_highgui opencv_imgproc opencv_core)
This diff is collapsed.
***************************
objdetect. Object Detection
***************************
.. highlight:: cpp
.. toctree::
:maxdepth: 2
erfilter
/*
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
(3-clause BSD License)
Copyright (C) 2013, OpenCV Foundation, 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:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions 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.
* Neither the names of the copyright holders nor the names of the contributors
may 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 copyright holders 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.
*/
#ifndef __OPENCV_TEXT_HPP__
#define __OPENCV_TEXT_HPP__
#include "opencv2/text/erfilter.hpp"
#endif
This diff is collapsed.
/*
* textdetection.cpp
*
* A demo program of the Extremal Region Filter algorithm described in
* Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012
*
* Created on: Sep 23, 2013
* Author: Lluis Gomez i Bigorda <lgomez AT cvc.uab.es>
*/
#include "opencv2/text.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;
using namespace cv;
using namespace cv::text;
void show_help_and_exit(const char *cmd);
void groups_draw(Mat &src, vector<Rect> &groups);
void er_show(vector<Mat> &channels, vector<vector<ERStat> > &regions);
int main(int argc, const char * argv[])
{
cout << endl << argv[0] << endl << endl;
cout << "Demo program of the Extremal Region Filter algorithm described in " << endl;
cout << "Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012" << endl << endl;
if (argc < 2) show_help_and_exit(argv[0]);
Mat src = imread(argv[1]);
// Extract channels to be processed individually
vector<Mat> channels;
computeNMChannels(src, channels);
int cn = (int)channels.size();
// Append negative channels to detect ER- (bright regions over dark background)
for (int c = 0; c < cn-1; c++)
channels.push_back(255-channels[c]);
// Create ERFilter objects with the 1st and 2nd stage default classifiers
Ptr<ERFilter> er_filter1 = createERFilterNM1(loadClassifierNM1("trained_classifierNM1.xml"),16,0.00015f,0.13f,0.2f,true,0.1f);
Ptr<ERFilter> er_filter2 = createERFilterNM2(loadClassifierNM2("trained_classifierNM2.xml"),0.5);
vector<vector<ERStat> > regions(channels.size());
// Apply the default cascade classifier to each independent channel (could be done in parallel)
cout << "Extracting Class Specific Extremal Regions from " << (int)channels.size() << " channels ..." << endl;
cout << " (...) this may take a while (...)" << endl << endl;
for (int c=0; c<(int)channels.size(); c++)
{
er_filter1->run(channels[c], regions[c]);
er_filter2->run(channels[c], regions[c]);
}
// Detect character groups
cout << "Grouping extracted ERs ... ";
vector<Rect> groups;
erGrouping(channels, regions, "trained_classifier_erGrouping.xml", 0.5, groups);
// draw groups
groups_draw(src, groups);
imshow("grouping",src);
cout << "Done!" << endl << endl;
cout << "Press 'e' to show the extracted Extremal Regions, any other key to exit." << endl << endl;
if( waitKey (-1) == 101)
er_show(channels,regions);
// memory clean-up
er_filter1.release();
er_filter2.release();
regions.clear();
if (!groups.empty())
{
groups.clear();
}
}
// helper functions
void show_help_and_exit(const char *cmd)
{
cout << " Usage: " << cmd << " <input_image> " << endl;
cout << " Default classifier files (trained_classifierNM*.xml) must be in current directory" << endl << endl;
exit(-1);
}
void groups_draw(Mat &src, vector<Rect> &groups)
{
for (int i=(int)groups.size()-1; i>=0; i--)
{
if (src.type() == CV_8UC3)
rectangle(src,groups.at(i).tl(),groups.at(i).br(),Scalar( 0, 255, 255 ), 3, 8 );
else
rectangle(src,groups.at(i).tl(),groups.at(i).br(),Scalar( 255 ), 3, 8 );
}
}
void er_show(vector<Mat> &channels, vector<vector<ERStat> > &regions)
{
for (int c=0; c<(int)channels.size(); c++)
{
Mat dst = Mat::zeros(channels[0].rows+2,channels[0].cols+2,CV_8UC1);
for (int r=0; r<(int)regions[c].size(); r++)
{
ERStat er = regions[c][r];
if (er.parent != NULL) // deprecate the root region
{
int newMaskVal = 255;
int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
floodFill(channels[c],dst,Point(er.pixel%channels[c].cols,er.pixel/channels[c].cols),
Scalar(255),0,Scalar(er.level),Scalar(0),flags);
}
}
char buff[10]; char *buff_ptr = buff;
sprintf(buff, "channel %d", c);
imshow(buff_ptr, dst);
}
waitKey(-1);
}
This diff is collapsed.
This diff is collapsed.
......@@ -175,5 +175,4 @@ public:
} /* namespace xobjdetect */
} /* namespace cv */
#endif /* __OPENCV_XOBJDETECT_XOBJDETECT_HPP__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment