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:
const int gradNum) const = 0;
};
CV_EXPORTS_W Ptr<RFFeatureGetter> createRFFeatureGetter(void);
CV_EXPORTS_W Ptr<RFFeatureGetter> createRFFeatureGetter();
......
......@@ -280,7 +280,7 @@ public:
* \param outNum : __rf.options.numberOfOutputChannels
* \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
{
cv::Mat luvImg = rgb2luv(src);
......@@ -320,7 +320,7 @@ protected:
String name;
};
Ptr<RFFeatureGetter> createRFFeatureGetter(void)
Ptr<RFFeatureGetter> createRFFeatureGetter()
{
return makePtr<RFFeatureGetterImpl>();
}
......
......@@ -40,87 +40,234 @@
#ifndef __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 = 0; i < next.rows; ++i)
for (int j = 0; j < next.cols; ++j)
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
{
int y = cv::borderInterpolate(i - dy, next.rows, cv::BORDER_CONSTANT);
int x = cv::borderInterpolate(j - dx, next.cols, cv::BORDER_CONSTANT);
cv::Vec <Tp, cn> u = main->data[main->idx[x]];
cv::Vec <Tp, cn> v = main->data[main->idx[y]];
next.at<float>(i, j) = -next.at<float>(y, x)
+ current.at<float>(i, j) - current.at<float>(y, x);
return u[dimIdx] < v[dimIdx];
}
}
static void minusToPlusUpdate(const cv::Mat &current, cv::Mat &next, const int dx, const int dy)
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)
for (int j = 0; j < next.cols; ++j)
cv::Vec<Tp, cn> maxValue = data[ idx[_left] ],
minValue = data[ idx[_left] ];
for (int i = _left + 1; i < _right; i += cn)
for (int j = 0; j < cn; ++j)
{
int y = cv::borderInterpolate(i - dy, next.rows, cv::BORDER_CONSTANT);
int x = cv::borderInterpolate(j - dx, next.cols, cv::BORDER_CONSTANT);
next.at<float>(i, j) = next.at<float>(y, x)
- current.at<float>(i, j) + current.at<float>(y, x);
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);
}
static void getWHSeries(const cv::Mat &src, cv::Mat &dst, const int nProjections, const int psize = 8)
template <typename Tp, int cn> KDTree <Tp, cn>::
KDTree(const cv::Mat &img, const int _leafNumber)
: leafNumber(_leafNumber)
///////////////////////////////////////////////////
{
CV_Assert(nProjections <= psize*psize && src.type() == CV_32FC3);
CV_Assert( hamming_length(psize) == 1 );
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 _left = left.top(); left.pop();
int _right = right.top(); right.pop();
std::vector <cv::Mat> projections;
if ( _right - _left <= leafNumber)
{
for (int i = _left; i < _right; ++i)
{
nodes[idx[i]].x = _left;
nodes[idx[i]].y = _right;
}
continue;
}
cv::Mat proj;
cv::boxFilter(proj, proj, CV_32F, cv::Size(psize, psize),
cv::Point(-1,-1), false, cv::BORDER_REFLECT);
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) ) /**/);
projections.push_back(proj);
left.push(_left); right.push(nth + 1);
left.push(nth + 1); right.push(_right);
}
}
std::vector <int> snake_idx(1, 0);
std::vector <int> snake_idy(1, 0);
/************************** ANNF search **************************/
for (int k = 1, num = 1; k < psize && num <= nProjections; ++k)
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 k = I.x; k < I.y; ++k)
{
const int dx[] = { (k % 2 == 0) ? +1 : 0, (k % 2 == 0) ? 0 : -1};
const int dy[] = { (k % 2 == 0) ? 0 : +1, (k % 2 == 0) ? -1 : 0};
int newIdx = kdTree.idx[k];
snake_idx.push_back(snake_idx[num - 1] - dx[1]);
snake_idy.push_back(snake_idy[num++ - 1] - dy[1]);
if (newIdx%width == width - 1)
continue;
for (int i = 0; i < k && num < nProjections; ++i, ++num)
if (newIdx/width == height - 1)
continue;
int dx = currentIdx%width - newIdx%width;
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)
{
snake_idx.push_back(snake_idx[num - 1] + dx[0]);
snake_idy.push_back(snake_idy[num - 1] + dy[0]);
dist = ndist;
bestIdx = newIdx;
}
}
}
static void getANNF(const cv::Mat &img, std::vector <cv::Matx33f> &transforms,
const int nTransform, const int psize)
{
/** Walsh-Hadamard Transformation **/
for (int i = 0; i < k && num < nProjections; ++i, ++num)
std::vector <cv::Mat> channels;
cv::split(img, channels);
const int np[] = {16, 4, 4};
for (int i = 0; i < img.channels(); ++i)
getWHSeries(channels[i], channels[i], np[i], psize);
cv::Mat whs; // Walsh-Hadamard series
cv::merge(channels, whs);
KDTree <float, 24> kdTree(whs);
std::vector <int> annf( whs.total(), 0 );
/** Propagation-assisted kd-tree search **/
for (int i = 0; i < whs.rows; ++i)
for (int j = 0; j < whs.cols; ++j)
{
snake_idx.push_back(snake_idx[num - 1] + dx[1]);
snake_idy.push_back(snake_idy[num - 1] + dy[1]);
double dist = std::numeric_limits <double>::max();
int current = i*whs.cols + j;
cv::Point2i I = kdTree.nodes[i*whs.cols + j];
updateDist(kdTree, I, whs.rows, whs.cols, current, annf[i*whs.cols + j], dist);
if (i != 0)
{
int idx = annf[(i - 1)*whs.cols + j] + whs.cols;
cv::Point2i I = kdTree.nodes[idx];
updateDist(kdTree, I, whs.rows, whs.cols, current, annf[i*whs.cols + j], dist);
}
if (j != 0)
{
int idx = annf[i*whs.cols + (j - 1)] + 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)
{
int dx = (snake_idx[i] - snake_idx[i - 1]);
int dy = (snake_idy[i] - snake_idy[i - 1]);
/** Local maxima extraction **/
cv::Mat_<double> annfHist(2*whs.rows, 2*whs.cols, 0.0),
_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);
cv::GaussianBlur( annfHist, annfHist,
cv::Size(9, 9), 1.41, 0.0, cv::BORDER_CONSTANT);
cv::dilate(annfHist, _annfHist,
cv::Matx<uchar, 9, 9>::ones());
dx <<= hamming_length(psize - 1) - hamming_length(snake_idx[i - 1] ^ snake_idx[i]);
dy <<= hamming_length(psize - 1) - hamming_length(snake_idy[i - 1] ^ snake_idy[i]);
std::vector < std::pair<double, int> > amount;
std::vector <cv::Point2i> shiftM;
if (i % 2 == 0)
plusToMinusUpdate(proj, proj, dx, dy);
else
minusToPlusUpdate(proj, proj, dx, dy);
for (int i = 0, t = 0; i < annfHist.rows; ++i)
{
double *pAnnfHist = annfHist.template ptr<double>(i);
double *_pAnnfHist = _annfHist.template ptr<double>(i);
for (int j = 0; j < annfHist.cols; ++j)
if ( pAnnfHist[j] != 0 && pAnnfHist[j] == _pAnnfHist[j] )
{
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__ */
......@@ -38,14 +38,18 @@
//M*/
#include <vector>
#include <stack>
#include <limits>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <time.h>
#include <functional>
#include "opencv2/xphoto.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/core.hpp"
#include "opencv2/core/core_c.h"
......@@ -67,18 +71,17 @@ namespace cv
const int nTransform = 60; // number of dominant transforms for stitching
const int psize = 8; // single ANNF patch size
/** ANNF computation **/
srand( unsigned(time(NULL)) );
cv::Mat img;
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)
{
float dx = float( rand()%src.cols - src.cols/2 );
float dy = float( rand()%src.rows - src.rows/2 );
transforms.push_back( Matx33f( 1, 0, dx,
0, 1, dy,
0, 0, 1) );
}
/** ANNF computation **/
std::vector <Matx33f> transforms( nTransform );
xphotoInternal::getANNF(img, transforms,
nTransform, psize);
/** Warping **/
std::vector <Mat> images( nTransform + 1 ); // source image transformed with transforms
......@@ -87,7 +90,7 @@ namespace cv
Mat_<uchar> invMask = 255 - mask;
dilate(invMask, invMask, Mat(), Point(-1,-1), 2);
src.convertTo( images[0], CV_32F );
img.copyTo( images[0] );
mask.copyTo( masks[0] );
for (int i = 0; i < nTransform; ++i)
......@@ -104,7 +107,10 @@ namespace cv
Mat photomontageResult;
xphotoInternal::Photomontage < cv::Vec <float, cn> >( images, masks )
.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>
......@@ -137,66 +143,66 @@ namespace cv
switch ( src.type() )
{
case CV_8UC1:
inpaint <uchar, 1>( src, mask, dst, algorithmType );
break;
case CV_8UC2:
inpaint <uchar, 2>( src, mask, dst, algorithmType );
break;
//case CV_8UC1:
// inpaint <uchar, 1>( src, mask, dst, algorithmType );
// break;
//case CV_8UC2:
// inpaint <uchar, 2>( src, mask, dst, algorithmType );
// break;
case CV_8UC3:
inpaint <uchar, 3>( src, mask, dst, algorithmType );
break;
case CV_8UC4:
inpaint <uchar, 4>( src, mask, dst, algorithmType );
break;
case CV_16SC1:
inpaint <short, 1>( src, mask, dst, algorithmType );
break;
case CV_16SC2:
inpaint <short, 2>( src, mask, dst, algorithmType );
break;
//case CV_8UC4:
// inpaint <uchar, 4>( src, mask, dst, algorithmType );
// break;
//case CV_16SC1:
// inpaint <short, 1>( src, mask, dst, algorithmType );
// break;
//case CV_16SC2:
// inpaint <short, 2>( src, mask, dst, algorithmType );
// break;
case CV_16SC3:
inpaint <short, 3>( src, mask, dst, algorithmType );
break;
case CV_16SC4:
inpaint <short, 4>( src, mask, dst, algorithmType );
break;
case CV_32SC1:
inpaint <int, 1>( src, mask, dst, algorithmType );
break;
case CV_32SC2:
inpaint <int, 2>( src, mask, dst, algorithmType );
break;
//case CV_16SC4:
// inpaint <short, 4>( src, mask, dst, algorithmType );
// break;
//case CV_32SC1:
// inpaint <int, 1>( src, mask, dst, algorithmType );
// break;
//case CV_32SC2:
// inpaint <int, 2>( src, mask, dst, algorithmType );
// break;
case CV_32SC3:
inpaint <int, 3>( src, mask, dst, algorithmType );
break;
case CV_32SC4:
inpaint <int, 4>( src, mask, dst, algorithmType );
break;
case CV_32FC1:
inpaint <float, 1>( src, mask, dst, algorithmType );
break;
case CV_32FC2:
inpaint <float, 2>( src, mask, dst, algorithmType );
break;
//case CV_32SC4:
// inpaint <int, 4>( src, mask, dst, algorithmType );
// break;
//case CV_32FC1:
// inpaint <float, 1>( src, mask, dst, algorithmType );
// break;
//case CV_32FC2:
// inpaint <float, 2>( src, mask, dst, algorithmType );
// break;
case CV_32FC3:
inpaint <float, 3>( src, mask, dst, algorithmType );
break;
case CV_32FC4:
inpaint <float, 4>( src, mask, dst, algorithmType );
break;
case CV_64FC1:
inpaint <double, 1>( src, mask, dst, algorithmType );
break;
case CV_64FC2:
inpaint <double, 2>( src, mask, dst, algorithmType );
break;
//case CV_32FC4:
// inpaint <float, 4>( src, mask, dst, algorithmType );
// break;
//case CV_64FC1:
// inpaint <double, 1>( src, mask, dst, algorithmType );
// break;
//case CV_64FC2:
// inpaint <double, 2>( src, mask, dst, algorithmType );
// break;
case CV_64FC3:
inpaint <double, 3>( src, mask, dst, algorithmType );
break;
case CV_64FC4:
inpaint <double, 4>( src, mask, dst, algorithmType );
break;
//case CV_64FC4:
// inpaint <double, 4>( src, mask, dst, algorithmType );
// break;
default:
CV_Error_( CV_StsNotImplemented,
("Unsupported source image format (=%d)",
......
......@@ -42,11 +42,17 @@
#include "norm2.hpp"
#include "algo.hpp"
#include "gcgraph.hpp"
#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
{
......
......@@ -37,16 +37,10 @@
//
//M*/
#ifndef __ALGO_HPP__
#define __ALGO_HPP__
#ifndef __WHS_HPP__
#define __WHS_HPP__
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)
static inline int hl(int x)
{
int res = 0;
while (x)
......@@ -57,5 +51,69 @@ static inline int hamming_length(int x)
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