Xmipp  v3.23.11-Nereus
angular_distance.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar Sanchez Sorzano coss@cnb.csic.es (2002)
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
26 #include "angular_distance.h"
27 
28 #include <core/args.h>
29 #include <core/histogram.h>
30 #include "core/geometry.h"
31 #include <core/metadata_db.h>
32 
33 #include <cassert>
34 
35 // Read arguments ==========================================================
37 {
38  fn_ang1 = getParam("--ang1");
39  fn_ang2 = getParam("--ang2");
40  fn_out = getParam("--oroot");
41  fn_sym = getParam("--sym");
42  check_mirrors = checkParam("--check_mirrors");
43  object_rotation = checkParam("--object_rotation");
44  compute_weights = checkParam("--compute_weights");
45  if (compute_weights)
46  {
47  minSigma = getDoubleParam("--compute_weights");
48  idLabel = getParam("--compute_weights",1);
49  minSigmaD = getDoubleParam("--compute_weights",2);
50  }
51  set = getIntParam("--set");
52  ang = getIntParam("--ang");
53  compute_average_angle = checkParam("--compute_average_angle");
54  compute_average_shift = checkParam("--compute_average_shift");
55 }
56 
57 // Show ====================================================================
59 {
60  std::cout
61  << "Angular docfile 1 : " << fn_ang1 << std::endl
62  << "Angular docfile 2 : " << fn_ang2 << std::endl
63  << "Angular output : " << fn_out << std::endl
64  << "Symmetry file : " << fn_sym << std::endl
65  << "Check mirrors : " << check_mirrors << std::endl
66  << "Object rotation : " << object_rotation<<std::endl
67  << "Compute weights : " << compute_weights << std::endl
68  << "Min sigma : " << minSigma << std::endl
69  << "Min sigmaD : " << minSigmaD << std::endl
70  << "IdLabel : " << idLabel << std::endl
71  << "Set : " << set << std::endl
72  << "Ang : " << ang << std::endl
73  << "Compute average angle: " << compute_average_angle << std::endl
74  << "Compute average shift: " << compute_average_shift << std::endl
75  ;
76 }
77 
78 // usage ===================================================================
80 {
81  addUsageLine("Computes the angular distance between two angle files. The angular distance ");
82  addUsageLine("is defined as the average angular distance between the 3 vectors of the ");
83  addUsageLine("coordinate system defined by the Euler angles (taking into account any ");
84  addUsageLine("possible symmetry). ");
85  addParamsLine(" --ang1 <Metadata1> : Angular document file 1");
86  addParamsLine(" --ang2 <Metadata2> : Angular document file 2");
87  addParamsLine(" [--oroot <rootname=\"\">] : Output rootname");
88  addParamsLine(" : rootname.xmd Angular comparison;");
89  addParamsLine(" : rootname_vec_diff_hist.txt Histogram of the differences in vector directions;");
90  addParamsLine(" : rootname_shift_diff_hist.txt Histogram of the differences in shifts;");
91  addParamsLine(" :+ rootname_rot_diff_hist.txt (verbose>=2) Histogram of the differences in rot;");
92  addParamsLine(" :+ rootname_tilt_diff_hist.txt (verbose>=2) Histogram of the differences in tilt;");
93  addParamsLine(" :+ rootname_psi_diff_hist.txt (verbose>=2) Histogram of the differences in psi;");
94  addParamsLine(" :+ rootname_X_diff_hist.txt (verbose>=2) Histogram of the differences in shiftX;");
95  addParamsLine(" :+ rootname_Y_diff_hist.txt (verbose>=2) Histogram of the differences in shiftY;");
96  addParamsLine(" [--sym <symmetry=\"\">] : Symmetry file if any");
97  addParamsLine(" :+The definition of the symmetry is described at [[transform_symmetrize_v3][transform_symmetrize]]");
98  addParamsLine(" [--check_mirrors] : Check if mirrored projections give better results");
99  addParamsLine(" [--object_rotation] : Use object rotations rather than projection directions");
100  addParamsLine(" : fit (Spider, APMQ)");
101  addParamsLine(" [--compute_weights <minSigma=1> <idLabel=particleId> <minSigmaD=-1>] : If this flag is given, images in ang2 are given a weight according to their ");
102  addParamsLine(" : distance to the same image in ang1. The ang2 file is rewritten.");
103  addParamsLine(" : Ang1 and ang2 are supposed to have a label called itemId");
104  addParamsLine(" : The output is written to oroot+_weights.xmd");
105  addParamsLine(" : Min sigma is the minimum angular standard deviation, by default, 1 degree");
106  addParamsLine(" : Min sigmaD is the minimum shift standard deviation, set to -1 for not using shifts for weighting");
107  addParamsLine(" [--set <set=1>] : Set of distance to compute (angular_diff0 and jumper_weight0, angular_diff and jumper_weight,");
108  addParamsLine(" : or angular_diff2 and jumper_weight2)");
109  addParamsLine(" [--ang <ang=1>] : The angle set to be written in the first position. Note that ang2 may be modified");
110  addParamsLine(" : so that for the given symmetry is the closest to ang1. Therefore using ang=2 is useful ");
111  addParamsLine(" : to obtain get ang2 close to ang1");
112  addParamsLine(" [--compute_average_angle] : Average the angles defined in ang1 and ang2");
113  addParamsLine(" [--compute_average_shift] : Average the shifts defined in ang1 and ang2");
114 }
115 
116 // Produce side information ================================================
118 {
119  if (fn_sym != "")
121 
122  // Check that both docfiles are of the same length
123  if (fn_ang1!="" && fn_ang2!="")
124  {
125  DF1.read(fn_ang1);
126  DF2.read(fn_ang2);
127  if (DF1.size() != DF2.size() && !compute_weights)
129  "Angular_distance: Input Docfiles with different number of entries");
130  }
131 }
132 
133 //#define DEBUG
134 // Compute distance --------------------------------------------------------
136 {
138  if (compute_weights)
139  {
140  computeWeights();
141  return;
142  }
143 
144  MetaDataVec DF_out;
145  double angular_distance=0;
146  double shift_distance=0;
147 
148  MultidimArray<double> rot_diff, tilt_diff, psi_diff, vec_diff,
149  X_diff, Y_diff, shift_diff;
150  rot_diff.resize(DF1.size());
151  tilt_diff.resize(rot_diff);
152  psi_diff.resize(rot_diff);
153  vec_diff.resize(rot_diff);
154  X_diff.resize(rot_diff);
155  Y_diff.resize(rot_diff);
156  shift_diff.resize(rot_diff);
157 
158  // Build output comment
160 
161  size_t id;
162  FileName fnImg;
163  std::vector<double> output;
164  output.resize(17,0);
165  bool fillOutput=fn_out!="";
166 
167  auto iter1(DF1.ids().begin());
168  auto iter2(DF2.ids().begin());
169  const auto s = std::min(DF1.size(), DF2.size());
170  int i;
171  for (i = 0; i < s; ++i, ++iter1, ++iter2)
172  {
173  // Read input data
174  size_t itemId;
175  double rot1, tilt1, psi1;
176  double rot2, tilt2, psi2;
177  double rot2p, tilt2p, psi2p;
178  double distp;
179  double X1, X2, Y1, Y2;
180  DF1.getValue(MDL_ITEM_ID,itemId, *iter1);
181  DF1.getValue(MDL_IMAGE,fnImg, *iter1);
182 
183  DF1.getValue(MDL_ANGLE_ROT,rot1, *iter1);
184  DF1.getValue(MDL_ANGLE_TILT,tilt1, *iter1);
185  DF1.getValue(MDL_ANGLE_PSI,psi1, *iter1);
186  DF1.getValue(MDL_SHIFT_X,X1, *iter1);
187  DF1.getValue(MDL_SHIFT_Y,Y1, *iter1);
188 
189  DF2.getValue(MDL_ANGLE_ROT,rot2, *iter2);
190  DF2.getValue(MDL_ANGLE_TILT,tilt2, *iter2);
191  DF2.getValue(MDL_ANGLE_PSI,psi2, *iter2);
192  DF2.getValue(MDL_SHIFT_X,X2, *iter2);
193  DF2.getValue(MDL_SHIFT_Y,Y2, *iter2);
194 
195  // Bring both angles to a normalized set
196  rot1 = realWRAP(rot1, -180, 180);
197  tilt1 = realWRAP(tilt1, -180, 180);
198  psi1 = realWRAP(psi1, -180, 180);
199 
200  rot2 = realWRAP(rot2, -180, 180);
201  tilt2 = realWRAP(tilt2, -180, 180);
202  psi2 = realWRAP(psi2, -180, 180);
203 
204  // Apply rotations to find the minimum distance angles
205  rot2p = rot2;
206  tilt2p = tilt2;
207  psi2p = psi2;
208  distp = SL.computeDistance(rot1, tilt1, psi1,
209  rot2p, tilt2p, psi2p, false,
211  angular_distance += distp;
212 
213  // Compute angular difference
214  rot_diff(i) = rot1 - rot2p;
215  tilt_diff(i) = tilt1 - tilt2p;
216  psi_diff(i) = psi1 - psi2p;
217  vec_diff(i) = distp;
218  X_diff(i) = X1 - X2;
219  Y_diff(i) = Y1 - Y2;
220  shift_diff(i) = sqrt(X_diff(i)*X_diff(i)+Y_diff(i)*Y_diff(i));
221  shift_distance += shift_diff(i);
222 
223  // Fill the output result
224  if (fillOutput)
225  {
226  MDRowVec row;
227  row.setValue(MDL_ITEM_ID, itemId);
228 
229  // Write angles
231  // Average angles
232  double rotAvg, tiltAvg, psiAvg;
233  computeAverageAngles(rot1, tilt1, psi1,
234  rot2p, tilt2p, psi2p,
235  rotAvg, tiltAvg, psiAvg );
236 
237  row.setValue(MDL_ANGLE_ROT, rotAvg);
238  row.setValue(MDL_ANGLE_ROT2, rot1);
239  row.setValue(MDL_ANGLE_ROT3, rot2p);
240  row.setValue(MDL_ANGLE_TILT, tiltAvg);
241  row.setValue(MDL_ANGLE_TILT2, tilt1);
242  row.setValue(MDL_ANGLE_TILT3, tilt2p);
243  row.setValue(MDL_ANGLE_PSI, psiAvg);
244  row.setValue(MDL_ANGLE_PSI2, psi1);
245  row.setValue(MDL_ANGLE_PSI3, psi2p);
246  } else if (ang==2) {
247  row.setValue(MDL_ANGLE_ROT, rot2p);
248  row.setValue(MDL_ANGLE_ROT2, rot1);
249  row.setValue(MDL_ANGLE_TILT, tilt2p);
250  row.setValue(MDL_ANGLE_TILT2, tilt1);
251  row.setValue(MDL_ANGLE_PSI, psi2p);
252  row.setValue(MDL_ANGLE_PSI2, psi1);
253  } else {
254  row.setValue(MDL_ANGLE_ROT, rot1);
255  row.setValue(MDL_ANGLE_ROT2, rot2p);
256  row.setValue(MDL_ANGLE_TILT, tilt1);
257  row.setValue(MDL_ANGLE_TILT2, tilt2p);
258  row.setValue(MDL_ANGLE_PSI, psi1);
259  row.setValue(MDL_ANGLE_PSI2, psi2p);
260  }
261 
262  // Write angle differences
263  row.setValue(MDL_ANGLE_ROT_DIFF, rot_diff(i));
264  row.setValue(MDL_ANGLE_TILT_DIFF,tilt_diff(i) );
265  row.setValue(MDL_ANGLE_PSI_DIFF, psi_diff(i));
266  if (set==1)
267  row.setValue(MDL_ANGLE_DIFF, distp);
268  else
269  row.setValue(MDL_ANGLE_DIFF2, distp);
270 
271  // Write shifts
273  // Compute average
274  double XAvg, YAvg;
275  computeAverageShifts(X1, Y1,
276  X2, Y2,
277  XAvg, YAvg );
278 
279  row.setValue(MDL_SHIFT_X, XAvg);
280  row.setValue(MDL_SHIFT_X2, X1);
281  row.setValue(MDL_SHIFT_X3, X2);
282  row.setValue(MDL_SHIFT_Y, YAvg);
283  row.setValue(MDL_SHIFT_Y2, Y1);
284  row.setValue(MDL_SHIFT_Y3, Y2);
285  } else if(ang==2) {
286  row.setValue(MDL_SHIFT_X, X2);
287  row.setValue(MDL_SHIFT_X2, X1);
288  row.setValue(MDL_SHIFT_Y, Y2);
289  row.setValue(MDL_SHIFT_Y2, Y1);
290  } else {
291  row.setValue(MDL_SHIFT_X, X1);
292  row.setValue(MDL_SHIFT_X2, X2);
293  row.setValue(MDL_SHIFT_Y, Y1);
294  row.setValue(MDL_SHIFT_Y2, Y2);
295  }
296 
297  // Write shift differences
298  row.setValue(MDL_SHIFT_X_DIFF, X_diff(i));
299  row.setValue(MDL_SHIFT_Y_DIFF, Y_diff(i));
300  if (set==1)
301  row.setValue(MDL_SHIFT_DIFF,shift_diff(i));
302  else
303  row.setValue(MDL_SHIFT_DIFF2,shift_diff(i));
304 
305  id = DF_out.addRow(row);
306  //id = DF_out.addObject();
307  DF_out.setValue(MDL_IMAGE,fnImg,id);
308  //DF_out.setValue(MDL_ANGLE_COMPARISON,output, id);
309  }
310  }
311  if (0 == i) {
312  REPORT_ERROR(ERR_NUMERICAL, "i is zero (0), which would lead to division by zero");
313  }
314  angular_distance /= i;
315  shift_distance /=i;
316 
317  if (fillOutput)
318  {
319  DF_out.write(fn_out + ".xmd");
320  Histogram1D hist;
321  compute_hist(vec_diff, hist, 0, 180, 180);
322  hist.write(fn_out + "_vec_diff_hist.txt",MDL_ANGLE_DIFF,MDL_COUNT);
323  compute_hist(shift_diff, hist, 20);
324  hist.write(fn_out + "_shift_diff_hist.txt",MDL_SHIFT_DIFF,MDL_COUNT);
325  if (verbose==2)
326  {
327  compute_hist(rot_diff, hist, 100);
328  hist.write(fn_out + "_rot_diff_hist.txt");
329  compute_hist(tilt_diff, hist, 100);
330  hist.write(fn_out + "_tilt_diff_hist.txt");
331  compute_hist(psi_diff, hist, 100);
332  hist.write(fn_out + "_psi_diff_hist.txt");
333  compute_hist(X_diff, hist, 20);
334  hist.write(fn_out + "_X_diff_hist.txt");
335  compute_hist(Y_diff, hist, 20);
336  hist.write(fn_out + "_Y_diff_hist.txt");
337  }
338  }
339 
340  std::cout << "Global angular distance = " << angular_distance << std::endl;
341  std::cout << "Global shift distance = " << shift_distance << std::endl;
342 }
343 
345 {
346  MetaDataVec DF1sorted, DF2sorted, DFweights;
348  DF1sorted.sort(DF1,label);
349  DF2sorted.sort(DF2,label);
350  std::vector<MDLabel> labels;
351  labels.push_back(label);
352  labels.push_back(MDL_ANGLE_ROT);
353  labels.push_back(MDL_ANGLE_TILT);
354  labels.push_back(MDL_ANGLE_PSI);
355  labels.push_back(MDL_SHIFT_X);
356  labels.push_back(MDL_SHIFT_Y);
357  labels.push_back(MDL_FLIP);
358  DF1sorted.keepLabels(labels);
359  DF2sorted.keepLabels(labels);
360  MDLabel angleDiffLabel, shiftDiffLabel, weightLabel;
361  switch (set)
362  {
363  case 1:
364  angleDiffLabel=MDL_ANGLE_DIFF;
365  shiftDiffLabel=MDL_SHIFT_DIFF;
366  weightLabel=MDL_WEIGHT_JUMPER;
367  break;
368  case 2:
369  angleDiffLabel=MDL_ANGLE_DIFF2;
370  shiftDiffLabel=MDL_SHIFT_DIFF2;
371  weightLabel=MDL_WEIGHT_JUMPER2;
372  break;
373  case 0:
374  angleDiffLabel=MDL_ANGLE_DIFF0;
375  shiftDiffLabel=MDL_SHIFT_DIFF0;
376  weightLabel=MDL_WEIGHT_JUMPER0;
377  break;
378  default:
379  REPORT_ERROR(ERR_VALUE_INCORRECT, "Set value is out of range. It shoudl be 0, 1 or 2.\n");
380  }
381 
382  auto iter1(DF1sorted.ids().begin());
383  auto iter2(DF2sorted.ids().begin());
384  std::vector< Matrix1D<double> > ang1, ang2;
385  Matrix1D<double> rotTiltPsi(5);
386  size_t currentId;
387  bool anotherImageIn2 = iter2 != DF2sorted.ids().end();
388  size_t id1, id2;
389  bool mirror;
390  while (anotherImageIn2)
391  {
392  ang1.clear();
393  ang2.clear();
394 
395  // Take current id
396  DF2sorted.getValue(label,currentId, *iter2);
397 
398  // Grab all the angles in DF2 associated to this id
399  bool anotherIteration=false;
400  do
401  {
402  DF2sorted.getValue(label,id2,*iter2);
403  anotherIteration=false;
404  if (id2==currentId)
405  {
406  DF2sorted.getValue(MDL_ANGLE_ROT,XX(rotTiltPsi),*iter2);
407  DF2sorted.getValue(MDL_ANGLE_TILT,YY(rotTiltPsi),*iter2);
408  DF2sorted.getValue(MDL_ANGLE_PSI,ZZ(rotTiltPsi),*iter2);
409  DF2sorted.getValue(MDL_SHIFT_X,VEC_ELEM(rotTiltPsi,3),*iter2);
410  DF2sorted.getValue(MDL_SHIFT_Y,VEC_ELEM(rotTiltPsi,4),*iter2);
411  DF2sorted.getValue(MDL_FLIP,mirror,*iter2);
412  if (mirror)
413  {
414  double rotp, tiltp, psip;
415  Euler_mirrorY(XX(rotTiltPsi),YY(rotTiltPsi),ZZ(rotTiltPsi), rotp, tiltp, psip);
416  XX(rotTiltPsi)=rotp;
417  YY(rotTiltPsi)=tiltp;
418  ZZ(rotTiltPsi)=psip;
419  }
420  ang2.push_back(rotTiltPsi);
421  ++iter2;
422  if (iter2 != DF2sorted.ids().end())
423  anotherIteration=true;
424  }
425  } while (anotherIteration);
426 
427  // Advance Iter 1 to catch Iter 2
428  double N=0, cumulatedDistance=0, cumulatedDistanceShift=0;
429  size_t newObjId=0;
430  if (iter1 != DF1sorted.ids().end() && *iter1 > 0)
431  {
432  DF1sorted.getValue(label,id1,*iter1);
433  const auto lastID = DF1sorted.ids().end();
434  while (id1<currentId && iter1 != lastID)
435  {
436  ++iter1;
437  if (iter1 != DF1sorted.ids().end())
438  DF1sorted.getValue(label,id1,*iter1);
439  }
440 
441  // If we are at the end of DF1, then we did not find id1 such that id1==currentId
442  if (iter1 == DF1sorted.ids().end())
443  break;
444 
445  // Grab all the angles in DF1 associated to this id
446  anotherIteration=false;
447  do
448  {
449  DF1sorted.getValue(label,id1,*iter1);
450  anotherIteration=false;
451  if (id1==currentId)
452  {
453  DF1sorted.getValue(MDL_ANGLE_ROT,XX(rotTiltPsi),*iter1);
454  DF1sorted.getValue(MDL_ANGLE_TILT,YY(rotTiltPsi),*iter1);
455  DF1sorted.getValue(MDL_ANGLE_PSI,ZZ(rotTiltPsi),*iter1);
456  DF1sorted.getValue(MDL_SHIFT_X,VEC_ELEM(rotTiltPsi,3),*iter1);
457  DF1sorted.getValue(MDL_SHIFT_Y,VEC_ELEM(rotTiltPsi,4),*iter1);
458  DF1sorted.getValue(MDL_FLIP,mirror,*iter1);
459  if (mirror)
460  {
461  double rotp, tiltp, psip;
462  Euler_mirrorY(XX(rotTiltPsi),YY(rotTiltPsi),ZZ(rotTiltPsi), rotp, tiltp, psip);
463  XX(rotTiltPsi)=rotp;
464  YY(rotTiltPsi)=tiltp;
465  ZZ(rotTiltPsi)=psip;
466  }
467  ang1.push_back(rotTiltPsi);
468  ++iter1;
469  if (iter1 != DF1sorted.ids().end())
470  anotherIteration=true;
471  }
472  } while (anotherIteration);
473 
474  // Process both sets of angles
475  cumulatedDistance=0;
476  N=0;
477  for (size_t i=0; i<ang2.size(); ++i)
478  {
479  const Matrix1D<double> &anglesi=ang2[i];
480  double rot2=XX(anglesi);
481  double tilt2=YY(anglesi);
482  double psi2=ZZ(anglesi);
483  double bestDistance=1e38, bestShiftDistance=1e38;
484  for (size_t j=0; j<ang1.size(); ++j)
485  {
486  const Matrix1D<double> &anglesj=ang1[j];
487  double rot1=XX(anglesj);
488  double tilt1=YY(anglesj);
489  double psi1=ZZ(anglesj);
490  double dist = SL.computeDistance(rot1, tilt1, psi1, rot2, tilt2, psi2, false,
492  if (dist<bestDistance)
493  {
494  bestDistance=dist;
495  bestShiftDistance=fabs(VEC_ELEM(anglesi,3)-VEC_ELEM(anglesj,3))+fabs(VEC_ELEM(anglesi,4)-VEC_ELEM(anglesj,4));
496  }
497  }
498  bestShiftDistance*=0.5;
499  if (bestDistance<360)
500  {
501  cumulatedDistance+=bestDistance;
502  cumulatedDistanceShift+=bestShiftDistance;
503  N++;
504  }
505  }
506  newObjId=DFweights.addObject();
507  DFweights.setValue(label,currentId,newObjId);
508  }
509  else
510  N=0;
511 
512  if (N>0)
513  {
514  double meanDistance=cumulatedDistance/ang2.size();
515  DFweights.setValue(angleDiffLabel,meanDistance,newObjId);
516  double meanDistanceShift=cumulatedDistanceShift/ang2.size();
517  DFweights.setValue(shiftDiffLabel,meanDistanceShift,newObjId);
518  ang1.clear();
519  ang2.clear();
520  }
521  else
522  if (newObjId>0)
523  {
524  DFweights.setValue(angleDiffLabel,-1.0,newObjId);
525  DFweights.setValue(shiftDiffLabel,-1.0,newObjId);
526  ang1.clear();
527  ang2.clear();
528  }
529  anotherImageIn2 = iter2 != DF2sorted.ids().end();
530  }
531  if (ang2.size()>0)
532  {
533  size_t newObjId=DFweights.addObject();
534  DFweights.setValue(label,currentId,newObjId);
535  DFweights.setValue(angleDiffLabel,-1.0,newObjId);
536  DFweights.setValue(shiftDiffLabel,-1.0,newObjId);
537  }
538 
539  // If there are more images in MD1 than in MD2, set the last images to 0
540  const auto totalSize = DF2sorted.ids().end();
541  while (iter2 != totalSize)
542  {
543  size_t newObjId=DFweights.addObject();
544  DFweights.setValue(label,currentId,newObjId);
545  DFweights.setValue(angleDiffLabel,-1.0,newObjId);
546  DFweights.setValue(shiftDiffLabel,-1.0,newObjId);
547  ++iter2;
548  }
549 
550  // Calculate the deviation with respect to angleDiff=0 of the angular distances
551  std::vector<double> angleDistances, shiftDistances;
552  DFweights.getColumnValues(angleDiffLabel,angleDistances);
553  DFweights.getColumnValues(shiftDiffLabel,shiftDistances);
554 
555  double sigma2=0, sigma2D=0, N=0;
556  for (size_t i=0; i<angleDistances.size(); ++i)
557  {
558  double d=angleDistances[i];
559  if (d>0)
560  {
561  sigma2+=d*d;
562  d=shiftDistances[i];
563  sigma2D+=d*d;
564  ++N;
565  }
566  }
567  sigma2/=N;
568  sigma2=std::max(minSigma*minSigma,sigma2);
569  std::cout << "Sigma of angular distances=" << sqrt(sigma2) << std::endl;
570  sigma2D/=N;
571  sigma2D=std::max(minSigmaD*minSigmaD,sigma2D);
572  std::cout << "Sigma of shift distances=" << sqrt(sigma2D) << std::endl;
573 
574  // Adjust the jumper weights according to a Gaussian
575  double isigma2=-0.5/sigma2;
576  double isigma2D=-0.5/sigma2D;
577 
578  for (size_t objId : DFweights.ids())
579  {
580  double d;
581  double weight=1.0;
582  DFweights.getValue(angleDiffLabel,d,objId);
583  if (d>0)
584  weight=exp(d*d*isigma2);
585  else
586  weight=0.5;
587 
588  if (minSigmaD>0)
589  {
590  DFweights.getValue(shiftDiffLabel,d,objId);
591  if (d>0)
592  weight*=exp(d*d*isigma2D);
593  else
594  weight*=0.5;
595  }
596  DFweights.setValue(weightLabel,weight,objId);
597  }
598 
599  // Transfer these weights to the DF2 metadata
600  MetaDataDb DF2weighted;
601  if (DF2.containsLabel(angleDiffLabel))
602  DF2.removeLabel(angleDiffLabel);
603  if (DF2.containsLabel(angleDiffLabel))
604  DF2.removeLabel(angleDiffLabel);
605  if (DF2.containsLabel(weightLabel))
606  DF2.removeLabel(weightLabel);
607  DF2weighted.join1(MetaDataDb(DF2),MetaDataDb(DFweights),label,INNER);
608 
609  for (size_t objId : DF2weighted.ids())
610  {
611  double d;
612  DF2weighted.getValue(angleDiffLabel,d,objId);
613  if (d<0)
614  {
615  // DF2weighted.setValue(MDL_ENABLED,-1,objId);
616  DF2weighted.setValue(angleDiffLabel,0.0,objId);
617  }
618  DF2weighted.getValue(shiftDiffLabel,d,objId);
619  if (d<0)
620  {
621  // DF2weighted.setValue(MDL_ENABLED,-1,objId);
622  DF2weighted.setValue(shiftDiffLabel,0.0,objId);
623  }
624  }
625  DF2weighted.removeDisabled();
626  DF2weighted.write(fn_out+"_weights.xmd");
627 }
628 
629 void ProgAngularDistance::euler2quat( double rot, double tilt, double psi,
630  double q[4] )
631 {
632  // Convert to radians and divide by 2
633  const double ai = -DEG2RAD(rot) / 2;
634  const double aj = DEG2RAD(tilt) / 2;
635  const double ak = -DEG2RAD(psi) / 2;
636 
637  // Obtain sin and cos
638  const double si = std::sin(ai),
639  ci = std::cos(ai),
640  sj = std::sin(aj),
641  cj = std::cos(aj),
642  sk = std::sin(ak),
643  ck = std::cos(ak);
644 
645  const double cc = ci * ck,
646  cs = ci * sk,
647  sc = si * ck,
648  ss = si * sk;
649 
650  // Compute the quaternion values
651  // WXYZ
652  q[0] = +cj * (cc - ss);
653  q[1] = +sj * (cs - sc);
654  q[2] = -sj * (cc + ss);
655  q[3] = +cj * (cs + sc);
656 }
657 
658 void ProgAngularDistance::quat2Euler( const double q[4],
659  double& rot, double& tilt, double& psi )
660 {
661  // Multiply the quaternion by sqrt2 to avoid multiplying pairs by 2
662  const auto sqrt2 = std::sqrt(2);
663  const auto qw = sqrt2 * q[0];
664  const auto qx = sqrt2 * q[1];
665  const auto qy = sqrt2 * q[2];
666  const auto qz = sqrt2 * q[3];
667 
668  // Obtain pairwise products of the quaternion elements
669  const auto qx2 = qx*qx;
670  const auto qy2 = qy*qy;
671  const auto qz2 = qz*qz;
672  const auto qxqy = qx*qy;
673  const auto qxqz = qx*qz;
674  const auto qxqw = qx*qw;
675  const auto qyqz = qy*qz;
676  const auto qyqw = qy*qw;
677  const auto qzqw = qz*qw;
678 
679  // Ensemble the matrix
680  const double //m00 = 1 - qy2 - qz2,
681  //m01 = qxqy - qzqw,
682  m02 = qxqz + qyqw,
683  m10 = qxqy + qzqw,
684  m11 = 1 - qx2 - qz2,
685  m12 = qyqz - qxqw,
686  m20 = qxqz - qyqw,
687  m21 = qyqz + qxqw,
688  m22 = 1 - qx2 - qy2;
689 
690 
691 
692  const auto sy = std::sqrt(m21*m21 + m20*m20);
693  double ax, ay, az;
694  if(sy > 1e-6) {
695  ax = std::atan2(m21, m20);
696  ay = std::atan2(sy, m22);
697  az = std::atan2(m12, -m02);
698  } else {
699  ax = std::atan2(-m10, m11);
700  ay = std::atan2(sy, m22);
701  az = 0;
702  }
703 
704  rot = RAD2DEG(ax);
705  tilt = RAD2DEG(ay);
706  psi = RAD2DEG(az);
707 }
708 
709 void ProgAngularDistance::computeAverageAngles( double rot1, double tilt1, double psi1,
710  double rot2, double tilt2, double psi2,
711  double& rot, double& tilt, double& psi )
712 {
713  // Convert the angles to quaternions
714  Matrix1D<double> eigvals;
715  Matrix2D<double> quaternions(2, 4), m, eigvecs;
716  euler2quat(rot1, tilt1, psi1, &MAT_ELEM(quaternions, 0, 0));
717  euler2quat(rot2, tilt2, psi2, &MAT_ELEM(quaternions, 1, 0));
718 
719  // Average quaternions into a matrix
720  matrixOperation_AtA(quaternions, m);
721  m /= 2;
722 
723  // Compute the largest eigenvector
724  firstEigs(m, 1UL, eigvals, eigvecs, true);
725 
726  // Convert back to euler. As eigvecs has a single
727  // column it is safe to take a pointer to its data
728  assert(MAT_SIZE(eigvecs) == 4);
729  quat2Euler(MATRIX2D_ARRAY(eigvecs), rot, tilt, psi);
730 }
731 
732 void ProgAngularDistance::computeAverageShifts( double shiftX1, double shiftY1,
733  double shiftX2, double shiftY2,
734  double& shiftX, double& shiftY )
735 {
736  shiftX = (shiftX1 + shiftX2) / 2;
737  shiftY = (shiftY1 + shiftY2) / 2;
738 }
Rotation angle of an image (double,degrees)
void min(Image< double > &op1, const Image< double > &op2)
#define VEC_ELEM(v, i)
Definition: matrix1d.h:245
void resize(size_t Ndim, size_t Zdim, size_t Ydim, size_t Xdim, bool copy=true)
Tilting angle of an image (double,degrees)
Shift for the image in the X axis (double)
#define MAT_SIZE(m)
Definition: matrix2d.h:128
shift difference (double)
void sort(const MetaDataVec &MDin, const MDLabel sortLabel, bool asc=true, int limit=-1, int offset=0)
double getDoubleParam(const char *param, int arg=0)
static MDLabel str2Label(const String &labelName)
Shift for the image in the Y axis (double)
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
Weight due to angular jumping.
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
difference between rot angles (double,degrees)
void keepLabels(const std::vector< MDLabel > &labels)
#define DEG2RAD(d)
Definition: xmipp_macros.h:312
void sqrt(Image< double > &op)
bool removeLabel(const MDLabel label) override
bool getValue(MDObject &mdValueOut, size_t id) const override
Tilting angle of an image (double,degrees)
difference between two angles (double,degrees)
void setValue(const MDObject &object) override
int readSymmetryFile(FileName fn_sym, double accuracy=SYM_ACCURACY)
Definition: symmetries.cpp:33
Shift for the image in the X axis (double)
static void euler2quat(double rot, double tilt, double psi, double q[4])
void Euler_mirrorY(double rot, double tilt, double psi, double &newrot, double &newtilt, double &newpsi)
Definition: geometry.cpp:1011
Tilting angle of an image (double,degrees)
Special label to be used when gathering MDs in MpiMetadataPrograms.
difference in Shift along Y axis (double)
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
virtual IdIteratorProxy< false > ids()
void matrixOperation_AtA(const Matrix2D< double > &A, Matrix2D< double > &B)
Definition: matrix2d.cpp:436
static void computeAverageAngles(double rot1, double tilt1, double psi1, double rot2, double tilt2, double psi2, double &rot, double &tilt, double &psi)
bool compute_average_angle
Compute angle mean.
size_t size() const override
#define i
Incorrect number of objects in Metadata.
Definition: xmipp_error.h:160
size_t addRow(const MDRow &row) override
Unique identifier for items inside a list or set (std::size_t)
doublereal * d
Shift for the image in the Y axis (double)
void readParams()
Read argument from command line.
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
Rotation angle of an image (double,degrees)
static void computeAverageShifts(double shiftX1, double shiftY1, double shiftX2, double shiftY2, double &shiftX, double &shiftY)
double computeDistance(double rot1, double tilt1, double psi1, double &rot2, double &tilt2, double &psi2, bool projdir_mode, bool check_mirrors, bool object_rotation=false, bool write_mirrors=true)
shift difference (double)
struct _constraint * cs
Number of elements of a type (int) [this is a genereic type do not use to transfer information to ano...
const char * getParam(const char *param, int arg=0)
void compute_hist(const MultidimArrayGeneric &array, Histogram1D &hist, int no_steps)
Definition: histogram.cpp:572
#define XX(v)
Definition: matrix1d.h:85
difference between psi angles (double,degrees)
bool setValue(const MDObject &mdValueIn, size_t id)
Weight due to angular jumping.
size_t addObject() override
Flip the image? (bool)
void firstEigs(const Matrix2D< double > &A, size_t M, Matrix1D< double > &D, Matrix2D< double > &P, bool Pneeded)
Definition: matrix2d.cpp:284
static void quat2Euler(const double q[4], double &rot, double &tilt, double &psi)
void max(Image< double > &op1, const Image< double > &op2)
Error related to numerical calculation.
Definition: xmipp_error.h:179
int verbose
Verbosity level.
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const override
Psi angle of an image (double,degrees)
#define j
difference between two angles (double,degrees)
bool compute_average_shift
Compute shift mean.
#define YY(v)
Definition: matrix1d.h:93
int m
void defineParams()
Define parameters.
bool getValue(MDObject &mdValueOut, size_t id) const override
void getColumnValues(const MDLabel label, std::vector< MDObject > &valuesOut) const override
Shift for the image in the X axis (double)
bool setValue(const MDObject &mdValueIn, size_t id) override
Definition: metadata_db.cpp:90
virtual void removeDisabled()
#define RAD2DEG(r)
Definition: xmipp_macros.h:320
double psi(const double x)
void write(const FileName &fn, MDLabel=MDL_X, MDLabel=MDL_COUNT)
Definition: histogram.cpp:129
Rotation angle of an image (double,degrees)
#define realWRAP(x, x0, xF)
Definition: xmipp_macros.h:304
difference between two angles (double,degrees)
void join1(const MetaDataDb &mdInLeft, const MetaDataDb &mdInRight, const MDLabel label, JoinType type=LEFT)
bool checkParam(const char *param)
difference between tilt angles (double,degrees)
Weight due to angular jumping.
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
bool containsLabel(const MDLabel label) const override
int ang
The set of angles to be used for output.
shift difference (double)
int getIntParam(const char *param, int arg=0)
Incorrect value received.
Definition: xmipp_error.h:195
#define MATRIX2D_ARRAY(m)
Definition: matrix2d.h:89
Psi angle of an image (double,degrees)
Name of an image (std::string)
#define ZZ(v)
Definition: matrix1d.h:101
MDLabel
void addParamsLine(const String &line)
difference in Shift along X axis (double)