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