1 /****************************************************************************
2 * MeshLab o o *
3 * A versatile mesh processing toolbox o o *
4 * _ O _ *
5 * Copyright(C) 2005 \/)\/ *
6 * Visual Computing Lab /\/| *
7 * ISTI - Italian National Research Council | *
8 * \ *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20 * for more details. *
21 * *
22 ****************************************************************************/
23
24 #include "filter_watermark.h"
25 #include "utilsWatermark.h"
26 #include <QtScript>
27
28
29 using namespace vcg;
30 using namespace std;
31
32
33 // Constructor usually performs only two simple tasks of filling the two lists
34 // - typeList: with all the possible id of the filtering actions
35 // - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly
36
WatermarkPlugin()37 WatermarkPlugin::WatermarkPlugin()
38 {
39 typeList << FP_EMBED_WATERMARK << FP_DECODE_WATERMARK;
40
41 foreach(FilterIDType tt , types())
42 actionList << new QAction(filterName(tt), this);
43 }
44
45 // ST() must return the very short string describing each filtering action
46 // (this string is used also to define the menu entry)
filterName(FilterIDType filterId) const47 QString WatermarkPlugin::filterName(FilterIDType filterId) const
48 {
49 switch(filterId) {
50 case FP_EMBED_WATERMARK : return QString("Watermark embedding on 3D points");
51 case FP_DECODE_WATERMARK : return QString("Watermark decoding on 3D points");
52 default : assert(0);
53 }
54 return QString();
55 }
56
57 // Info() must return the longer string describing each filtering action
58 // (this string is used in the About plugin dialog)
filterInfo(FilterIDType filterId) const59 QString WatermarkPlugin::filterInfo(FilterIDType filterId) const
60 {
61 switch(filterId) {
62 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>");
63 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.");
64 default : assert(0);
65 }
66 return QString("Unknown Filter");
67 }
68
69 // The FilterClass describes in which generic class of filters it fits.
70 // This choice affect the submenu in which each filter will be placed
71 // More than a single class can be choosen.
getClass(QAction * a)72 WatermarkPlugin::FilterClass WatermarkPlugin::getClass(QAction *a)
73 {
74 switch(ID(a))
75 {
76 case FP_EMBED_WATERMARK : return MeshFilterInterface::Smoothing;
77 case FP_DECODE_WATERMARK : return MeshFilterInterface::Smoothing;
78 default : assert(0);
79 }
80 return MeshFilterInterface::Generic;
81 }
82
83 // This function define the needed parameters for each filter. Return true if the filter has some parameters
84 // it is called every time, so you can set the default value of parameters according to the mesh
85 // For each parameter you need to define,
86 // - the name of the parameter,
87 // - the string shown in the dialog
88 // - the default value
89 // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog)
initParameterSet(QAction * action,MeshModel & m,RichParameterSet & parlst)90 void WatermarkPlugin::initParameterSet(QAction *action,MeshModel &m, RichParameterSet & parlst)
91 {
92 switch(ID(action)) {
93 case FP_EMBED_WATERMARK :
94 case FP_DECODE_WATERMARK :
95 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"));
96 parlst.addParam(new RichString("String_code","STRING_CODE", "Embedding code","The code to embed into the model. It can be an alphanumeric string"));
97 break;
98 default : assert(0);
99 }
100 }
101
102
103
104
105 // The Real Core Function doing the actual mesh processing.
106 // Move Vertex of a random quantity
applyFilter(QAction * filter,MeshDocument & md,RichParameterSet & par,vcg::CallBackPos * cb)107 bool WatermarkPlugin::applyFilter(QAction * filter, MeshDocument &md, RichParameterSet & par, vcg::CallBackPos *cb)
108 {
109
110 MeshModel &m=*md.mm();
111 const float max_gamma = par.getFloat("Power_gamma");
112 const QString string_code = par.getString("String_code");
113
114 utilsWatermark utilw;
115 double cellTablesize = 1.0;
116 int nsTheta = 360.0/cellTablesize;
117 int nsPhi = 180.0/cellTablesize;
118
119 unsigned int seed = utilw.ComputeSeed(string_code);
120
121 vector<vector<double> > watermarkTable = utilw.CreateWatermarkTable(seed);
122
123 switch(ID(filter))
124 {
125 case FP_EMBED_WATERMARK:
126 {
127 int indexThetaRef,indexPhiRef;
128
129 double DELTAR;
130
131 //for(unsigned int i = 0; i< m.cm.vert.size(); i++)
132 for(CMeshO::VertexIterator vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi)
133 {
134 double sphR,sphTheta,sphPhi;
135
136 double dx = (vi)->P()[0];
137 double dy = (vi)->P()[1];
138 double dz = (vi)->P()[2];
139
140 // Passo 1 : Trasformazione in coordinate sferiche della wavelet
141 utilw.cartesian2sph( vi->P()[0], vi->P()[1],vi->P()[2], sphR, sphTheta, sphPhi );
142
143 // Pu� accadere, basta pensare al vertice (-1.0,0.0,0.0)
144 if ( (sphTheta+180.0) >= 360.0)
145 sphTheta -= 360.0;
146
147 double dd = PHIEXCLUSION_DEGREE;
148 if ((sphR > 0.000000000001)&&(sphPhi < 180.0-PHIEXCLUSION_DEGREE)&&(sphPhi > PHIEXCLUSION_DEGREE))
149 {
150 // Passo 2 : Mappatura sul Tabella
151
152 nsPhi = 180.0/cellTablesize;
153 nsTheta = 360.0/cellTablesize;
154
155 indexThetaRef = (int)utilw.round( (sphTheta+180.0) );
156 indexPhiRef = (int)utilw.round( (179.0/180.0)*sphPhi );
157
158 if (indexThetaRef == nsTheta)
159 indexThetaRef = 0;
160
161 DELTAR = watermarkTable[indexPhiRef][indexThetaRef];
162
163 //watermark on vertex module
164 sphR = sphR + DELTAR*max_gamma;
165
166 if (sphR < 0.00000000001)
167 sphR = 0.00000000001;
168
169 utilw.sph2cartesian( sphR,sphTheta,sphPhi, (vi)->P()[0], (vi)->P()[1], (vi)->P()[2] );
170 double dx = (vi)->P()[0];
171 double dy = (vi)->P()[1];
172 double dz = (vi)->P()[2];
173
174 int dd=0;
175 }
176
177 }
178 vcg::tri::UpdateBounding<CMeshO>::Box(m.cm);
179
180
181 } break;
182 case FP_DECODE_WATERMARK:
183 {
184 double Pf = 0.01;
185 double Pm;
186
187 double sphR,sphTheta,sphPhi;
188
189 int indexThetaRef,indexPhiRef;
190
191 double DELTAR;
192
193 vector<double> corr;
194 vector<double> sphRi;
195
196 int n=0;
197
198 for(CMeshO::VertexIterator vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi)
199 {
200
201 // Passo 1 : Trasformazione in coordinate sferiche della wavelet
202 utilw.cartesian2sph( vi->P()[0], vi->P()[1],vi->P()[2], sphR, sphTheta, sphPhi );
203
204 // Pu� accadere, basta pensare al vertice (-1.0,0.0,0.0)
205 if ( (sphTheta+180.0) >= 360.0)
206 sphTheta -= 360.0;
207
208 if ((sphR > 0.000000000001)&&(sphPhi < 180.0-PHIEXCLUSION_DEGREE)&&(sphPhi > PHIEXCLUSION_DEGREE))
209 {
210 nsPhi = 180.0/cellTablesize;
211 nsTheta = 360.0/cellTablesize;
212
213 indexThetaRef = (int)utilw.round( (sphTheta+180.0) );
214 indexPhiRef = (int)utilw.round( (179.0/180.0)*sphPhi );
215
216 if (indexThetaRef == nsTheta)
217 indexThetaRef = 0;
218
219 DELTAR = watermarkTable[indexPhiRef][indexThetaRef];
220
221 sphRi.push_back( sphR );
222 corr.push_back(sphR*DELTAR);
223 n++;
224
225 }
226 }
227
228 double mean_corr = 0;
229 double var_corr = 0;
230
231 // mean
232 for(int i = 0; i < n; i++)
233 mean_corr += corr[i];
234 mean_corr /= (double)n;
235
236
237 // variance
238 for(int i = 0; i < n; i++)
239 var_corr+= pow(corr[i] - mean_corr, 2);
240 var_corr /= (double)n;
241
242
243 //VALORI TEORICI
244 double muRhoH0,muRhoH1;
245 double varRhoH0, varRhoH1;
246 double var_sphR = 0.0;
247 for (int i=0; i<n; i++)
248 var_sphR += pow(sphRi[i],2);
249 var_sphR /= (double)n;
250
251 double b = RANGE_MARCHIO;
252
253 muRhoH0 = 0.0;
254 varRhoH0 = (((b*b)/3.0)*var_sphR)/(double)(n-1);
255
256 muRhoH1 = max_gamma*((b*b)/3.0)/(double)(n);
257 varRhoH1 = ((b*b)/3.0)/(double)(n-1)*(var_sphR+pow(max_gamma,2)*b*b/(double)(3*n));
258
259 double threshold = utilw.thresholdRo( muRhoH0, varRhoH0, muRhoH1, varRhoH1, Pf, Pm );
260
261 if (mean_corr <= threshold){
262 errorMessage = "The mesh is NOT watermarked"; //
263 return false;
264 }
265 vcg::tri::UpdateBounding<CMeshO>::Box(m.cm);
266 } break;
267 default : assert(0);
268 }
269
270
271 }
272
273
274
275
filterScriptFunctionName(FilterIDType filterID)276 QString WatermarkPlugin::filterScriptFunctionName( FilterIDType filterID )
277 {
278 switch(filterID) {
279 case FP_EMBED_WATERMARK : return QString("embedWatermarking");
280 case FP_DECODE_WATERMARK : return QString("decodeWatermarking");
281 default : assert(0);
282 }
283 return QString();
284 }
285
286 Q_EXPORT_PLUGIN(WatermarkPlugin)
287