Added Watermarking filter

This commit is contained in:
Paolo Cignoni cignoni 2011-04-06 20:55:37 +00:00
parent 353d60c33f
commit e75c4bd820
6 changed files with 652 additions and 0 deletions

View File

@ -0,0 +1,107 @@
#include <iostream>
#include <stddef.h>
#include <math.h>
template<class T>
inline T SQR(const T a) {return a*a;}
struct Erf {
static const int ncof=28;
static const double cof[28];
inline double erf(double x) {
if (x >=0.) return 1.0 - erfccheb(x);
else return erfccheb(-x) - 1.0;
}
inline double erfc(double x) {
if (x >= 0.) return erfccheb(x);
else return 2.0 - erfccheb(-x);
}
double erfccheb(double z){
int j;
double t,ty,tmp,d=0.,dd=0.;
if (z < 0.) throw("erfccheb requires nonnegative argument");
t = 2./(2.+z);
ty = 4.*t - 2.;
for (j=ncof-1;j>0;j--) {
tmp = d;
d = ty*d - dd + cof[j];
dd = tmp;
}
return t*exp(-z*z + 0.5*(cof[0] + ty*d) - dd);
}
double inverfc(double p) {
double x,err,t,pp;
if (p >= 2.0) return -100.;
if (p <= 0.0) return 100.;
pp = (p < 1.0)? p : 2. - p;
t = sqrt(-2.*log(pp/2.));
x = -0.70711*((2.30753+t*0.27061)/(1.+t*(0.99229+t*0.04481)) - t);
for (int j=0;j<2;j++) {
err = erfc(x) - pp;
x += err/(1.12837916709551257*exp(-SQR(x))-x*err);
}
return (p < 1.0? x : -x);
}
inline double inverf(double p) {return inverfc(1.-p);}
};
const double Erf::cof[28] = {-1.3026537197817094, 6.4196979235649026e-1,
1.9476473204185836e-2,-9.561514786808631e-3,-9.46595344482036e-4,
3.66839497852761e-4,4.2523324806907e-5,-2.0278578112534e-5,
-1.624290004647e-6,1.303655835580e-6,1.5626441722e-8,-8.5238095915e-8,
6.529054439e-9,5.059343495e-9,-9.91364156e-10,-2.27365122e-10,
9.6467911e-11, 2.394038e-12,-6.886027e-12,8.94487e-13, 3.13092e-13,
-1.12708e-13,3.81e-16,7.106e-15,-1.523e-15,-9.4e-17,1.21e-16,-2.8e-17};
double erfcc(const double x)
{
double t,z=fabs(x),ans;
t=2./(2.+z);
ans=t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+
t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+
t*(-0.82215223+t*0.17087277)))))))));
return (x >= 0.0 ? ans : 2.0-ans);
}
struct Normaldist : Erf {
double mu, sig;
Normaldist(double mmu = 0., double ssig = 1.) : mu(mmu), sig(ssig) {
if (sig <= 0.) throw("bad sig in Normaldist");
}
double p(double x) {
return (0.398942280401432678/sig)*exp(-0.5*SQR((x-mu)/sig));
}
double cdf(double x) {
return 0.5*erfc(-0.707106781186547524*(x-mu)/sig);
}
double invcdf(double p) {
if (p <= 0. || p >= 1.) throw("bad p in Normaldist");
return -1.41421356237309505*sig*inverfc(2.*p)+mu;
}
};
struct Lognormaldist : Erf {
double mu, sig;
Lognormaldist(double mmu = 0., double ssig = 1.) : mu(mmu), sig(ssig) {
if (sig <= 0.) throw("bad sig in Lognormaldist");
}
double p(double x) {
if (x < 0.) throw("bad x in Lognormaldist");
if (x == 0.) return 0.;
return (0.398942280401432678/(sig*x))*exp(-0.5*SQR((log(x)-mu)/sig));
}
double cdf(double x) {
if (x < 0.) throw("bad x in Lognormaldist");
if (x == 0.) return 0.;
return 0.5*erfc(-0.707106781186547524*(log(x)-mu)/sig);
}
double invcdf(double p) {
if (p <= 0. || p >= 1.) throw("bad p in Lognormaldist");
return exp(-1.41421356237309505*sig*inverfc(2.*p)+mu);
}
};

View File

@ -0,0 +1,286 @@
/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include "filter_watermark.h"
#include "utilsWatermark.h"
#include <QtScript>
using namespace vcg;
using namespace std;
// Constructor usually performs only two simple tasks of filling the two lists
// - typeList: with all the possible id of the filtering actions
// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly
WatermarkPlugin::WatermarkPlugin()
{
typeList << FP_EMBED_WATERMARK << FP_DECODE_WATERMARK;
foreach(FilterIDType tt , types())
actionList << new QAction(filterName(tt), this);
}
// ST() must return the very short string describing each filtering action
// (this string is used also to define the menu entry)
QString WatermarkPlugin::filterName(FilterIDType filterId) const
{
switch(filterId) {
case FP_EMBED_WATERMARK : return QString("Watermark embedding on 3D points");
case FP_DECODE_WATERMARK : return QString("Watermark decoding on 3D points");
default : assert(0);
}
return QString();
}
// Info() must return the longer string describing each filtering action
// (this string is used in the About plugin dialog)
QString WatermarkPlugin::filterInfo(FilterIDType filterId) const
{
switch(filterId) {
case FP_EMBED_WATERMARK : return QString("Embed a watermark on the model with a given strength depending on a string code. The string code can be a mix of letters, numbers and special characters. A missing alarm probability is guaranteed according to a prefixed false alarm probability.<br> See: <br /> <i>F. Uccheddu, M. Corsini and M. Barni </i><br/> <b>Wavelet-Based Blind Watermarking of 3D Models</b><br/>ACM Multimedia and Security Workshop, 2004, pp. 143-154.<br/><br>");
case FP_DECODE_WATERMARK : return QString("Decode a watermark potentially embedded on the model and depending on a string code. The string code is a mix of letters, numbers and special characters.");
default : assert(0);
}
return QString("Unknown Filter");
}
// The FilterClass describes in which generic class of filters it fits.
// This choice affect the submenu in which each filter will be placed
// More than a single class can be choosen.
WatermarkPlugin::FilterClass WatermarkPlugin::getClass(QAction *a)
{
switch(ID(a))
{
case FP_EMBED_WATERMARK : return MeshFilterInterface::Smoothing;
case FP_DECODE_WATERMARK : return MeshFilterInterface::Smoothing;
default : assert(0);
}
return MeshFilterInterface::Generic;
}
// This function define the needed parameters for each filter. Return true if the filter has some parameters
// it is called every time, so you can set the default value of parameters according to the mesh
// For each parameter you need to define,
// - the name of the parameter,
// - the string shown in the dialog
// - the default value
// - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog)
void WatermarkPlugin::initParameterSet(QAction *action,MeshModel &m, RichParameterSet & parlst)
{
switch(ID(action)) {
case FP_EMBED_WATERMARK :
case FP_DECODE_WATERMARK :
parlst.addParam(new RichFloat("Power_gamma",(float)0.001,"Power value","Power value for the watermark; trade-off between visual quality and robustness. The default is 0.001"));
parlst.addParam(new RichString("String_code","STRING_CODE", "Embedding code","The code to embed into the model. It can be an alphanumeric string"));
break;
default : assert(0);
}
}
// The Real Core Function doing the actual mesh processing.
// Move Vertex of a random quantity
bool WatermarkPlugin::applyFilter(QAction * filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb)
{
MeshModel &m=*md.mm();
const float max_gamma = par.getFloat("Power_gamma");
const QString string_code = par.getString("String_code");
utilsWatermark utilw;
double cellTablesize = 1.0;
int nsTheta = 360.0/cellTablesize;
int nsPhi = 180.0/cellTablesize;
unsigned int seed = utilw.ComputeSeed(string_code);
vector<vector<double> > watermarkTable = utilw.CreateWatermarkTable(seed);
switch(ID(filter))
{
case FP_EMBED_WATERMARK:
{
int indexThetaRef,indexPhiRef;
double DELTAR;
//for(unsigned int i = 0; i< m.cm.vert.size(); i++)
for(CMeshO::VertexIterator vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi)
{
double sphR,sphTheta,sphPhi;
double dx = (vi)->P()[0];
double dy = (vi)->P()[1];
double dz = (vi)->P()[2];
// Passo 1 : Trasformazione in coordinate sferiche della wavelet
utilw.cartesian2sph( vi->P()[0], vi->P()[1],vi->P()[2], sphR, sphTheta, sphPhi );
// Può accadere, basta pensare al vertice (-1.0,0.0,0.0)
if ( (sphTheta+180.0) >= 360.0)
sphTheta -= 360.0;
double dd = PHIEXCLUSION_DEGREE;
if ((sphR > 0.000000000001)&&(sphPhi < 180.0-PHIEXCLUSION_DEGREE)&&(sphPhi > PHIEXCLUSION_DEGREE))
{
// Passo 2 : Mappatura sul Tabella
nsPhi = 180.0/cellTablesize;
nsTheta = 360.0/cellTablesize;
indexThetaRef = (int)utilw.round( (sphTheta+180.0) );
indexPhiRef = (int)utilw.round( (179.0/180.0)*sphPhi );
if (indexThetaRef == nsTheta)
indexThetaRef = 0;
DELTAR = watermarkTable[indexPhiRef][indexThetaRef];
//watermark on vertex module
sphR = sphR + DELTAR*max_gamma;
if (sphR < 0.00000000001)
sphR = 0.00000000001;
utilw.sph2cartesian( sphR,sphTheta,sphPhi, (vi)->P()[0], (vi)->P()[1], (vi)->P()[2] );
double dx = (vi)->P()[0];
double dy = (vi)->P()[1];
double dz = (vi)->P()[2];
int dd=0;
}
}
vcg::tri::UpdateBounding<CMeshO>::Box(m.cm);
} break;
case FP_DECODE_WATERMARK:
{
double Pf = 0.01;
double Pm;
double sphR,sphTheta,sphPhi;
int indexThetaRef,indexPhiRef;
double DELTAR;
vector<double> corr;
vector<double> sphRi;
int n=0;
for(CMeshO::VertexIterator vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi)
{
// Passo 1 : Trasformazione in coordinate sferiche della wavelet
utilw.cartesian2sph( vi->P()[0], vi->P()[1],vi->P()[2], sphR, sphTheta, sphPhi );
// Può accadere, basta pensare al vertice (-1.0,0.0,0.0)
if ( (sphTheta+180.0) >= 360.0)
sphTheta -= 360.0;
if ((sphR > 0.000000000001)&&(sphPhi < 180.0-PHIEXCLUSION_DEGREE)&&(sphPhi > PHIEXCLUSION_DEGREE))
{
nsPhi = 180.0/cellTablesize;
nsTheta = 360.0/cellTablesize;
indexThetaRef = (int)utilw.round( (sphTheta+180.0) );
indexPhiRef = (int)utilw.round( (179.0/180.0)*sphPhi );
if (indexThetaRef == nsTheta)
indexThetaRef = 0;
DELTAR = watermarkTable[indexPhiRef][indexThetaRef];
sphRi.push_back( sphR );
corr.push_back(sphR*DELTAR);
n++;
}
}
double mean_corr = 0;
double var_corr = 0;
// mean
for(int i = 0; i < n; i++)
mean_corr += corr[i];
mean_corr /= (double)n;
// variance
for(int i = 0; i < n; i++)
var_corr+= pow(corr[i] - mean_corr, 2);
var_corr /= (double)n;
//VALORI TEORICI
double muRhoH0,muRhoH1;
double varRhoH0, varRhoH1;
double var_sphR = 0.0;
for (int i=0; i<n; i++)
var_sphR += pow(sphRi[i],2);
var_sphR /= (double)n;
double b = RANGE_MARCHIO;
muRhoH0 = 0.0;
varRhoH0 = (((b*b)/3.0)*var_sphR)/(double)(n-1);
muRhoH1 = max_gamma*((b*b)/3.0)/(double)(n);
varRhoH1 = ((b*b)/3.0)/(double)(n-1)*(var_sphR+pow(max_gamma,2)*b*b/(double)(3*n));
double threshold = utilw.thresholdRo( muRhoH0, varRhoH0, muRhoH1, varRhoH1, Pf, Pm );
if (mean_corr <= threshold){
errorMessage = "The mesh is NOT watermarked"; //
return false;
}
vcg::tri::UpdateBounding<CMeshO>::Box(m.cm);
} break;
default : assert(0);
}
}
QString WatermarkPlugin::filterScriptFunctionName( FilterIDType filterID )
{
switch(filterID) {
case FP_EMBED_WATERMARK : return QString("embedWatermarking");
case FP_DECODE_WATERMARK : return QString("decodeWatermarking");
default : assert(0);
}
return QString();
}
Q_EXPORT_PLUGIN(WatermarkPlugin)

View File

@ -0,0 +1,57 @@
/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef WATERMARKPLUGIN_H
#define WATERMARKPLUGIN_H
#include <QObject>
#include <common/interfaces.h>
class QScriptEngine;
class WatermarkPlugin : public QObject, public MeshFilterInterface
{
Q_OBJECT
Q_INTERFACES(MeshFilterInterface)
public:
enum { FP_EMBED_WATERMARK, FP_DECODE_WATERMARK } ;
WatermarkPlugin();
~WatermarkPlugin(){};
virtual QString pluginName(void) const { return "WatermarkPlugin"; }
virtual QString filterName(FilterIDType filter) const;
virtual QString filterInfo(FilterIDType filter) const;
virtual void initParameterSet(QAction *,MeshModel &/*m*/, RichParameterSet & /*parent*/);
virtual bool applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & /*parent*/, vcg::CallBackPos * cb) ;
virtual int postCondition( QAction* ) const {return MeshModel::MM_VERTCOORD | MeshModel::MM_FACENORMAL | MeshModel::MM_VERTNORMAL;};
virtual FilterClass getClass(QAction *a);
virtual QString filterScriptFunctionName(FilterIDType filterID);
};
#endif

View File

@ -0,0 +1,9 @@
include (../../shared.pri)
HEADERS += filter_watermark.h \
utilsWatermark.h
SOURCES += filter_watermark.cpp \
utilsWatermark.cpp
TARGET = filter_watermark

View File

@ -0,0 +1,142 @@
/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include "utilsWatermark.h"
#include "qstring.h"
#include "filter_watermark.h"
#include "ERF.h"
using namespace std;
// Seed generator for the psedo random sequence in the watermark table
// The seed is obtained by multiplying the ascii codes of each char of the chosen string
unsigned int utilsWatermark::ComputeSeed( QString string_code )
{
unsigned int code = (unsigned int)(string_code[0].digitValue());
for (int i=1; i<string_code.length(); i++)
{
code *= (unsigned int)(string_code[i].digitValue());
}
return code;
}
vector< vector<double> > utilsWatermark::CreateWatermarkTable(unsigned int seed)
{
double cellTablesize = 1.0;
static vcg::math::MarsenneTwisterRNG rnd;
rnd.initialize(seed);
double p = 0; // I valori generati di 'p' vanno da -RANGE_MARCHIO a RANGE_MARCHIO
int nsTheta = 360.0/cellTablesize;
int nsPhi = 180.0/cellTablesize;
vector<vector<double> > watermarkTable;
watermarkTable.resize(nsPhi);
for (int k = 0; k < nsPhi; ++k)
watermarkTable[k].resize(nsTheta);
int i,j;
for (i=0; i<nsPhi; i++)
{
for (j=0; j<nsTheta; j++)
{
p = 2.0*(rnd.generate01())*RANGE_MARCHIO - RANGE_MARCHIO;
watermarkTable[i][j] = p;
}
}
return watermarkTable;
}
// Spheric to Cartesian Coordinates System conversion
void utilsWatermark::sph2cartesian(double R, double theta, double phi, float &x, float &y, float &z)
{
// Conversione Gradi --> Radianti
phi *= DEG_TO_RAD;
theta *= DEG_TO_RAD;
x = float(R*cos(theta)*sin(phi));
z = float(R*sin(theta)*sin(phi));
y = float(R*cos(phi));
}
// Cartesian to Spheric Coordinates System conversion
void utilsWatermark::cartesian2sph(double x, double y, double z, double &R, double &theta, double &phi)
{
R = sqrt( x*x + y*y + z*z );
theta = atan2( z,x );
phi = acos( y / R );
// Conversione Radianti --> Gradi
phi *= RAD_TO_DEG;
theta *= RAD_TO_DEG;
}
// rounding
double utilsWatermark::round(double x)
{
double app = floor(x);
if (x - app >= 0.5)
return (app + 1.0);
else
return app;
}
// evaluate threshold
double utilsWatermark::thresholdRo(double muRhoH0, double varRhoH0,
double muRhoH1, double varRhoH1,
double Pf, double &Pm)
{
Erf erf;
double Y;
double Z;
// Calcolo di T(ro)
/////////////////////////////////////////////////
Y = erf.inverfc( 2.0*Pf );
double Trho = sqrt(2.0*varRhoH0)*Y + muRhoH0;
// Calcolo di Pm
///////////////////////////////////////////////////////
//Z = gsl_sf_erfc( sqrt( ((muRhoH1 - Trho)*(muRhoH1 - Trho))/(2.0*varRhoH1)) );
//Z = erfc( sqrt( ((muRhoH1 - Trho)*(muRhoH1 - Trho))/(2.0*varRhoH1)) );
Z = erf.erfc( sqrt( ((muRhoH1 - Trho)*(muRhoH1 - Trho))/(2.0*varRhoH1)) );
Pm = 0.5*Z;
return Trho;
}

View File

@ -0,0 +1,51 @@
/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef __UTILS_WATERMARKPLUGIN_H
#define __UTILS_WATERMARKPLUGIN_H
#define RANGE_MARCHIO 1.0 // I valori della TabellaMarchio vanno da -RANGE_MARCHIO a +RANGE_MARCHIO (distribuiti UNIFORMEMENTE)
#define RAD_TO_DEG 57.295779513082320876798154814105 // Radianti*RAD_TO_DEG = Gradi
#define DEG_TO_RAD 0.017453292519943295769236907684886 // Gradi*DEG_TO_RAD = Radianti
#define PHIEXCLUSION_DEGREE 8.0 // Esclude dalla marchiature le coordinate polari con phi troppo vicine a 180.0 o a 0.0
#include "qstring.h"
#include "math.h"
#include <vector>
class utilsWatermark
{
public:
utilsWatermark(void){}
~utilsWatermark(void){}
static unsigned int ComputeSeed(QString string_code);
static std::vector< std::vector<double> > CreateWatermarkTable(unsigned int seed);
static void sph2cartesian(double R, double theta, double phi, float &x, float &y, float &z);
static void cartesian2sph(double x, double y, double z, double &R, double &theta, double &phi);
static double round(double x);
static double thresholdRo(double muRhoH0, double varRhoH0,
double muRhoH1, double varRhoH1,
double Pf, double &Pm);
};
#endif