Commit 79020cf7 authored by Bellaktris's avatar Bellaktris

propagation-assissted kd-tree search added, but not well debugged yet

parent 809c13bc
...@@ -87,7 +87,7 @@ public: ...@@ -87,7 +87,7 @@ public:
const int gradNum) const = 0; const int gradNum) const = 0;
}; };
CV_EXPORTS_W Ptr<RFFeatureGetter> createRFFeatureGetter(void); CV_EXPORTS_W Ptr<RFFeatureGetter> createRFFeatureGetter();
......
...@@ -280,7 +280,7 @@ public: ...@@ -280,7 +280,7 @@ public:
* \param outNum : __rf.options.numberOfOutputChannels * \param outNum : __rf.options.numberOfOutputChannels
* \param gradNum : __rf.options.numberOfGradientOrientations * \param gradNum : __rf.options.numberOfGradientOrientations
*/ */
virtual void getFeatures(const cv::Mat &src, Mat &features, const int gnrmRad, const int gsmthRad, virtual void getFeatures(const Mat &src, Mat &features, const int gnrmRad, const int gsmthRad,
const int shrink, const int outNum, const int gradNum) const const int shrink, const int outNum, const int gradNum) const
{ {
cv::Mat luvImg = rgb2luv(src); cv::Mat luvImg = rgb2luv(src);
...@@ -320,7 +320,7 @@ protected: ...@@ -320,7 +320,7 @@ protected:
String name; String name;
}; };
Ptr<RFFeatureGetter> createRFFeatureGetter(void) Ptr<RFFeatureGetter> createRFFeatureGetter()
{ {
return makePtr<RFFeatureGetterImpl>(); return makePtr<RFFeatureGetterImpl>();
} }
......
...@@ -40,87 +40,234 @@ ...@@ -40,87 +40,234 @@
#ifndef __ANNF_HPP__ #ifndef __ANNF_HPP__
#define __ANNF_HPP__ #define __ANNF_HPP__
#include "algo.hpp" #include "norm2.hpp"
#include "whs.hpp"
static void plusToMinusUpdate(const cv::Mat &current, cv::Mat &next, const int dx, const int dy) /************************* KDTree class *************************/
template <typename ForwardIterator> void
generate_seq(ForwardIterator it, int first, int last)
{
for (int i = first; i < last; ++i, ++it)
*it = i;
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
template <typename Tp, int cn> class KDTree
{
private:
class KDTreeComparator
{
const KDTree <Tp, cn> *main; // main class
int dimIdx; // dimension to compare
public:
bool operator () (const int &x, const int &y) const
{
cv::Vec <Tp, cn> u = main->data[main->idx[x]];
cv::Vec <Tp, cn> v = main->data[main->idx[y]];
return u[dimIdx] < v[dimIdx];
}
KDTreeComparator(const KDTree <Tp, cn> *_main, int _dimIdx)
: main(_main), dimIdx(_dimIdx) {}
};
const int leafNumber;
int getMaxSpreadN(const int left, const int right) const;
void operator =(const KDTree <Tp, cn> &) const {};
public:
std::vector <cv::Vec <Tp, cn> > data;
std::vector <int> idx;
std::vector <cv::Point2i> nodes;
KDTree(const cv::Mat &data, const int leafNumber = 8);
~KDTree(){};
};
template <typename Tp, int cn> int KDTree <Tp, cn>::
getMaxSpreadN(const int _left, const int _right) const
{ {
for (int i = 0; i < next.rows; ++i) cv::Vec<Tp, cn> maxValue = data[ idx[_left] ],
for (int j = 0; j < next.cols; ++j) minValue = data[ idx[_left] ];
for (int i = _left + 1; i < _right; i += cn)
for (int j = 0; j < cn; ++j)
{
minValue[j] = std::min( minValue[j], data[idx[i]][j] );
maxValue[j] = std::max( maxValue[j], data[idx[i]][j] );
}
cv::Vec<Tp, cn> spread = maxValue - minValue;
Tp *begIt = &spread[0];
return int(std::max_element(begIt, begIt + cn) - begIt);
}
template <typename Tp, int cn> KDTree <Tp, cn>::
KDTree(const cv::Mat &img, const int _leafNumber)
: leafNumber(_leafNumber)
///////////////////////////////////////////////////
{
for (int i = 0; i < img.rows; ++i)
for (int j = 0; j < img.cols; ++j)
data.push_back(img.template at<cv::Vec <Tp, cn> >(i, j));
generate_seq( std::back_inserter(idx), 0, int(data.size()) );
fill_n( std::back_inserter(nodes), int(data.size()), cv::Point2i(0, 0) );
std::stack <int> left, right;
left.push( 0 );
right.push( int(idx.size()) );
while ( !left.empty() )
{ {
int y = cv::borderInterpolate(i - dy, next.rows, cv::BORDER_CONSTANT); int _left = left.top(); left.pop();
int x = cv::borderInterpolate(j - dx, next.cols, cv::BORDER_CONSTANT); int _right = right.top(); right.pop();
next.at<float>(i, j) = -next.at<float>(y, x) if ( _right - _left <= leafNumber)
+ current.at<float>(i, j) - current.at<float>(y, x); {
for (int i = _left; i < _right; ++i)
{
nodes[idx[i]].x = _left;
nodes[idx[i]].y = _right;
}
continue;
}
std::vector <int>::iterator begIt = idx.begin();
int nth = _left + (_right - _left)/2;
std::nth_element(/**/ begIt + _left,
begIt + nth, begIt + _right,
KDTreeComparator( this,
getMaxSpreadN(_left, _right) ) /**/);
left.push(_left); right.push(nth + 1);
left.push(nth + 1); right.push(_right);
} }
} }
static void minusToPlusUpdate(const cv::Mat &current, cv::Mat &next, const int dx, const int dy) /************************** ANNF search **************************/
template <typename Tp, int cn>
static void updateDist(const KDTree <Tp, cn> &kdTree, const cv::Point2i &I, const int height,
const int width, const int &currentIdx, int &bestIdx, double &dist)
{ {
for (int i = 0; i < next.rows; ++i) for (int k = I.x; k < I.y; ++k)
for (int j = 0; j < next.cols; ++j)
{ {
int y = cv::borderInterpolate(i - dy, next.rows, cv::BORDER_CONSTANT); int newIdx = kdTree.idx[k];
int x = cv::borderInterpolate(j - dx, next.cols, cv::BORDER_CONSTANT);
if (newIdx%width == width - 1)
continue;
if (newIdx/width == height - 1)
continue;
next.at<float>(i, j) = next.at<float>(y, x) int dx = currentIdx%width - newIdx%width;
- current.at<float>(i, j) + current.at<float>(y, x); int dy = currentIdx/width - newIdx/width;
if (abs(dx) + abs(dy) < 32)
continue;
double ndist = norm2(kdTree.data[newIdx],
kdTree.data[currentIdx]);
if (ndist < dist)
{
dist = ndist;
bestIdx = newIdx;
}
} }
} }
static void getWHSeries(const cv::Mat &src, cv::Mat &dst, const int nProjections, const int psize = 8) static void getANNF(const cv::Mat &img, std::vector <cv::Matx33f> &transforms,
const int nTransform, const int psize)
{ {
CV_Assert(nProjections <= psize*psize && src.type() == CV_32FC3); /** Walsh-Hadamard Transformation **/
CV_Assert( hamming_length(psize) == 1 );
std::vector <cv::Mat> channels;
cv::split(img, channels);
std::vector <cv::Mat> projections; const int np[] = {16, 4, 4};
for (int i = 0; i < img.channels(); ++i)
getWHSeries(channels[i], channels[i], np[i], psize);
cv::Mat proj; cv::Mat whs; // Walsh-Hadamard series
cv::boxFilter(proj, proj, CV_32F, cv::Size(psize, psize), cv::merge(channels, whs);
cv::Point(-1,-1), false, cv::BORDER_REFLECT);
projections.push_back(proj); KDTree <float, 24> kdTree(whs);
std::vector <int> annf( whs.total(), 0 );
std::vector <int> snake_idx(1, 0); /** Propagation-assisted kd-tree search **/
std::vector <int> snake_idy(1, 0);
for (int k = 1, num = 1; k < psize && num <= nProjections; ++k) for (int i = 0; i < whs.rows; ++i)
for (int j = 0; j < whs.cols; ++j)
{ {
const int dx[] = { (k % 2 == 0) ? +1 : 0, (k % 2 == 0) ? 0 : -1}; double dist = std::numeric_limits <double>::max();
const int dy[] = { (k % 2 == 0) ? 0 : +1, (k % 2 == 0) ? -1 : 0}; int current = i*whs.cols + j;
snake_idx.push_back(snake_idx[num - 1] - dx[1]); cv::Point2i I = kdTree.nodes[i*whs.cols + j];
snake_idy.push_back(snake_idy[num++ - 1] - dy[1]); updateDist(kdTree, I, whs.rows, whs.cols, current, annf[i*whs.cols + j], dist);
for (int i = 0; i < k && num < nProjections; ++i, ++num) if (i != 0)
{ {
snake_idx.push_back(snake_idx[num - 1] + dx[0]); int idx = annf[(i - 1)*whs.cols + j] + whs.cols;
snake_idy.push_back(snake_idy[num - 1] + dy[0]); cv::Point2i I = kdTree.nodes[idx];
updateDist(kdTree, I, whs.rows, whs.cols, current, annf[i*whs.cols + j], dist);
} }
for (int i = 0; i < k && num < nProjections; ++i, ++num) if (j != 0)
{ {
snake_idx.push_back(snake_idx[num - 1] + dx[1]); int idx = annf[i*whs.cols + (j - 1)] + 1;
snake_idy.push_back(snake_idy[num - 1] + dy[1]); cv::Point2i I = kdTree.nodes[idx];
updateDist(kdTree, I, whs.rows, whs.cols, current, annf[i*whs.cols + j], dist);
} }
} }
for (int i = 1; i < nProjections; ++i) /** Local maxima extraction **/
{
int dx = (snake_idx[i] - snake_idx[i - 1]); cv::Mat_<double> annfHist(2*whs.rows, 2*whs.cols, 0.0),
int dy = (snake_idy[i] - snake_idy[i - 1]); _annfHist(2*whs.rows, 2*whs.cols, 0.0);
for (size_t i = 0; i < annf.size(); ++i)
++annfHist( (annf[i] - int(i))/whs.cols + whs.rows,
(annf[i] - int(i))%whs.cols + whs.cols);
dx <<= hamming_length(psize - 1) - hamming_length(snake_idx[i - 1] ^ snake_idx[i]); cv::GaussianBlur( annfHist, annfHist,
dy <<= hamming_length(psize - 1) - hamming_length(snake_idy[i - 1] ^ snake_idy[i]); cv::Size(9, 9), 1.41, 0.0, cv::BORDER_CONSTANT);
cv::dilate(annfHist, _annfHist,
cv::Matx<uchar, 9, 9>::ones());
std::vector < std::pair<double, int> > amount;
std::vector <cv::Point2i> shiftM;
for (int i = 0, t = 0; i < annfHist.rows; ++i)
{
double *pAnnfHist = annfHist.template ptr<double>(i);
double *_pAnnfHist = _annfHist.template ptr<double>(i);
if (i % 2 == 0) for (int j = 0; j < annfHist.cols; ++j)
plusToMinusUpdate(proj, proj, dx, dy); if ( pAnnfHist[j] != 0 && pAnnfHist[j] == _pAnnfHist[j] )
else {
minusToPlusUpdate(proj, proj, dx, dy); amount.push_back( std::make_pair(pAnnfHist[j], t++) );
shiftM.push_back(cv::Point2i(j - whs.cols,
i - whs.rows));
}
} }
cv::merge(projections, dst); std::partial_sort( amount.begin(), amount.begin() + nTransform,
} amount.end(), std::greater< std::pair<double, int> >() );
transforms.resize(nTransform);
for (int i = 0; i < nTransform; ++i)
{
int idx = amount[i].second;
transforms[i] = cv::Matx33f(1, 0, float(shiftM[idx].x),
0, 1, float(shiftM[idx].y),
0, 0, 1 );
}
}
#endif /* __ANNF_HPP__ */ #endif /* __ANNF_HPP__ */
...@@ -38,14 +38,18 @@ ...@@ -38,14 +38,18 @@
//M*/ //M*/
#include <vector> #include <vector>
#include <stack>
#include <limits> #include <limits>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <iostream> #include <iostream>
#include <time.h> #include <time.h>
#include <functional>
#include "opencv2/xphoto.hpp" #include "opencv2/xphoto.hpp"
#include "opencv2/imgproc.hpp" #include "opencv2/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/core.hpp" #include "opencv2/core.hpp"
#include "opencv2/core/core_c.h" #include "opencv2/core/core_c.h"
...@@ -67,18 +71,17 @@ namespace cv ...@@ -67,18 +71,17 @@ namespace cv
const int nTransform = 60; // number of dominant transforms for stitching const int nTransform = 60; // number of dominant transforms for stitching
const int psize = 8; // single ANNF patch size const int psize = 8; // single ANNF patch size
/** ANNF computation **/ cv::Mat img;
srand( unsigned(time(NULL)) );
cvtColor(src, img, CV_RGB2Lab);
img.setTo(0, 255 - mask);
img.convertTo( img, CV_32F );
std::vector <Matx33f> transforms; // dominant transforms
for (int i = 0; i < nTransform; ++i) /** ANNF computation **/
{ std::vector <Matx33f> transforms( nTransform );
float dx = float( rand()%src.cols - src.cols/2 ); xphotoInternal::getANNF(img, transforms,
float dy = float( rand()%src.rows - src.rows/2 ); nTransform, psize);
transforms.push_back( Matx33f( 1, 0, dx,
0, 1, dy,
0, 0, 1) );
}
/** Warping **/ /** Warping **/
std::vector <Mat> images( nTransform + 1 ); // source image transformed with transforms std::vector <Mat> images( nTransform + 1 ); // source image transformed with transforms
...@@ -87,7 +90,7 @@ namespace cv ...@@ -87,7 +90,7 @@ namespace cv
Mat_<uchar> invMask = 255 - mask; Mat_<uchar> invMask = 255 - mask;
dilate(invMask, invMask, Mat(), Point(-1,-1), 2); dilate(invMask, invMask, Mat(), Point(-1,-1), 2);
src.convertTo( images[0], CV_32F ); img.copyTo( images[0] );
mask.copyTo( masks[0] ); mask.copyTo( masks[0] );
for (int i = 0; i < nTransform; ++i) for (int i = 0; i < nTransform; ++i)
...@@ -104,7 +107,10 @@ namespace cv ...@@ -104,7 +107,10 @@ namespace cv
Mat photomontageResult; Mat photomontageResult;
xphotoInternal::Photomontage < cv::Vec <float, cn> >( images, masks ) xphotoInternal::Photomontage < cv::Vec <float, cn> >( images, masks )
.assignResImage(photomontageResult); .assignResImage(photomontageResult);
photomontageResult.convertTo( dst, dst.type() );
/** Writing result **/
photomontageResult.convertTo( photomontageResult, dst.type() );
cvtColor(photomontageResult, dst, CV_Lab2RGB);
} }
template <typename Tp, unsigned int cn> template <typename Tp, unsigned int cn>
...@@ -137,66 +143,66 @@ namespace cv ...@@ -137,66 +143,66 @@ namespace cv
switch ( src.type() ) switch ( src.type() )
{ {
case CV_8UC1: //case CV_8UC1:
inpaint <uchar, 1>( src, mask, dst, algorithmType ); // inpaint <uchar, 1>( src, mask, dst, algorithmType );
break; // break;
case CV_8UC2: //case CV_8UC2:
inpaint <uchar, 2>( src, mask, dst, algorithmType ); // inpaint <uchar, 2>( src, mask, dst, algorithmType );
break; // break;
case CV_8UC3: case CV_8UC3:
inpaint <uchar, 3>( src, mask, dst, algorithmType ); inpaint <uchar, 3>( src, mask, dst, algorithmType );
break; break;
case CV_8UC4: //case CV_8UC4:
inpaint <uchar, 4>( src, mask, dst, algorithmType ); // inpaint <uchar, 4>( src, mask, dst, algorithmType );
break; // break;
case CV_16SC1: //case CV_16SC1:
inpaint <short, 1>( src, mask, dst, algorithmType ); // inpaint <short, 1>( src, mask, dst, algorithmType );
break; // break;
case CV_16SC2: //case CV_16SC2:
inpaint <short, 2>( src, mask, dst, algorithmType ); // inpaint <short, 2>( src, mask, dst, algorithmType );
break; // break;
case CV_16SC3: case CV_16SC3:
inpaint <short, 3>( src, mask, dst, algorithmType ); inpaint <short, 3>( src, mask, dst, algorithmType );
break; break;
case CV_16SC4: //case CV_16SC4:
inpaint <short, 4>( src, mask, dst, algorithmType ); // inpaint <short, 4>( src, mask, dst, algorithmType );
break; // break;
case CV_32SC1: //case CV_32SC1:
inpaint <int, 1>( src, mask, dst, algorithmType ); // inpaint <int, 1>( src, mask, dst, algorithmType );
break; // break;
case CV_32SC2: //case CV_32SC2:
inpaint <int, 2>( src, mask, dst, algorithmType ); // inpaint <int, 2>( src, mask, dst, algorithmType );
break; // break;
case CV_32SC3: case CV_32SC3:
inpaint <int, 3>( src, mask, dst, algorithmType ); inpaint <int, 3>( src, mask, dst, algorithmType );
break; break;
case CV_32SC4: //case CV_32SC4:
inpaint <int, 4>( src, mask, dst, algorithmType ); // inpaint <int, 4>( src, mask, dst, algorithmType );
break; // break;
case CV_32FC1: //case CV_32FC1:
inpaint <float, 1>( src, mask, dst, algorithmType ); // inpaint <float, 1>( src, mask, dst, algorithmType );
break; // break;
case CV_32FC2: //case CV_32FC2:
inpaint <float, 2>( src, mask, dst, algorithmType ); // inpaint <float, 2>( src, mask, dst, algorithmType );
break; // break;
case CV_32FC3: case CV_32FC3:
inpaint <float, 3>( src, mask, dst, algorithmType ); inpaint <float, 3>( src, mask, dst, algorithmType );
break; break;
case CV_32FC4: //case CV_32FC4:
inpaint <float, 4>( src, mask, dst, algorithmType ); // inpaint <float, 4>( src, mask, dst, algorithmType );
break; // break;
case CV_64FC1: //case CV_64FC1:
inpaint <double, 1>( src, mask, dst, algorithmType ); // inpaint <double, 1>( src, mask, dst, algorithmType );
break; // break;
case CV_64FC2: //case CV_64FC2:
inpaint <double, 2>( src, mask, dst, algorithmType ); // inpaint <double, 2>( src, mask, dst, algorithmType );
break; // break;
case CV_64FC3: case CV_64FC3:
inpaint <double, 3>( src, mask, dst, algorithmType ); inpaint <double, 3>( src, mask, dst, algorithmType );
break; break;
case CV_64FC4: //case CV_64FC4:
inpaint <double, 4>( src, mask, dst, algorithmType ); // inpaint <double, 4>( src, mask, dst, algorithmType );
break; // break;
default: default:
CV_Error_( CV_StsNotImplemented, CV_Error_( CV_StsNotImplemented,
("Unsupported source image format (=%d)", ("Unsupported source image format (=%d)",
......
...@@ -42,11 +42,17 @@ ...@@ -42,11 +42,17 @@
#include "norm2.hpp" #include "norm2.hpp"
#include "algo.hpp"
#include "gcgraph.hpp" #include "gcgraph.hpp"
#define GCInfinity 10*1000*1000*1000.0 #define GCInfinity 10*1000*1000*1000.0
template <typename Tp> static int min_idx(std::vector <Tp> vec)
{
return int( std::min_element(vec.begin(), vec.end()) - vec.begin() );
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
template <typename Tp> class Photomontage template <typename Tp> class Photomontage
{ {
......
...@@ -37,16 +37,10 @@ ...@@ -37,16 +37,10 @@
// //
//M*/ //M*/
#ifndef __ALGO_HPP__ #ifndef __WHS_HPP__
#define __ALGO_HPP__ #define __WHS_HPP__
static inline int hl(int x)
template <typename Tp> static int min_idx(std::vector <Tp> vec)
{
return int( std::min_element(vec.begin(), vec.end()) - vec.begin() );
}
static inline int hamming_length(int x)
{ {
int res = 0; int res = 0;
while (x) while (x)
...@@ -57,5 +51,69 @@ static inline int hamming_length(int x) ...@@ -57,5 +51,69 @@ static inline int hamming_length(int x)
return res; return res;
} }
static void nextProjection(std::vector <cv::Mat> &projections, const cv::Point &A,
const cv::Point &B, const int psize)
{
int xsign = (A.x != B.x)*(hl(A.x&B.x) + (B.x > A.x))&1;
int ysign = (A.y != B.y)*(hl(A.y&B.y) + (B.y > A.y))&1;
bool plusToMinusUpdate = std::max(xsign, ysign);
int dx = (A.x != B.x) << hl(psize - 1) - hl(A.x ^ B.x);
int dy = (A.y != B.y) << hl(psize - 1) - hl(A.y ^ B.y);
cv::Mat proj = projections[projections.size() - 1];
cv::Mat nproj( proj.size(), proj.type(), cv::Scalar::all(0) );
for (int i = dy; i < nproj.rows; ++i)
{
float *vCurrent = proj.template ptr<float>(i);
float *vxCurrent = proj.template ptr<float>(i - dy);
float *vxNext = nproj.template ptr<float>(i - dy);
float *vNext = nproj.template ptr<float>(i);
if (plusToMinusUpdate)
for (int j = dx; j < nproj.cols; ++j)
vNext[j] = -vxNext[j - dx] + vCurrent[j] - vxCurrent[j - dx];
else
for (int j = dx; j < nproj.cols; ++j)
vNext[j] = +vxNext[j - dx] + vCurrent[j] + vxCurrent[j - dx];
}
projections.push_back(nproj);
}
static void getWHSeries(const cv::Mat &src, cv::Mat &dst, const int nProjections, const int psize)
{
CV_Assert(nProjections <= psize*psize && src.type() == CV_32FC1);
CV_Assert( hl(psize) == 1 );
std::vector <cv::Mat> projections;
cv::Mat proj;
cv::boxFilter(src, proj, CV_32F, cv::Size(psize, psize),
cv::Point(-1,-1), true, cv::BORDER_REFLECT);
projections.push_back(proj);
std::vector <cv::Point2i> snake_idx( 1, cv::Point2i(0, 0) );
for (int k = 1, num = 1; k < psize && num <= nProjections; ++k)
{
const cv::Point2i dv[] = { cv::Point2i( !(k&1), (k&1) ),
cv::Point2i( -(k&1), -!(k&1) ) };
snake_idx.push_back(snake_idx[num++ - 1] - dv[1]);
for (int i = 0; i < k && num < nProjections; ++i)
snake_idx.push_back(snake_idx[num++ - 1] + dv[0]);
for (int i = 0; i < k && num < nProjections; ++i)
snake_idx.push_back(snake_idx[num++ - 1] + dv[1]);
}
for (int i = 1; i < nProjections; ++i)
nextProjection(projections, snake_idx[i - 1],
snake_idx[i], psize);
cv::merge(projections, dst);
}
#endif /* __ALGO_HPP__ */ #endif /* __WHS_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