Commit b6f37935 authored by Bellaktris's avatar Bellaktris

Walsh-Hadamard transform and clearing of photomontage part

parent 1aad484c
/*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 __ALGO_HPP__
#define __ALGO_HPP__
#include <vector>
#include <algorithm>
#include <cmath>
template <typename Tp> static inline int min_idx(std::vector <Tp> vec)
{
return std::min_element(vec.begin(), vec.end()) - vec.begin();
}
static inline int hamming_length(int x)
{
int res = 0;
while (x)
{
res += x&1;
x >>= 1;
}
return res;
}
#endif /* __ALGO_HPP__ */
\ No newline at end of file
/*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 __ANNF_HPP__
#define __ANNF_HPP__
#include "algo.hpp"
static void plusToMinusUpdate(const cv::Mat &current, cv::Mat &next, const int dx, const int dy)
{
for (int i = 0; i < next.rows; ++i)
for (int j = 0; j < next.cols; ++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);
}
}
static void minusToPlusUpdate(const cv::Mat &current, cv::Mat &next, const int dx, const int dy)
{
for (int i = 0; i < next.rows; ++i)
for (int j = 0; j < next.cols; ++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);
}
}
static void getWHSeries(const cv::Mat &src, cv::Mat &dst, const int nProjections, const int psize = 8)
{
CV_Assert(nProjections <= psize*psize && src.type() == CV_32FC3);
CV_Assert( hamming_length(psize) == 1 );
std::vector <cv::Mat> projections;
cv::Mat proj;
cv::boxFilter(proj, proj, CV_32F, cv::Size(psize, psize),
cv::Point(-1,-1), false, cv::BORDER_REFLECT);
projections.push_back(proj);
std::vector <int> snake_idx(1, 0);
std::vector <int> snake_idy(1, 0);
for (int k = 1, num = 1; k < psize && num <= nProjections; ++k)
{
int dx[] = { (k % 2 == 0) ? +1 : 0, (k % 2 == 0) ? 0 : -1};
int dy[] = { (k % 2 == 0) ? 0 : +1, (k % 2 == 0) ? -1 : 0};
snake_idx.push_back(snake_idx[num - 1] - dx[1]);
snake_idy.push_back(snake_idy[num++ - 1] - dy[1]);
for (int i = 0; i < k && num < nProjections; ++i, ++num)
{
snake_idx.push_back(snake_idx[num - 1] + dx[0]);
snake_idy.push_back(snake_idy[num - 1] + dy[0]);
}
for (int i = 0; i < k && num < nProjections; ++i, ++num)
{
snake_idx.push_back(snake_idx[num - 1] + dx[1]);
snake_idy.push_back(snake_idy[num - 1] + dy[1]);
}
}
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]);
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]);
if (i % 2 == 0)
plusToMinusUpdate(proj, proj, dx, dy);
else
minusToPlusUpdate(proj, proj, dx, dy);
}
cv::merge(projections, dst);
}
#endif /* __ANNF_HPP__ */
\ No newline at end of file
......@@ -57,21 +57,21 @@ namespace cv
struct grayDctDenoisingInvoker : public ParallelLoopBody
{
public:
grayDctDenoisingInvoker(const Mat_<float> &src, std::vector < Mat_<float> > &patches, const double sigma, const int psize);
grayDctDenoisingInvoker(const Mat &src, std::vector <Mat> &patches, const double sigma, const int psize);
~grayDctDenoisingInvoker();
void operator() (const Range &range) const;
private:
const Mat_<float> &src;
std::vector < Mat_<float> > &patches; // image decomposition into sliding patches
const Mat &src;
std::vector <Mat> &patches; // image decomposition into sliding patches
const int psize; // size of block to compute dct
const double sigma; // expected noise standard deviation
const double thresh; // thresholding estimate
};
grayDctDenoisingInvoker::grayDctDenoisingInvoker(const Mat_<float> &src, std::vector < Mat_<float> > &patches,
grayDctDenoisingInvoker::grayDctDenoisingInvoker(const Mat &src, std::vector <Mat> &patches,
const double sigma, const int psize)
: src(src), patches(patches), sigma(sigma), thresh(3*sigma), psize(psize) {}
grayDctDenoisingInvoker::~grayDctDenoisingInvoker(){}
......@@ -85,7 +85,7 @@ namespace cv
Rect patchNum( x, y, psize, psize );
Mat_<float> patch(psize, psize);
Mat patch(psize, psize, CV_32FC1);
src(patchNum).copyTo( patch );
dct(patch, patch);
......@@ -96,44 +96,20 @@ namespace cv
}
}
void grayDctDenoising(const Mat_<float> &src, Mat_<float> &dst, const double sigma, const int psize)
void grayDctDenoising(const Mat &src, Mat &dst, const double sigma, const int psize)
{
CV_Assert( src.channels() == 1 );
//Mat_<float> res( src.size(), 0.0f ),
// num( src.size(), 0.0f );
//
//double threshold = 3*sigma;
//
//for (int i = 0; i <= src.rows - psize; ++i)
// for (int j = 0; j <= src.cols - psize; ++j)
// {
// Mat_<float> patch = src( Rect(j, i, psize, psize) ).clone();
//
// dct(patch, patch);
// float * ptr = (float *) patch.data;
// for (int k = 0; k < psize*psize; ++k)
// if (fabs(ptr[k]) < threshold)
// ptr[k] = 0.0f;
// idct(patch, patch);
//
// res( Rect(j, i, psize, psize) ) += patch;
// num( Rect(j, i, psize, psize) ) += Mat_<float>::ones(psize, psize);
// }
//res /= num;
//
//res.convertTo( dst, src.type() );
CV_Assert( src.type() == CV_MAKE_TYPE(CV_32F, 1) );
int npixels = (src.rows - psize)*(src.cols - psize);
std::vector < Mat_<float> > patches;
std::vector <Mat> patches;
for (int i = 0; i < npixels; ++i)
patches.push_back( Mat_<float>(psize, psize) );
patches.push_back( Mat(psize, psize, CV_32FC1) );
parallel_for_( cv::Range(0, npixels),
grayDctDenoisingInvoker(src, patches, sigma, psize) );
Mat_<float> res( src.size(), 0.0f ),
num( src.size(), 0.0f );
Mat res( src.size(), CV_32FC1, 0.0f ),
num( src.size(), CV_32FC1, 0.0f );
for (int k = 0; k < npixels; ++k)
{
......@@ -141,24 +117,24 @@ namespace cv
int j = k % (src.cols - psize);
res( Rect(j, i, psize, psize) ) += patches[k];
num( Rect(j, i, psize, psize) ) += Mat_<float>::ones(psize, psize);
num( Rect(j, i, psize, psize) ) += Mat::ones(psize, psize, CV_32FC1);
}
res /= num;
res.convertTo( dst, src.type() );
}
void rgbDctDenoising(const Mat_<Vec3f> &src, Mat_<Vec3f> &dst, const double sigma, const int psize)
void rgbDctDenoising(const Mat &src, Mat &dst, const double sigma, const int psize)
{
CV_Assert( src.channels() == 3 );
CV_Assert( src.type() == CV_MAKE_TYPE(CV_32F, 3) );
float M[] = {cvInvSqrt(3), cvInvSqrt(3), cvInvSqrt(3),
cvInvSqrt(2), 0.0f, -cvInvSqrt(2),
cvInvSqrt(6), -2.0f*cvInvSqrt(6), cvInvSqrt(6)};
Mat_<Vec3f>::iterator outIt = dst.begin();
Mat_<Vec3f>::iterator outIt = dst.begin<Vec3f>();
for (Mat_<Vec3f>::const_iterator it = src.begin(); it != src.end(); ++it, ++outIt)
for (Mat_<Vec3f>::const_iterator it = src.begin<Vec3f>(); it != src.end<Vec3f>(); ++it, ++outIt)
{
Vec3f rgb = *it;
*outIt = Vec3f(M[0]*rgb[0] + M[1]*rgb[1] + M[2]*rgb[2],
......@@ -167,7 +143,7 @@ namespace cv
}
/*************************************/
std::vector < Mat_<float> > mv;
std::vector <Mat> mv;
split(dst, mv);
for (int i = 0; i < mv.size(); ++i)
......@@ -176,7 +152,7 @@ namespace cv
merge(mv, dst);
/*************************************/
for (Mat_<Vec3f>::iterator it = dst.begin(); it != dst.end(); ++it)
for (Mat_<Vec3f>::iterator it = dst.begin<Vec3f>(); it != dst.end<Vec3f>(); ++it)
{
Vec3f rgb = *it;
*it = Vec3f(M[0]*rgb[0] + M[3]*rgb[1] + M[6]*rgb[2],
......@@ -202,9 +178,9 @@ namespace cv
src.convertTo(img, xtype);
if ( img.type() == CV_32FC3 )
rgbDctDenoising( Mat_<Vec3f>(img), Mat_<Vec3f>(img), sigma, psize );
rgbDctDenoising( img, img, sigma, psize );
else if ( img.type() == CV_32FC1 )
grayDctDenoising( Mat_<float>(img), Mat_<float>(img), sigma, psize );
grayDctDenoising( img, img, sigma, psize );
else
CV_Assert( false );
......
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-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 __NORM2_HPP__
#define __NORM2_HPP__
template <typename Tp> static inline Tp sqr(Tp x) { return x*x; }
template <typename Tp, int cn> static inline Tp sqr( cv::Vec<Tp, cn> x) { return x.dot(x); }
template <typename Tp> static inline Tp norm2(const Tp &a, const Tp &b) { return sqr(a - b); }
template <typename Tp, int cn> static inline
Tp norm2(const cv::Vec <Tp, cn> &a, const cv::Vec<Tp, cn> &b) { return sqr(a - b); }
#endif /* __NORM2_HPP__ */
\ No newline at end of file
/*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 __PHOTOMONTAGE_HPP__
#define __PHOTOMONTAGE_HPP__
#include <opencv2/core.hpp>
#include "norm2.hpp"
#include "algo.hpp"
#include "annf.hpp"
#include "gcgraph.hpp"
#define GCInfinity 10*1000*1000*1000.0
#define EFFECTIVE_HEIGHT 600
#define EFFECTIVE_WIDTH 800
template <typename Tp> class Photomontage
{
private:
const std::vector <cv::Mat> &images; // vector of images for different labels
const std::vector <cv::Mat> &masks; // vector of definition domains for each image
std::vector <cv::Mat> labelings; // vector of labelings for different expansions
std::vector <double> distances; // vector of max-flow costs for different labeling
const int height;
const int width;
const int type;
const int channels;
const int lsize;
bool multiscale; // if true, Photomontage use coarse-to-fine scheme
double singleExpansion(const cv::Mat &x_i, const int alpha); // single neighbor computing
void gradientDescent(const cv::Mat &x_0, cv::Mat x_n); // gradient descent in alpha-expansion topology
protected:
virtual double dist(const Tp &l1p1, const Tp &l1p2, const Tp &l2p1, const Tp &l2p2);
virtual void setWeights(GCGraph <double> &graph, const cv::Point &pA, const cv::Point &pB, const int lA, const int lB, const int lX);
public:
Photomontage(const std::vector <cv::Mat> &images, const std::vector <cv::Mat> &masks, bool multiscale = true);
virtual ~Photomontage(){};
void assignLabeling(cv::Mat &img);
void assignResImage(cv::Mat &img);
};
template <typename Tp> double Photomontage <Tp>::
dist(const Tp &l1p1, const Tp &l1p2, const Tp &l2p1, const Tp &l2p2)
{
return norm2(l1p1, l2p1) + norm2(l1p2, l2p2);
}
template <typename Tp> void Photomontage <Tp>::
setWeights(GCGraph <double> &graph, const cv::Point &pA, const cv::Point &pB, const int lA, const int lB, const int lX)
{
if (lA == lB)
{
/** Link from A to B **/
double weightAB = dist( images[lA].at<Tp>(pA),
images[lA].at<Tp>(pB),
images[lX].at<Tp>(pA),
images[lX].at<Tp>(pB) );
graph.addEdges(pA.y*width + pA.x, pB.y*width + pB.x, weightAB, weightAB);
}
else
{
int X = graph.addVtx();
/** Link from X to sink **/
double weightXS = dist( images[lA].at<Tp>(pA),
images[lA].at<Tp>(pB),
images[lB].at<Tp>(pA),
images[lB].at<Tp>(pB) );
graph.addTermWeights(X, 0, weightXS);
/** Link from A to X **/
double weightAX = dist( images[lA].at<Tp>(pA),
images[lA].at<Tp>(pB),
images[lX].at<Tp>(pA),
images[lX].at<Tp>(pB) );
graph.addEdges(pA.y*width + pA.x, X, weightAX, weightAX);
/** Link from X to B **/
double weightXB = dist( images[lX].at<Tp>(pA),
images[lX].at<Tp>(pB),
images[lB].at<Tp>(pA),
images[lB].at<Tp>(pB) );
graph.addEdges(X, pB.y*width + pB.x, weightXB, weightXB);
}
}
template <typename Tp> double Photomontage <Tp>::
singleExpansion(const cv::Mat &x_i, const int alpha)
{
int actualEdges = (height - 1)*width + height*(width - 1);
GCGraph <double> graph(actualEdges + height*width, 2*actualEdges);
/** Terminal links **/
for (int i = 0; i < height; ++i)
{
const uchar *maskAlphaRow = masks[alpha].ptr <uchar>(i);
const int *labelRow = (const int *) x_i.ptr <int>(i);
for (int j = 0; j < width; ++j)
graph.addTermWeights( graph.addVtx(),
maskAlphaRow[j] ? 0 : GCInfinity,
masks[ labelRow[j] ].at<uchar>(i, j) ? 0 : GCInfinity );
}
/** Neighbor links **/
for (int i = 0; i < height - 1; ++i)
{
const int *currentRow = (const int *) x_i.ptr <int>(i);
const int *nextRow = (const int *) x_i.ptr <int>(i + 1);
for (int j = 0; j < width - 1; ++j)
{
setWeights( graph, cv::Point(i, j), cv::Point(i, j + 1), currentRow[j], currentRow[j + 1], alpha );
setWeights( graph, cv::Point(i, j), cv::Point(i + 1, j), currentRow[j], nextRow[j], alpha );
}
setWeights( graph, cv::Point(i, width - 1), cv::Point(i + 1, width - 1),
currentRow[width - 1], nextRow[width - 1], alpha );
}
const int *currentRow = (const int *) x_i.ptr <int>(height - 1);
for (int i = 0; i < width - 1; ++i)
setWeights( graph, cv::Point(height - 1, i), cv::Point(height - 1, i + 1),
currentRow[i], currentRow[i + 1], alpha );
/** Max-flow computation **/
double result = graph.maxFlow();
/** Writing results **/
labelings[alpha].create( height, width, CV_32SC1 );
for (int i = 0; i < height; ++i)
{
const int *inRow = (const int *) x_i.ptr <int>(i);
int *outRow = (int *) labelings[alpha].ptr <int>(i);
for (int j = 0; j < width; ++j)
outRow[j] = graph.inSourceSegment(i*width + j) ? inRow[j] : alpha;
}
return result;
}
template <typename Tp> void Photomontage <Tp>::
gradientDescent(const cv::Mat &x_0, cv::Mat x_n)
{
double optValue = std::numeric_limits<double>::max();
x_0.copyTo(x_n);
for (int num = -1; /**/; num = -1)
{
for (int i = 0; i < lsize; ++i)
distances[i] = singleExpansion(x_n, i);
int minIndex = min_idx(distances);
double minValue = distances[minIndex];
if (minValue < 0.98*optValue)
optValue = distances[num = minIndex];
if (num == -1)
break;
labelings[num].copyTo(x_n);
}
}
template <typename Tp> void Photomontage <Tp>::
assignLabeling(cv::Mat &img)
{
if (multiscale == 0 || (height < EFFECTIVE_HEIGHT && width < EFFECTIVE_WIDTH))
{
img.create(height, width, CV_32SC1);
img.setTo(0);
gradientDescent(img, img);
}
else
{
int l = std::min( cvRound(height/600.0), cvRound(width/800.0) );
img.create( cv::Size(width/l, height/l), CV_32SC1 );
...
img.setTo(0);
gradientDescent(img, img);
resize(img, img, cv::Size(height, width), 0.0, 0.0, cv::INTER_NEAREST);
...
}
}
template <typename Tp> void Photomontage <Tp>::
assignResImage(cv::Mat &img)
{
cv::Mat optimalLabeling;
assignLabeling(optimalLabeling);
img.create( height, width, type );
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
img.at<Tp>(i, j) = images[ optimalLabeling.at<int>(i, j) ].at<Tp>(i, j);
}
template <typename Tp> Photomontage <Tp>::
Photomontage(const std::vector <cv::Mat> &images, const std::vector <cv::Mat> &masks, const bool multiscale)
:
images(images), masks(masks), multiscale(multiscale), height(images[0].rows), width(images[0].cols), type(images[0].type()),
channels(images[0].channels()), lsize(images.size()), labelings(images.size()), distances(images.size())
{
CV_Assert(images[0].depth() != CV_8U && masks[0].depth() == CV_8U);
}
#endif /* __PHOTOMONTAGE_HPP__ */
\ No newline at end of file
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