Xmipp  v3.23.11-Nereus
image_peak_high_contrast.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Federico P. de Isidro Gomez fp.deisidro@cnb.csic.es
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 
27 #include <chrono>
28 
29 
30 
31 // --------------------- IN/OUT FUNCTIONS -----------------------------
32 
34 {
35  fnVol = getParam("--vol");
36  fnOut = getParam("-o");
37  samplingRate = getDoubleParam("--samplingRate");
38  fiducialSize = getDoubleParam("--fiducialSize");
39  boxSize = getIntParam("--boxSize");
40  numberSampSlices = getIntParam("--numberSampSlices");
41  sdThr = getDoubleParam("--sdThr");
42  numberOfCoordinatesThr = getIntParam("--numberOfCoordinatesThr");
43  mirrorCorrelationThr = getDoubleParam("--mirrorCorrelationThr");
44  mahalanobisDistanceThr = getDoubleParam("--mahalanobisDistanceThr");
45  relaxedMode = checkParam("--relaxedModeThr");
46 
47  if (relaxedMode)
48  {
49  relaxedModeThr = getIntParam("--relaxedModeThr");
50  }
51 
52 }
53 
54 
56 {
57  addUsageLine("This function determines the location of high contrast features in a volume.");
58  addParamsLine(" --vol <vol_file=\"\"> : File path to input volume.");
59  addParamsLine(" [-o <output=\"coordinates3D.xmd\">] : File path to output coordinates file.");
60  addParamsLine(" [--samplingRate <samplingRate=1>] : Sampling rate of the input tomogram (A/px).");
61  addParamsLine(" [--fiducialSize <fiducialSize=100>] : Size of the fiducial markers in Angstroms (A).");
62  addParamsLine(" [--boxSize <boxSize=32>] : Box size of the peaked fiducials.");
63  addParamsLine(" [--numberSampSlices <numberSampSlices=10>] : Number of sampling slices to calculate the threshold value.");
64  addParamsLine(" [--sdThr <sdThr=5>] : Number of STD away the mean to consider that a pixel has an outlier value.");
65  addParamsLine(" [--numberOfCoordinatesThr <numberOfCoordinatesThr=10>] : Minimum number of points attracted to a coordinate.");
66  addParamsLine(" [--mirrorCorrelationThr <mirrorCorrelationThr=0.1>] : Minimum correlation of a coordinate with its mirror.");
67  addParamsLine(" [--mahalanobisDistanceThr <mahalanobisDistanceThr=2>] : Minimum Mahalanobis distance.");
68  addParamsLine(" [--relaxedModeThr <mahalanobisDistanceThr=3>] : Number of remaining coordinates to disable a filter in case it removes all coordinates.");
69 }
70 
71 
73 {
74  #ifdef VERBOSE_OUTPUT
75  std::cout << "Saving output coordinates... " << std::endl;
76  #endif
77 
78  MetaDataVec md;
79  size_t id;
80 
81  for(size_t i = 0 ;i < coordinates3D.size(); i++)
82  {
83  id = md.addObject();
84  md.setValue(MDL_XCOOR, (int)coordinates3D[i].x, id);
85  md.setValue(MDL_YCOOR, (int)coordinates3D[i].y, id);
86  md.setValue(MDL_ZCOOR, (int)coordinates3D[i].z, id);
87  }
88 
89  md.write(fnOut);
90 
91  #ifdef VERBOSE_OUTPUT
92  std::cout << "Output coordinates metadata saved at: " << fnOut << std::endl;
93  #endif
94 }
95 
96 
97 
98 // ---------------------- MAIN FUNCTIONS -----------------------------
99 
101 {
102  #ifdef VERBOSE_OUTPUT
103  std::cout << "Preprocessing volume..." << std::endl;
104  #endif
105 
106  // -- Average
107  #ifdef VERBOSE_OUTPUT
108  std::cout << "Averaging volume..." << std::endl;
109  #endif
110 
111  MultidimArray<double> slice(ySize, xSize);
112  MultidimArray<double> sliceU(ySize, xSize);
113  MultidimArray<double> sliceD(ySize, xSize);
114  MultidimArray<double> sliceU2(ySize, xSize);
115  MultidimArray<double> sliceD2(ySize, xSize);
116 
117  for (int k = 2; k < zSize-2; k++)
118  {
119  if(k==2)
120  {
121  inputTomo.getSlice(k-2, sliceU2);
122  inputTomo.getSlice(k-1, sliceU);
123  inputTomo.getSlice(k, slice);
124  inputTomo.getSlice(k+1, sliceD);
125  inputTomo.getSlice(k+2, sliceD2);
126  }
127  else
128  {
129  sliceU2 = sliceU;
130  sliceU = slice;
131  slice = sliceD;
132  sliceD = sliceD2;
133  inputTomo.getSlice(k+2, sliceD2);
134  }
135 
136  for (int i = 0; i < ySize; i++)
137  {
138  for (int j = 0; j < xSize; j++)
139  {
140  DIRECT_A3D_ELEM(inputTomo, k, i, j) = DIRECT_A2D_ELEM(sliceD2, i , j) +
141  DIRECT_A2D_ELEM(sliceD, i , j) +
142  DIRECT_A2D_ELEM(slice, i , j) +
143  DIRECT_A2D_ELEM(sliceU, i , j) +
144  DIRECT_A2D_ELEM(sliceU2, i , j);
145  }
146  }
147  }
148 
149  #ifdef DEBUG_OUTPUT_FILES
150  size_t lastindex = fnOut.find_last_of(".");
151  std::string rawname = fnOut.substr(0, lastindex);
152  std::string outputFileNameFilteredVolume;
153  outputFileNameFilteredVolume = rawname + "_average.mrc";
154 
155  V.write(outputFileNameFilteredVolume);
156  #endif
157 
158  #ifdef VERBOSE_OUTPUT
159  std::cout << "Volume averaging finished succesfully!" << std::endl;
160  #endif
161 
162 
163  // -- Band-pass filtering
165  transformer.FourierTransform(inputTomo, fftV, false);
166 
167  #ifdef VERBOSE_OUTPUT
168  std::cout << "Applying bandpass filter to volume..." << std::endl;
169  #endif
170 
171  int n=0;
172 
173  double freqLow = samplingRate / (fiducialSize*1.1);
174  double freqHigh = samplingRate/(fiducialSize*0.9);
175 
176  double w; // = 0.02
177  double cutoffFreqHigh = freqHigh + w;
178  double cutoffFreqLow = freqLow - w;
179  double delta = PI / w;
180 
181  normDim = (xSize>ySize) ? xSize : ySize;
182 
183  // 43.2 = 1440 * 0.03. This 43.2 value makes w = 0.03 (standard value) for an image whose bigger dimension is 1440 px.
184  //w = 43.2 / normDim;
185 
186  #ifdef DEBUG_PREPROCESS
187  std::cout << "samplingRate " << samplingRate << std::endl;
188  std::cout << "fiducialSize " << fiducialSize << std::endl;
189  std::cout << "freqLow " << freqLow << std::endl;
190  std::cout << "freqHigh " << freqHigh << std::endl;
191  std::cout << "cutoffFreqLow " << cutoffFreqLow << std::endl;
192  std::cout << "cutoffFreqHigh " << cutoffFreqHigh << std::endl;
193  #endif
194 
195  for(size_t k=0; k<ZSIZE(fftV); ++k)
196  {
197  double uz;
198  double uy;
199  double ux;
200  double uz2y2;
201  double uz2;
202 
203  FFT_IDX2DIGFREQ(k,zSize,uz);
204  uz2=uz*uz;
205 
206  for(size_t i=0; i<YSIZE(fftV); ++i)
207  {
208  FFT_IDX2DIGFREQ(i,ySize,uy);
209  uz2y2=uz2+uy*uy;
210 
211  for(size_t j=0; j<XSIZE(fftV); ++j)
212  {
213  FFT_IDX2DIGFREQ(j,xSize,ux);
214  double u=sqrt(uz2y2+ux*ux);
215 
216  if(u > cutoffFreqHigh || u < cutoffFreqLow)
217  {
218  DIRECT_MULTIDIM_ELEM(fftV, n) = 0;
219  }
220  else
221  {
222  if(u >= freqHigh && u < cutoffFreqHigh)
223  {
224  DIRECT_MULTIDIM_ELEM(fftV, n) *= 0.5*(1+cos((u-freqHigh)*delta));
225  }
226 
227  if (u <= freqLow && u > cutoffFreqLow)
228  {
229  DIRECT_MULTIDIM_ELEM(fftV, n) *= 0.5*(1+cos((u-freqLow)*delta));
230  }
231  }
232 
233  ++n;
234  }
235  }
236  }
237 
239 
240  #ifdef DEBUG_OUTPUT_FILES
241  lastindex = fnOut.find_last_of(".");
242  rawname = fnOut.substr(0, lastindex);
243  outputFileNameFilteredVolume;
244  outputFileNameFilteredVolume = rawname + "_bandpass.mrc";
245 
246  V.write(outputFileNameFilteredVolume);
247  #endif
248 
249  #ifdef VERBOSE_OUTPUT
250  std::cout << "Bandpass filter applied to volume succesfully!" << std::endl;
251  #endif
252 
253 
254  // -- Apply Laplacian to tomo with kernel:
255  // 0 0 0 0 -1 0 0 0 0
256  // k = 0 -1 0 -1 4 -1 0 -1 0
257  // 0 0 0 0 -1 0 0 0 0
258 
259  #ifdef VERBOSE_OUTPUT
260  std::cout << "Applying laplacian filter to volume..." << std::endl;
261  #endif
262 
263  for (int k = 1; k < zSize-1; k++)
264  {
265  MultidimArray<double> slice(ySize, xSize);
266  inputTomo.getSlice(k, slice);
267 
268  for (int i = 1; i < ySize-1; i++)
269  {
270  for (int j = 1; j < xSize-1; j++)
271  {
272  DIRECT_A3D_ELEM(inputTomo, k, i, j) = -2 * DIRECT_A2D_ELEM(slice, i, j-1) +
273  -2 * DIRECT_A2D_ELEM(slice, i, j+1) +
274  -2 * DIRECT_A2D_ELEM(slice, i-1, j) +
275  -2 * DIRECT_A2D_ELEM(slice, i+1, j) +
276  8 * DIRECT_A2D_ELEM(slice, i, j);
277  }
278  }
279  }
280 
281  #ifdef VERBOSE_OUTPUT
282  std::cout << "Laplacian filter applied to volume succesfully!" << std::endl;
283  #endif
284 
285 
286  // -- Set extreme slices to 0 (unafected by average filter)
287  for (int k = 0; k < zSize; k++)
288  {
289  if(k<2 || k > zSize-2)
290  {
291  for (int i = 0; i < ySize; i++)
292  {
293  for (int j = 0; j < xSize; j++)
294  {
295  DIRECT_A3D_ELEM(inputTomo, k, i, j) = 0.0;
296  }
297  }
298  }
299  }
300 
301  #ifdef DEBUG_OUTPUT_FILES
302  lastindex = fnOut.find_last_of(".");
303  rawname = fnOut.substr(0, lastindex);
304  outputFileNameFilteredVolume;
305  outputFileNameFilteredVolume = rawname + "_preprocess.mrc";
306 
307  V.write(outputFileNameFilteredVolume);
308  #endif
309 
310  #ifdef VERBOSE_OUTPUT
311  std::cout << "Volume preprocessed succesfully!" << std::endl;
312  #endif
313 }
314 
315 
317 {
318  #ifdef VERBOSE_OUTPUT
319  std::cout << "Picking coordinates..." << std::endl;
320  #endif
321 
322  size_t centralSlice = zSize/2;
323  size_t minSamplingSlice = centralSlice - (numberSampSlices / 2);
324  size_t maxSamplingSlice = centralSlice + (numberSampSlices / 2);
325 
326  #ifdef DEBUG_HCC
327  std::cout << "Number of sampling slices: " << numberSampSlices << std::endl;
328  std::cout << "Sampling region from slice " << minSamplingSlice << " to " << maxSamplingSlice << std::endl;
329  #endif
330 
331  // Calculate threshols value for the central slices of the volume
332  double sum = 0;
333  double sum2 = 0;
334  int Nelems = xSize * ySize * numberSampSlices;
335 
336  for(size_t k = minSamplingSlice; k < maxSamplingSlice; ++k)
337  {
338  for(size_t j = 0; j < ySize; ++j)
339  {
340  for(size_t i = 0; i < xSize; ++i)
341  {
342  double value = DIRECT_ZYX_ELEM(inputTomo, k, i ,j);
343  sum += value;
344  sum2 += value*value;
345  }
346  }
347  }
348 
349  double average = sum / Nelems;
350  double standardDeviation = sqrt(sum2/Nelems - average*average);
351 
352  double thresholdL = average-sdThr*standardDeviation;
353 
354  #ifdef DEBUG_HCC
355  double thresholdU = average+sdThr*standardDeviation;
356  std::cout << "ThresholdU value = " << thresholdU << std::endl;
357  std::cout << "ThresholdL value = " << thresholdL << std::endl;
358  #endif
359 
360  MultidimArray<double> binaryCoordinatesMapSlice;
361  MultidimArray<double> labelCoordiantesMapSlice;
362 
363  for(size_t k = 1; k < zSize-1; k++)
364  {
365  binaryCoordinatesMapSlice.initZeros(ySize, xSize);
366 
367  #ifdef DEBUG_HCC
368  int numberOfPointsAddedBinaryMap = 0;
369  #endif
370 
371  for(size_t j = 0; j < xSize; j++)
372  {
373  for(size_t i = 0; i < ySize; i++)
374  {
375  double value = DIRECT_A3D_ELEM(inputTomo, k, i, j);
376 
377  if (value < thresholdL)
378  {
379  DIRECT_A2D_ELEM(binaryCoordinatesMapSlice, i, j) = 1.0;
380 
381  #ifdef DEBUG_HCC
382  numberOfPointsAddedBinaryMap += 1;
383  #endif
384  }
385  }
386  }
387 
388  #ifdef DEBUG_HCC
389  std::cout << "Number of points in the binary map: " << numberOfPointsAddedBinaryMap << std::endl;
390  #endif
391 
392  #ifdef DEBUG_HCC
393  std::cout << "Labeling slice " << k << std::endl;
394  #endif
395 
396  int colour = labelImage2D(binaryCoordinatesMapSlice, labelCoordiantesMapSlice, 8); // Value 8 is the neighbourhood
397 
398 
399  #ifdef DEBUG_OUTPUT_FILES
400  for (size_t j = 0; j < xSize; j++)
401  {
402  for (size_t i = 0; i < ySize; i++)
403  {
404  double value = DIRECT_A2D_ELEM(labelCoordiantesMapSlice, i, j);
405 
406  if (value > 0)
407  {
408  DIRECT_A3D_ELEM(inputTomo, k, i, j) = value;
409  }
410  else
411  {
412  DIRECT_A3D_ELEM(inputTomo, k, i, j) = 0;
413  }
414  }
415  }
416  #endif
417 
418  #ifdef DEBUG_HCC
419  std::cout << "Colour: " << colour << std::endl;
420  #endif
421 
422  std::vector<std::vector<int>> coordinatesPerLabelX (colour);
423  std::vector<std::vector<int>> coordinatesPerLabelY (colour);
424 
425  for(size_t i = 0; i < ySize; i++)
426  {
427  for(size_t j = 0; j < xSize; ++j)
428  {
429  int value = DIRECT_A2D_ELEM(labelCoordiantesMapSlice, i, j);
430 
431  if(value != 0)
432  {
433  coordinatesPerLabelX[value-1].push_back(j);
434  coordinatesPerLabelY[value-1].push_back(i);
435  }
436  }
437  }
438 
439  size_t numberOfCoordinatesPerValue;
440 
441  // Trim coordinates based on the characteristics of the labeled region
442  for(size_t value = 0; value < colour; value++)
443  {
444  numberOfCoordinatesPerValue = coordinatesPerLabelX[value].size();
445 
446  int xCoor = 0;
447  int yCoor = 0;
448 
449  for(size_t coordinate=0; coordinate < coordinatesPerLabelX[value].size(); coordinate++)
450  {
451  xCoor += coordinatesPerLabelX[value][coordinate];
452  yCoor += coordinatesPerLabelY[value][coordinate];
453  }
454 
455  double xCoorCM = xCoor/numberOfCoordinatesPerValue;
456  double yCoorCM = yCoor/numberOfCoordinatesPerValue;
457 
458  bool keep = filterLabeledRegions(coordinatesPerLabelX[value], coordinatesPerLabelY[value], xCoorCM, yCoorCM);
459 
460  if(keep)
461  {
462  Point3D<double> point3D(xCoorCM, yCoorCM, k);
463  coordinates3D.push_back(point3D);
464  }
465  }
466  }
467 
468  #ifdef VERBOSE_OUTPUT
469  std::cout << "Number of high contrast features found: " << coordinates3D.size() << std::endl;
470  #endif
471 
472  #ifdef DEBUG_OUTPUT_FILES
473  size_t lastindex = fnOut.find_last_of(".");
474  std::string rawname = fnOut.substr(0, lastindex);
475  std::string outputFileNameLabeledVolume;
476  outputFileNameLabeledVolume = rawname + "_label.mrc";
477 
478  V.write(outputFileNameLabeledVolume);
479  #endif
480 }
481 
482 
484 {
485  std::vector<size_t> coordinatesInSlice;
486  std::vector<size_t> coordinatesInSlice_up;
487  std::vector<size_t> coordinatesInSlice_down;
488 
489  std::vector<size_t> coord3DVotes_V(coordinates3D.size(), 0);
490 
491  float thrVottingDistance2 = (fiducialSizePx/2)*(fiducialSizePx/2);
492 
493  #ifdef DEBUG_CLUSTER
494  std::cout << "thrVottingDistance2 " << thrVottingDistance2 << std::endl;
495  #endif
496 
497  size_t deletedIndexes;
498 
499  #ifdef DEBUG_CLUSTER
500  size_t iteration = 0;
501  #endif
502 
503  // -- Erase non-consistent coordinates with the voting systen
504  do
505  {
506  #ifdef DEBUG_CLUSTER
507  std::cout << "--- ITERATION " << iteration << std::endl;
508  #endif
509 
510  deletedIndexes = 0;
511 
512  // Votting step
513  for (int k = 0; k < zSize; k++)
514  {
515  if (k == 0) // Skip up-image for first slice
516  {
517  coordinatesInSlice = getCoordinatesInSliceIndex(k);
518  coordinatesInSlice_down = getCoordinatesInSliceIndex(k+1);
519  }
520  else if (k == (nSize-1)) // Skip down-image for last slice
521  {
522  coordinatesInSlice_up = coordinatesInSlice;
523  coordinatesInSlice = coordinatesInSlice_down;
524  }
525  else // Non-extrema slices
526  {
527  coordinatesInSlice_up = coordinatesInSlice;
528  coordinatesInSlice = coordinatesInSlice_down;
529  coordinatesInSlice_down = getCoordinatesInSliceIndex(k+1);
530  }
531 
532  for(size_t i = 0; i < coordinatesInSlice.size(); i++)
533  {
534  Point3D<double> c = coordinates3D[coordinatesInSlice[i]];
535 
536  // Skip for first image in the series
537  if (k != 0)
538  {
539  for (size_t j = 0; j < coordinatesInSlice_up.size(); j++)
540  {
541  Point3D<double> cu = coordinates3D[coordinatesInSlice_up[j]];
542  float distance2 = (c.x-cu.x)*(c.x-cu.x)+(c.y-cu.y)*(c.y-cu.y);
543 
544  if(distance2 < thrVottingDistance2)
545  {
546  coord3DVotes_V[coordinatesInSlice[i]] += 1;
547  }
548  }
549  }
550 
551  // Skip for last image in the series
552  if (k != (nSize-1))
553  {
554  for (size_t j = 0; j < coordinatesInSlice_down.size(); j++)
555  {
556  Point3D<double> cd = coordinates3D[coordinatesInSlice_down[j]];
557  float distance2 = (c.x-cd.x)*(c.x-cd.x)+(c.y-cd.y)*(c.y-cd.y);
558 
559  if(distance2 < thrVottingDistance2)
560  {
561  coord3DVotes_V[coordinatesInSlice[i]] += 1;
562  }
563  }
564  }
565  }
566  }
567 
568  // Trimming step
569  for (size_t i = 0; i < coord3DVotes_V.size(); i++)
570  {
571  if (coord3DVotes_V[i] == 0)
572  {
573  #ifdef DEBUG_CLUSTER
574  std::cout << "Deleted coordinate " << i << std::endl;
575  #endif
576 
577  coordinates3D.erase(coordinates3D.begin()+i);
578  coord3DVotes_V.erase(coord3DVotes_V.begin()+i);
579  deletedIndexes++;
580  i--;
581  }
582  }
583 
584  #ifdef DEBUG_CLUSTER
585  std::cout << "DeletedIndexes: " << deletedIndexes << std::endl;
586  iteration++;
587  #endif
588 
589  }
590  while(deletedIndexes > 0);
591 
592  #ifdef DEBUG_CLUSTER
593  std::cout << "coord3DVotes_V.size() " << coord3DVotes_V.size() << std::endl;
594  std::cout << "coordinates3D.size() " << coordinates3D.size() << std::endl;
595 
596  for (size_t i = 0; i < coord3DVotes_V.size(); i++)
597  {
598  std::cout << coord3DVotes_V[i] << " ";
599  }
600  std::cout << std::endl;
601  #endif
602 
603 
604  // -- Cluster non-unvoted coordinates
605  std::vector<size_t> coord3DId_V(coordinates3D.size(), 0);
606  size_t currentId = 1;
607 
608  // Initialize ID's in the first slice
609  coordinatesInSlice = getCoordinatesInSliceIndex(0);
610 
611  for(size_t i = 0; i < coordinatesInSlice.size(); i++)
612  {
613  coord3DId_V[coordinatesInSlice[i]] = currentId;
614  currentId++;
615  }
616 
617  // Extend ID's for coordinates in the whole volume
618  for (int k = 1; k < zSize; k++)
619  {
620  coordinatesInSlice_up = coordinatesInSlice;
621  coordinatesInSlice = getCoordinatesInSliceIndex(k);
622 
623  for(size_t i = 0; i < coordinatesInSlice.size(); i++)
624  {
625  Point3D<double> c = coordinates3D[coordinatesInSlice[i]];
626 
627  double match = false;
628  for (size_t j = 0; j < coordinatesInSlice_up.size(); j++)
629  {
630  Point3D<double> cu = coordinates3D[coordinatesInSlice_up[j]];
631  float distance2 = (c.x-cu.x)*(c.x-cu.x)+(c.y-cu.y)*(c.y-cu.y);
632 
633  if(distance2 < thrVottingDistance2)
634  {
635  coord3DId_V[coordinatesInSlice[i]] = coord3DId_V[coordinatesInSlice_up[j]];
636  match = true;
637  break;
638  }
639  }
640 
641  if (!match)
642  {
643  coord3DId_V[coordinatesInSlice[i]] = currentId;
644  currentId++;
645  }
646  }
647  }
648 
649 
650  #ifdef DEBUG_CLUSTER
651  std::cout << "coord3DId_V.size() " << coord3DId_V.size() << std::endl;
652 
653  for (size_t i = 0; i < coord3DId_V.size(); i++)
654  {
655  std::cout << coord3DId_V[i] << " ";
656  }
657  std::cout << std::endl;
658  #endif
659 
660 
661  #ifdef VERBOSE_OUTPUT
662  std::cout << "Number of clusters identified: " << (currentId-1) << std::endl;
663  #endif
664 
665  // -- Average coordinates with the same ID
666  std::vector<Point3D<double>> coordinates3D_avg;
667 
668  for (size_t id = 1; id < currentId; id++)
669  {
670  // Sum coordinate components with the same ID
671  Point3D<double> coord3D_avg(0,0,0);
672  int nCoords = 0;
673 
674  for (int n = 0; n < coord3DId_V.size(); n++)
675  {
676  if (coord3DId_V[n] == id)
677  {
678  coord3D_avg.x += coordinates3D[n].x;
679  coord3D_avg.y += coordinates3D[n].y;
680  coord3D_avg.z += coordinates3D[n].z;
681  nCoords++;
682 
683  coordinates3D.erase(coordinates3D.begin()+n);
684  coord3DId_V.erase(coord3DId_V.begin()+n);
685  n--;
686  }
687  }
688 
689  coord3D_avg.x /= nCoords;
690  coord3D_avg.y /= nCoords;
691  coord3D_avg.z /= nCoords;
692 
693  coordinates3D_avg.push_back(coord3D_avg);
694  }
695 
696  coordinates3D = coordinates3D_avg;
697 
698  #ifdef VERBOSE_OUTPUT
699  std::cout << "Number of coordinates obtained after clustering: " << coordinates3D.size() << std::endl;
700  std::cout << "Clustering of coordinates finished successfully!" << std::endl;
701  #endif
702 }
703 
704 
706 {
707  #ifdef VERBOSE_OUTPUT
708  std::cout << "Centering coordinates..." << std::endl;
709  #endif
710 
711  size_t numberOfFeatures = coordinates3D.size();
712 
713  MultidimArray<double> feature;
714  MultidimArray<double> mirrorFeature;
715  MultidimArray<double> correlationVolumeR;
716 
717  int coordHalfX;
718  int coordHalfY;
719  int coordHalfZ;
720 
721  int doubleBoxSize = boxSize * 2;
722 
723  for(size_t n = 0; n < numberOfFeatures; n++)
724  {
725  #ifdef DEBUG_CENTER_COORDINATES
726  std::cout << "-------------------- coordinate " << n << " (" << coordinates3D[n].x << ", " << coordinates3D[n].y << ", " << coordinates3D[n].z << ")" << std::endl;
727  #endif
728 
729  // Construct feature and its mirror symmetric. We quadruple the size to include a feature two times
730  // the box size plus padding to avoid incoherences in the shift sign
731  feature.initZeros(2 * doubleBoxSize, 2 * doubleBoxSize, 2 * doubleBoxSize);
732  mirrorFeature.initZeros(2 * doubleBoxSize, 2 * doubleBoxSize, 2 * doubleBoxSize);
733 
734  coordHalfX = coordinates3D[n].x - boxSize;
735  coordHalfY = coordinates3D[n].y - boxSize;
736  coordHalfZ = coordinates3D[n].z - boxSize;
737 
738  for(int k = 0; k < doubleBoxSize; k++) // zDim
739  {
740  for(int j = 0; j < doubleBoxSize; j++) // xDim
741  {
742  for(int i = 0; i < doubleBoxSize; i++) // yDim
743  {
744  // Check coordinate is not out of volume
745  if ((coordHalfZ + k) < 0 || (coordHalfZ + k) > zSize ||
746  (coordHalfY + i) < 0 || (coordHalfY + i) > ySize ||
747  (coordHalfX + j) < 0 || (coordHalfX + j) > xSize)
748  {
749  DIRECT_A3D_ELEM(feature, k + boxSize, i + boxSize, j + boxSize) = 0;
750 
751  DIRECT_A3D_ELEM(mirrorFeature, doubleBoxSize + boxSize -1 - k, doubleBoxSize + boxSize -1 - i, doubleBoxSize + boxSize -1 - j) = 0;
752  }
753  else
754  {
755  DIRECT_A3D_ELEM(feature, k + boxSize, i + boxSize, j + boxSize) = DIRECT_A3D_ELEM(volFiltered,
756  coordHalfZ + k,
757  coordHalfY + i,
758  coordHalfX + j);
759 
760  DIRECT_A3D_ELEM(mirrorFeature, doubleBoxSize + boxSize -1 - k, doubleBoxSize + boxSize -1 - i, doubleBoxSize + boxSize -1 - j) =
761  DIRECT_A3D_ELEM(volFiltered,
762  coordHalfZ + k,
763  coordHalfY + i,
764  coordHalfX + j);
765  }
766  }
767  }
768  }
769 
770  #ifdef DEBUG_CENTER_COORDINATES
771  Image<double> subtomo;
772 
773  std::cout << "Feature dimensions (" << XSIZE(feature) << ", " << YSIZE(feature) << ", " << ZSIZE(feature) << ")" << std::endl;
774  subtomo() = feature;
775  size_t lastindex = fnOut.find_last_of(".");
776  std::string rawname = fnOut.substr(0, lastindex);
777  std::string outputFileNameSubtomo;
778  outputFileNameSubtomo = rawname + "_" + std::to_string(n) + "_feature.mrc";
779  subtomo.write(outputFileNameSubtomo);
780 
781  std::cout << "Mirror feature dimensions (" << XSIZE(mirrorFeature) << ", " << YSIZE(mirrorFeature) << ", " << ZSIZE(mirrorFeature) << ")" << std::endl;
782  subtomo() = mirrorFeature;
783  outputFileNameSubtomo = rawname + "_" + std::to_string(n) + "_mirrorFeature.mrc";
784  subtomo.write(outputFileNameSubtomo);
785  #endif
786 
787  // Shift the particle respect to its symmetric to look for the maximum correlation displacement
788  CorrelationAux aux;
789  correlation_matrix(feature, mirrorFeature, correlationVolumeR, aux, true);
790 
791  auto maximumCorrelation = MINDOUBLE;
792  double xDisplacement = 0;
793  double yDisplacement = 0;
794  double zDisplacement = 0;
795 
796  FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(correlationVolumeR)
797  {
798  double value = DIRECT_A3D_ELEM(correlationVolumeR, k, i, j);
799 
800  if (value > maximumCorrelation)
801  {
802  maximumCorrelation = value;
803  xDisplacement = j;
804  yDisplacement = i;
805  zDisplacement = k;
806  }
807  }
808 
809  #ifdef DEBUG_CENTER_COORDINATES
810  std::cout << "maximumCorrelation " << maximumCorrelation << std::endl;
811  std::cout << "xDisplacement " << ((int) xDisplacement - doubleBoxSize) / 2 << std::endl;
812  std::cout << "yDisplacement " << ((int) yDisplacement - doubleBoxSize) / 2 << std::endl;
813  std::cout << "zDisplacement " << ((int) zDisplacement - doubleBoxSize) / 2 << std::endl;
814 
815  std::cout << "Correlation volume dimensions (" << XSIZE(correlationVolumeR) << ", " << YSIZE(correlationVolumeR) << ", " << ZSIZE(correlationVolumeR) << ")" << std::endl;
816  #endif
817 
818 
819  // Update coordinate and remove if it is moved out of the volume
820  double updatedCoordinateX = coordinates3D[n].x + ((int) xDisplacement - doubleBoxSize) / 2;
821  double updatedCoordinateY = coordinates3D[n].y + ((int) yDisplacement - doubleBoxSize) / 2;
822  double updatedCoordinateZ = coordinates3D[n].z + ((int) zDisplacement - doubleBoxSize) / 2;
823 
824  int deletedCoordinates = 0;
825 
826  if (updatedCoordinateZ < 0 || updatedCoordinateZ > zSize ||
827  updatedCoordinateY < 0 || updatedCoordinateY > ySize ||
828  updatedCoordinateX < 0 || updatedCoordinateX > xSize)
829  {
830  coordinates3D.erase(coordinates3D.begin()+n-deletedCoordinates);
831  deletedCoordinates++;
832  }
833  else
834  {
835  coordinates3D[n].x = updatedCoordinateX;
836  coordinates3D[n].y = updatedCoordinateY;
837  coordinates3D[n].z = updatedCoordinateZ;
838  }
839 
840  #ifdef DEBUG_CENTER_COORDINATES
841  // Construct and save the centered feature
842  MultidimArray<double> centerFeature;
843 
844  centerFeature.initZeros(doubleBoxSize, doubleBoxSize, doubleBoxSize);
845 
846  coordHalfX = coordinates3D[n].x - boxSize;
847  coordHalfY = coordinates3D[n].y - boxSize;
848  coordHalfZ = coordinates3D[n].z - boxSize;
849 
850  for(int k = 0; k < doubleBoxSize; k++) // zDim
851  {
852  for(int j = 0; j < doubleBoxSize; j++) // xDim
853  {
854  for(int i = 0; i < doubleBoxSize; i++) // yDim
855  {
856  // Check coordinate is not out of volume
857  if ((coordHalfZ + k) < 0 || (coordHalfZ + k) > zSize ||
858  (coordHalfY + i) < 0 || (coordHalfY + i) > ySize ||
859  (coordHalfX + j) < 0 || (coordHalfX + j) > xSize)
860  {
861  DIRECT_A3D_ELEM(centerFeature, k, i, j) = 0;
862  }
863  else
864  {
865  DIRECT_A3D_ELEM(centerFeature, k, i, j) = DIRECT_A3D_ELEM(volFiltered,
866  coordHalfZ + k,
867  coordHalfY + i,
868  coordHalfX + j);
869  }
870  }
871  }
872  }
873 
874  std::cout << "Centered feature dimensions (" << XSIZE(centerFeature) << ", " << YSIZE(centerFeature) << ", " << ZSIZE(centerFeature) << ")" << std::endl;
875 
876  subtomo() = centerFeature;
877  outputFileNameSubtomo = rawname + "_" + std::to_string(n) + "_centerFeature.mrc";
878  subtomo.write(outputFileNameSubtomo);
879  #endif
880  }
881 
882  #ifdef DEBUG_CENTER_COORDINATES
883  std::cout << "3D coordinates after centering: " << std::endl;
884 
885  for(size_t n = 0; n < numberOfFeatures; n++)
886  {
887  std::cout << "Coordinate " << n << " (" << coordinates3D[n].x << ", " << coordinates3D[n].y << ", " << coordinates3D[n].z << ")" << std::endl;
888 
889  }
890  #endif
891 
892  #ifdef VERBOSE_OUTPUT
893  std::cout << "Centering of coordinates finished successfully!" << std::endl;
894  #endif
895 }
896 
897 
899 {
900  #ifdef VERBOSE_OUTPUT
901  std::cout << "Removing duplicated coordinates..." << std::endl;
902  #endif
903 
904  double maxDistance = fiducialSizePx * fiducialSizePx;
905  size_t deletedCoordinates;
906 
907  #ifdef DEBUG_REMOVE_DUPLICATES
908  size_t iteration = 0;
909  std::cout << "maxDistance " << maxDistance << std::endl;
910  #endif
911 
912  do
913  {
914  #ifdef DEBUG_REMOVE_DUPLICATES
915  iteration +=1;
916  std::cout << "------------------------STARTING ITERATION " << iteration<< std::endl;
917  std::cout << "coordinates3D.size() " << coordinates3D.size() << std::endl;
918  #endif
919 
920  std::vector<Point3D<double>> newCoordinates3D;
921  size_t numberOfFeatures = coordinates3D.size();
922  std::vector<size_t> deleteCoordinatesVector(numberOfFeatures, 0);
923 
924  for(size_t i = 0; i < numberOfFeatures; i++)
925  {
926  for(size_t j = i+1; j < numberOfFeatures; j++)
927  {
928  double distance = (coordinates3D[i].x - coordinates3D[j].x) * (coordinates3D[i].x - coordinates3D[j].x) +
929  (coordinates3D[i].y - coordinates3D[j].y) * (coordinates3D[i].y - coordinates3D[j].y) +
930  (coordinates3D[i].z - coordinates3D[j].z) * (coordinates3D[i].z - coordinates3D[j].z);
931 
932  if (distance < maxDistance && deleteCoordinatesVector[i] == 0 && deleteCoordinatesVector[j] == 0)
933  {
934  Point3D<double> p((coordinates3D[i].x + coordinates3D[j].x)/2,
935  (coordinates3D[i].y + coordinates3D[j].y)/2,
936  (coordinates3D[i].z + coordinates3D[j].z)/2);
937  newCoordinates3D.push_back(p);
938 
939  #ifdef DEBUG_REMOVE_DUPLICATES
940  std::cout << "distance match between coordinates " << i << " and " << j << ": " << sqrt(distance) << std::endl;
941  std::cout << "Coordinate " << i << ": (" << coordinates3D[i].x << ", " << coordinates3D[i].y << ", " << coordinates3D[i].z << ")" << std::endl;
942  std::cout << "Coordinate " << j << ": (" << coordinates3D[j].x << ", " << coordinates3D[j].y << ", " << coordinates3D[j].z << ")" << std::endl;
943  std::cout << "Average coordinate: " << p.x << ", " << p.y << ", " << p.z << ")" << std::endl;
944  #endif
945 
946  deleteCoordinatesVector[i] = 1;
947  deleteCoordinatesVector[j] = 1;
948  }
949  }
950  }
951 
952  #ifdef DEBUG_REMOVE_DUPLICATES
953  std::cout << "coordinates3D.size() " << coordinates3D.size() << std::endl;
954  #endif
955 
956  deletedCoordinates = 0;
957  for (size_t i = 0; i < deleteCoordinatesVector.size(); i++)
958  {
959  if (deleteCoordinatesVector[i] == 1)
960  {
961  coordinates3D.erase(coordinates3D.begin()+i-deletedCoordinates);
962  deletedCoordinates++;
963  }
964  }
965 
966  #ifdef DEBUG_REMOVE_DUPLICATES
967  std::cout << "deletedCoordinates " << deletedCoordinates << std::endl;
968  std::cout << "coordinates3D.size() " << coordinates3D.size() << std::endl;
969  std::cout << "newCoordinates3D.size() " << newCoordinates3D.size() << std::endl;
970  #endif
971 
972  for (size_t i = 0; i < newCoordinates3D.size(); i++)
973  {
974  coordinates3D.push_back(newCoordinates3D[i]);
975  }
976 
977  #ifdef DEBUG_REMOVE_DUPLICATES
978  std::cout << "coordinates3D.size() " << coordinates3D.size() << std::endl;
979  #endif
980 
981  newCoordinates3D.clear();
982  }
983  while (deletedCoordinates>0);
984 
985  #ifdef DEBUG_REMOVE_DUPLICATES
986  // Construct and save the every coordinate after removing duplicates
987  size_t numberOfFeatures = coordinates3D.size();
988 
989  int coordHalfX;
990  int coordHalfY;
991  int coordHalfZ;
992 
993  int halfBoxSize = boxSize / 2;
994 
995  MultidimArray<double> feature;
996 
997  for(size_t n = 0; n < numberOfFeatures; n++)
998  {
999  feature.initZeros(boxSize, boxSize, boxSize);
1000 
1001  coordHalfX = coordinates3D[n].x - halfBoxSize;
1002  coordHalfY = coordinates3D[n].y - halfBoxSize;
1003  coordHalfZ = coordinates3D[n].z - halfBoxSize;
1004 
1005  for(int k = 0; k < boxSize; k++) // zDim
1006  {
1007  for(int j = 0; j < boxSize; j++) // xDim
1008  {
1009  for(int i = 0; i < boxSize; i++) // yDim
1010  {
1011  // Check coordinate is not out of volume
1012  if ((coordHalfZ + k) < 0 || (coordHalfZ + k) > zSize ||
1013  (coordHalfY + i) < 0 || (coordHalfY + i) > ySize ||
1014  (coordHalfX + j) < 0 || (coordHalfX + j) > xSize)
1015  {
1016  DIRECT_A3D_ELEM(feature, k, i, j) = 0;
1017  }
1018  else
1019  {
1020  DIRECT_A3D_ELEM(feature, k, i, j) = DIRECT_A3D_ELEM(volFiltered,
1021  coordHalfZ + k,
1022  coordHalfY + i,
1023  coordHalfX + j);
1024  }
1025  }
1026  }
1027  }
1028 
1029  Image<double> subtomo;
1030  subtomo() = feature;
1031  std::string outputFileNameSubtomo;
1032  size_t lastindex = fnOut.find_last_of(".");
1033  std::string rawname = fnOut.substr(0, lastindex);
1034  outputFileNameSubtomo = rawname + "_RD_" + std::to_string(n) + "_feature.mrc";
1035  subtomo.write(outputFileNameSubtomo);
1036  }
1037  #endif
1038 
1039  #ifdef DEBUG_REMOVE_DUPLICATES
1040  std::cout << "3D coordinates after removing duplicates: " << std::endl;
1041 
1042  for(size_t n = 0; n < numberOfFeatures; n++)
1043  {
1044  std::cout << "Coordinate " << n << " (" << coordinates3D[n].x << ", " << coordinates3D[n].y << ", " << coordinates3D[n].z << ")" << std::endl;
1045  }
1046  #endif
1047 
1048  #ifdef VERBOSE_OUTPUT
1049  std::cout << "Removing duplicated coordinates finished succesfully!" << std::endl;
1050  #endif
1051 }
1052 
1053 
1055 {
1056  #ifdef VERBOSE_OUTPUT
1057  std::cout << "Filter coordinates by correlation..." << std::endl;
1058  #endif
1059 
1060  // --- Filter coordinates mirror correlation ---
1061  size_t halfBoxSize = boxSize / 2;
1062 
1063  MultidimArray<double> feature;
1064  MultidimArray<double> mirrorFeature;
1065 
1066  double dotProductMirror = 0;
1067 
1068  int coordHalfX;
1069  int coordHalfY;
1070  int coordHalfZ;
1071 
1072  std::vector<Point3D<double>> newCoordinates3D;
1073 
1074  int numberOfCoordinates = coordinates3D.size();
1075 
1076  // --- Filter coordinates by correlation with mirror ---
1077  for(size_t n = 0; n < numberOfCoordinates; n++)
1078  {
1079  // Construct feature and its mirror symmetric
1080  feature.initZeros(boxSize, boxSize, boxSize);
1081  mirrorFeature.initZeros(boxSize, boxSize, boxSize);
1082 
1083  for(int k = 0; k < boxSize; k++) // zDim
1084  {
1085  for(int j = 0; j < boxSize; j++) // xDim
1086  {
1087  for(int i = 0; i < boxSize; i++) // yDim
1088  {
1089  coordHalfX = coordinates3D[n].x - halfBoxSize;
1090  coordHalfY = coordinates3D[n].y - halfBoxSize;
1091  coordHalfZ = coordinates3D[n].z - halfBoxSize;
1092 
1093  // Check coordinate is not out of volume
1094  if ((coordHalfZ + k) < 0 || (coordHalfZ + k) > zSize ||
1095  (coordHalfY + i) < 0 || (coordHalfY + i) > ySize ||
1096  (coordHalfX + j) < 0 || (coordHalfX + j) > xSize)
1097  {
1098  DIRECT_A3D_ELEM(feature, k, i, j) = 0;
1099 
1100  DIRECT_A3D_ELEM(mirrorFeature, boxSize -1 - k, boxSize -1 - i, boxSize -1 - j) = 0;
1101  }
1102  else
1103  {
1104  DIRECT_A3D_ELEM(feature, k, i, j) = DIRECT_A3D_ELEM(volFiltered,
1105  coordHalfZ + k,
1106  coordHalfY + i,
1107  coordHalfX + j);
1108 
1109  DIRECT_A3D_ELEM(mirrorFeature, boxSize -1 - k, boxSize -1 - i, boxSize -1 - j) =
1110  DIRECT_A3D_ELEM(volFiltered,
1111  coordHalfZ + k,
1112  coordHalfY + i,
1113  coordHalfX + j);
1114  }
1115  }
1116  }
1117  }
1118 
1119  feature.statisticsAdjust(0.0, 1.0);
1120  mirrorFeature.statisticsAdjust(0.0, 1.0);
1121 
1122  #ifdef DEBUG_FILTER_COORDINATES
1123  Image<double> subtomo;
1124 
1125  std::cout << "Feature dimensions (" << XSIZE(feature) << ", " << YSIZE(feature) << ", " << ZSIZE(feature) << ")" << std::endl;
1126  subtomo() = feature;
1127  size_t lastindex = fnOut.find_last_of(".");
1128  std::string rawname = fnOut.substr(0, lastindex);
1129  std::string outputFileNameSubtomo;
1130  outputFileNameSubtomo = rawname + "_" + std::to_string(n) + "_FC_feature.mrc";
1131  subtomo.write(outputFileNameSubtomo);
1132 
1133  std::cout << "Mirror feature dimensions (" << XSIZE(mirrorFeature) << ", " << YSIZE(mirrorFeature) << ", " << ZSIZE(mirrorFeature) << ")" << std::endl;
1134  subtomo() = mirrorFeature;
1135  outputFileNameSubtomo = rawname + "_" + std::to_string(n) + "_FC_mirrorFeature.mrc";
1136  subtomo.write(outputFileNameSubtomo);
1137  #endif
1138 
1139  // Calculate scalar product
1140  for(int k = 0; k < boxSize; k++) // zDim
1141  {
1142  for(int j = 0; j < boxSize; j++) // xDim
1143  {
1144  for(int i = 0; i < boxSize; i++) // yDim
1145  {
1146  dotProductMirror += DIRECT_A3D_ELEM(feature, k, i, j) * DIRECT_A3D_ELEM(mirrorFeature, k, i, j);
1147  }
1148  }
1149  }
1150 
1151  dotProductMirror /= boxSize * boxSize * boxSize;
1152 
1153  #ifdef DEBUG_FILTER_COORDINATES
1154  std::cout << "-------------------- coordinate " << n << " (" << coordinates3D[n].x << ", " << coordinates3D[n].y << ", " << coordinates3D[n].z << ")" << std::endl;
1155  std::cout << "dot product mirror: " << dotProductMirror << std::endl;
1156  #endif
1157 
1158  if (dotProductMirror > mirrorCorrelationThr)
1159  {
1160  newCoordinates3D.push_back(coordinates3D[n]);
1161  }
1162  else
1163  {
1164  #ifdef DEBUG_FILTER_COORDINATES
1165  std::cout << "Coordinate " << n << " removed. Mirror correlation: " << dotProductMirror << std::endl;
1166  #endif
1167  }
1168  }
1169 
1170  #ifdef DEBUG_FILTER_COORDINATES
1171  std::cout << "Number of corrdinates filtered by mirror correlation: " << (coordinates3D.size() - newCoordinates3D.size()) << std::endl;
1172  #endif
1173 
1174  // --- Filter coordinates by radial average Mahalanobis distante ---
1175  if (!newCoordinates3D.empty()) // Check if any coordinate have survived the previous filter
1176  {
1177  numberOfCoordinates = newCoordinates3D.size();
1178 
1179  MultidimArray<float> feature_float;
1180  MultidimArray<float> feature_RA;
1181  MultidimArray<double> mahalanobisDistance_List(numberOfCoordinates);
1182 
1183  std::vector<MultidimArray<float>> setOfFeatures_RA(numberOfCoordinates);
1184 
1185  int numAvgSlices = (boxSize*0.25);
1186  int halfNumberAvgSlices = numAvgSlices/2;
1187 
1188  // Calculate radial average of every feature
1189  #ifdef DEBUG_FILTER_COORDINATES
1190  std::cout << "Calculate radial averages " << std::endl;
1191  #endif
1192 
1193  for(size_t n = 0; n < numberOfCoordinates; n++)
1194  {
1195  #ifdef DEBUG_FILTER_COORDINATES
1196  std::cout << "Calculating radial average of coordinate " << n << std::endl;
1197  #endif
1198 
1199  feature_RA.initZeros(halfBoxSize);
1200  feature_float.initZeros(2*halfNumberAvgSlices, boxSize, boxSize);
1201 
1202  for(int k = 0; k < numAvgSlices; k++) // zDim
1203  {
1204  for(int j = 0; j < boxSize; j++) // xDim
1205  {
1206  for(int i = 0; i < boxSize; i++) // yDim
1207  {
1208  coordHalfX = newCoordinates3D[n].x - halfBoxSize;
1209  coordHalfY = newCoordinates3D[n].y - halfBoxSize;
1210  coordHalfZ = newCoordinates3D[n].z - halfNumberAvgSlices;
1211 
1212  // Check coordinate is not out of volume
1213  if (!((coordHalfZ + k) < 0 || (coordHalfZ + k) > zSize ||
1214  (coordHalfY + i) < 0 || (coordHalfY + i) > ySize ||
1215  (coordHalfX + j) < 0 || (coordHalfX + j) > xSize))
1216  {
1217  DIRECT_A3D_ELEM(feature_float, k, i, j) = (float)DIRECT_A3D_ELEM(volFiltered,
1218  coordHalfZ + k,
1219  coordHalfY + i,
1220  coordHalfX + j);
1221  }
1222  }
1223  }
1224  }
1225 
1226  feature_float.statisticsAdjust(0.0, 1.0);
1227 
1228  #ifdef DEBUG_FILTER_COORDINATES
1229  std::cout << "Feature_float dimensions: (" << XSIZE(feature_float) << ", " << YSIZE(feature_float) << ", " << ZSIZE(feature_float) << ")" << std::endl;
1230  #endif
1231 
1232  radialAverage(feature_float, feature_RA, numAvgSlices);
1233  setOfFeatures_RA[n] =feature_RA;
1234  }
1235 
1236  #ifdef DEBUG_FILTER_COORDINATES
1237  std::cout << "Calculate mahalanobis distance " << std::endl;
1238  size_t prevNumberOfCoordinates = newCoordinates3D.size();
1239  #endif
1240 
1241  mahalanobisDistance(setOfFeatures_RA, mahalanobisDistance_List);
1242 
1243  #ifdef DEBUG_FILTER_COORDINATES
1244  for (size_t n = 0; n < setOfFeatures_RA.size(); n++)
1245  {
1246  std::cout << "pcaAnalyzer.getZscore(" << n << ") " << mahalanobisDistance_List[n] << std::endl;
1247  }
1248  #endif
1249 
1250  size_t n_bis = 0;
1251 
1252  for (size_t n = 0; n < numberOfCoordinates; n++)
1253  {
1254  #ifdef DEBUG_FILTER_COORDINATES
1255  Point3D<double> p = newCoordinates3D[n];
1256  #endif
1257 
1258  if (mahalanobisDistance_List[n_bis] > mahalanobisDistanceThr)
1259  {
1260  #ifdef DEBUG_FILTER_COORDINATES
1261  std::cout << "Deleted coordinate due to mahalanobis distance " << n << " at: (" << p.x << ", " << p.y << ", " << p.z << ")" << std::endl;
1262  #endif
1263 
1264  newCoordinates3D.erase(newCoordinates3D.begin()+n);
1265  numberOfCoordinates--;
1266  n--;
1267  }
1268 
1269  n_bis++;
1270  }
1271 
1272  #ifdef DEBUG_FILTER_COORDINATES
1273  std::cout << "Number of corrdinates filtered by mahalanobis distance correlation: " << (prevNumberOfCoordinates - newCoordinates3D.size()) << std::endl;
1274  #endif
1275  }
1276 
1277  // --- Evaluate relaxed mode ---
1278  if (relaxedMode==false)
1279  {
1280  if (newCoordinates3D.size()<=relaxedModeThr)
1281  {
1282  coordinates3D.clear();
1283  coordinates3D = newCoordinates3D;
1284  }
1285  }
1286  else
1287  {
1288  coordinates3D.clear();
1289  coordinates3D = newCoordinates3D;
1290  }
1291 
1292  // --- Remove coordinates out of volume (any pixel from the box) ---
1293  numberOfCoordinates = coordinates3D.size();
1294 
1295  for (size_t i = 0; i < numberOfCoordinates; i++)
1296  {
1297  Point3D<double> p = coordinates3D[i];
1298 
1299  std::cout << "Analyzing coordinate " << i << std::endl;
1300 
1301  if ((p.z < halfBoxSize) || (p.z + halfBoxSize) > zSize ||
1302  (p.y < halfBoxSize) || (p.y + halfBoxSize) > ySize ||
1303  (p.x < halfBoxSize) || (p.x + halfBoxSize) > xSize)
1304  {
1305  #ifdef DEBUG_FILTER_COORDINATES
1306  std::cout << "Deleted border coordinate " << i << " at: (" << p.x << ", " << p.y << ", " << p.z << ")" << std::endl;
1307  #endif
1308 
1309  coordinates3D.erase(coordinates3D.begin()+i);
1310  numberOfCoordinates--;
1311  i--;
1312  }
1313  }
1314 
1315  #ifdef DEBUG_FILTER_COORDINATES
1316  std::cout << "3D coordinates after filtering: " << std::endl;
1317 
1318  for(size_t n = 0; n < coordinates3D.size(); n++)
1319  {
1320  std::cout << "Coordinate " << n << " (" << coordinates3D[n].x << ", " << coordinates3D[n].y << ", " << coordinates3D[n].z << ")" << std::endl;
1321  }
1322  #endif
1323 
1324  #ifdef VERBOSE_OUTPUT
1325  std::cout << "Filtering coordinates by correlation finished succesfully!" << std::endl;
1326  #endif
1327 }
1328 
1329 
1330 
1331 // --------------------------- MAIN ----------------------------------
1332 
1334 {
1335  using std::chrono::high_resolution_clock;
1336  using std::chrono::duration_cast;
1337  using std::chrono::duration;
1338  using std::chrono::milliseconds;
1339 
1340  auto t1 = high_resolution_clock::now();
1341 
1342  generateSideInfo();
1343 
1344  V.read(fnVol);
1345 
1346  MultidimArray<double> &inputTomo=V();
1347 
1348  xSize = XSIZE(inputTomo);
1349  ySize = YSIZE(inputTomo);
1350  zSize = ZSIZE(inputTomo);
1351  nSize = NSIZE(inputTomo);
1352 
1353  #ifdef DEBUG_DIM
1354  std::cout << "------------------ Input tomogram dimensions:" << std::endl;
1355  std::cout << "x " << xSize << std::endl;
1356  std::cout << "y " << ySize << std::endl;
1357  std::cout << "z " << zSize << std::endl;
1358  std::cout << "n " << nSize << std::endl;
1359  #endif
1360 
1361  preprocessVolume(inputTomo);
1362 
1363  #ifdef DEBUG_DIM
1364  std::cout << "------------------ Preprocessed tomogram dimensions:" << std::endl;
1365  std::cout << "x " << xSize << std::endl;
1366  std::cout << "y " << ySize << std::endl;
1367  std::cout << "z " << zSize << std::endl;
1368  std::cout << "n " << nSize << std::endl;
1369  #endif
1370 
1371  getHighContrastCoordinates(inputTomo);
1372 
1373  clusterHCC();
1374 
1375  // Read again volume (original tomogram is needed, at this point it is labeled)
1376  V.read(fnVol);
1377  inputTomo=V();
1378 
1379  centerCoordinates(inputTomo);
1380 
1382 
1383  filterCoordinatesByCorrelation(inputTomo);
1384 
1386 
1387  auto t2 = high_resolution_clock::now();
1388  auto ms_int = duration_cast<milliseconds>(t2 - t1); // Getting number of milliseconds as an integer
1389 
1390  std::cout << "Execution time: " << ms_int.count() << std::endl;
1391  std::cout << "Program executed succesfully!" << "ms" << std::endl;
1392 }
1393 
1394 
1395 
1396 // --------------------------- UTILS FUNCTIONS ----------------------------
1397 
1399 {
1400  #ifdef VERBOSE_OUTPUT
1401  std::cout << "Generating side info..." << std::endl;
1402  #endif
1403 
1405 
1406  #ifdef VERBOSE_OUTPUT
1407  std::cout << "Side info generated successfully!" << std::endl;
1408  #endif
1409 }
1410 
1411 
1412 bool ProgImagePeakHighContrast::filterLabeledRegions(std::vector<int> coordinatesPerLabelX, std::vector<int> coordinatesPerLabelY, double centroX, double centroY) const
1413 {
1414  #ifdef DEBUG_FILTERLABEL
1415  // // Uncomment for phantom
1416  // std::cout << "No label filtering, phantom mode!" << std::endl;
1417  // return true;
1418  #endif
1419 
1420  // Check number of elements of the label
1421  if(coordinatesPerLabelX.size() < numberOfCoordinatesThr)
1422  {
1423  return false;
1424  }
1425 
1426  // Calculate the furthest point of the region from the centroid
1427  double maxSquareDistance = 0;
1428  double distance;
1429 
1430  #ifdef DEBUG_FILTERLABEL
1431  size_t debugN;
1432  #endif
1433 
1434  for(size_t n = 0; n < coordinatesPerLabelX.size(); n++)
1435  {
1436  distance = (coordinatesPerLabelX[n]-centroX)*(coordinatesPerLabelX[n]-centroX)+(coordinatesPerLabelY[n]-centroY)*(coordinatesPerLabelY[n]-centroY);
1437 
1438  if(distance >= maxSquareDistance)
1439  {
1440  #ifdef DEBUG_FILTERLABEL
1441  debugN = n;
1442  #endif
1443 
1444  maxSquareDistance = distance;
1445  }
1446  }
1447 
1448  double maxDistace;
1449  maxDistace = sqrt(maxSquareDistance);
1450 
1451  // Check sphericity of the labeled region
1452  double circumscribedArea = PI * (maxDistace * maxDistace);
1453  double area = 0.0 + (double)coordinatesPerLabelX.size();
1454  double ocupation;
1455 
1456  ocupation = area / circumscribedArea;
1457 
1458  #ifdef DEBUG_FILTERLABEL
1459  std::cout << "debugN " << debugN << std::endl;
1460  std::cout << "x max distance " << coordinatesPerLabelX[debugN] << std::endl;
1461  std::cout << "y max distance " << coordinatesPerLabelY[debugN] << std::endl;
1462  std::cout << "centroX " << centroX << std::endl;
1463  std::cout << "centroY " << centroY << std::endl;
1464  std::cout << "area " << area << std::endl;
1465  std::cout << "circumscribedArea " << circumscribedArea << std::endl;
1466  std::cout << "maxDistace " << maxDistace << std::endl;
1467  std::cout << "ocupation " << ocupation << std::endl;
1468  #endif
1469 
1470  if(ocupation < 0.75)
1471  {
1472  #ifdef DEBUG_FILTERLABEL
1473  std::cout << "COORDINATE REMOVED AT " << centroX << " , " << centroY << " BECAUSE OF OCCUPATION"<< std::endl;
1474  #endif
1475  return false;
1476  }
1477 
1478  return true;
1479 }
1480 
1481 
1483 {
1484  std::vector<size_t> coordinatesInSlice;
1485 
1486  #ifdef DEBUG_COORDS_IN_SLICE
1487  std::cout << "Geting coordinates from slice " << slice << std::endl;
1488  #endif
1489 
1490  for(size_t n = 0; n < coordinates3D.size(); n++)
1491  {
1492  if(slice == coordinates3D[n].z)
1493  {
1494  coordinatesInSlice.push_back(n);
1495  }
1496  }
1497 
1498  #ifdef DEBUG_COORDS_IN_SLICE
1499  std::cout << "Number of coordinates found: " << coordinatesInSlice.size() << std::endl;
1500  #endif
1501 
1502  return coordinatesInSlice;
1503 }
1504 
1505 
1507 {
1508  #ifdef DEBUG_RADIAL_AVERAGE
1509  std::cout << "Calculating radial average..." << std::endl;
1510  #endif
1511 
1512  MultidimArray<int> counter(boxSize/2);
1513  counter.initZeros();
1514 
1515  for(int k=0; k<numSlices; k++) // Zdim
1516  {
1517  for(int i=0; i<boxSize; i++) // Xdim
1518  {
1519  double ii = i-(boxSize/2);
1520  double i2 = ii*ii;
1521 
1522  for(int j=0; j<boxSize; j++) // Ydim
1523  {
1524  double jj = j-(boxSize/2);
1525  int f = sqrt(i2 + jj*jj);
1526 
1527  if (f<(boxSize/2))
1528  {
1529  DIRECT_A1D_ELEM(radialAverage, f) += DIRECT_A3D_ELEM(feature, k, i, j);
1530  DIRECT_A1D_ELEM(counter, f) += 1;
1531  }
1532  }
1533  }
1534  }
1535 
1536  #ifdef DEBUG_RADIAL_AVERAGE
1537  std::cout << "Radial summatory" << std::endl;
1538  for (size_t i = 0; i < boxSize/2; i++)
1539  {
1540  std::cout << radialAverage[i] << " ";
1541  }
1542 
1543  std::cout << std::endl;
1544 
1545  std::cout << "Radial average" << std::endl;
1546  #endif
1547 
1548  for (size_t i = 0; i < boxSize/2; i++)
1549  {
1550  radialAverage[i] /= counter[i];
1551 
1552  #ifdef DEBUG_RADIAL_AVERAGE
1553  std::cout << radialAverage[i] << " ";
1554  #endif
1555  }
1556 
1557  #ifdef DEBUG_RADIAL_AVERAGE
1558  std::cout << std::endl;
1559  std::cout << "Number of elements per radius" << std::endl;
1560 
1561  for (size_t i = 0; i < boxSize/2; i++)
1562  {
1563  std::cout << counter[i] << " ";
1564  }
1565 
1566  std::cout << std::endl;
1567  #endif
1568 }
1569 
1570 
1571 void ProgImagePeakHighContrast::mahalanobisDistance(std::vector<MultidimArray<float>> &setOfFeatures_RA, MultidimArray<double> &mahalanobisDistance_List) const
1572 {
1573  #ifdef DEBUG_MAHALANOBIS_DISTANCE
1574  std::cout << "Calculating Mahalanobis distance..." << std::endl;
1575  #endif
1576 
1577  PCAMahalanobisAnalyzer pcaAnalyzer;
1578 
1579  for (size_t n = 0; n < setOfFeatures_RA.size(); n++)
1580  {
1581  #ifdef DEBUG_MAHALANOBIS_DISTANCE
1582  std::cout << "Adding vector " << n << std::endl;
1583  #endif
1584 
1585  pcaAnalyzer.addVector(setOfFeatures_RA[n]);
1586  }
1587 
1588  pcaAnalyzer.learnPCABasis(2, 200);
1589  pcaAnalyzer.evaluateZScore(2, 200, false); // int NPCA, int Niter, bool trained NO, const char* fileName, int numdesc
1590 
1591  #ifdef DEBUG_MAHALANOBIS_DISTANCE
1592  std::cout << "Zscore list of vertors" << std::endl;
1593  #endif
1594 
1595  for (size_t n = 0; n < setOfFeatures_RA.size(); n++)
1596  {
1597  #ifdef DEBUG_MAHALANOBIS_DISTANCE
1598  std::cout << "pcaAnalyzer.getZscore(" << n << ") " << pcaAnalyzer.getZscore(n) << std::endl;
1599  #endif
1600 
1601  mahalanobisDistance_List[n] = pcaAnalyzer.getZscore(n);
1602  }
1603 }
#define NSIZE(v)
#define YSIZE(v)
void addVector(const MultidimArray< float > &_v)
Add vector.
Definition: basic_pca.h:100
void mahalanobisDistance(std::vector< MultidimArray< float >> &setOfFeatures_RA, MultidimArray< double > &mahalanobisDistance_List) const
double getDoubleParam(const char *param, int arg=0)
void inverseFourierTransform()
Definition: xmipp_fftw.cpp:329
n The following was calculated during iteration
void getSlice(int k, MultidimArray< T1 > &M, char axis='Z', bool reverse=false, size_t n=0) const
doublereal * c
void * cd
void sqrt(Image< double > &op)
double getZscore(int n)
Definition: basic_pca.h:140
static double * y
#define DIRECT_A2D_ELEM(v, i, j)
void write(const FileName &name="", size_t select_img=ALL_IMAGES, bool isStack=false, int mode=WRITE_OVERWRITE, CastWriteMode castMode=CW_CAST, int _swapWrite=0)
void correlation_matrix(const MultidimArray< double > &m1, const MultidimArray< double > &m2, MultidimArray< double > &R, CorrelationAux &aux, bool center)
Definition: xmipp_fftw.cpp:869
doublereal * w
void preprocessVolume(MultidimArray< double > &inputTomo)
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(V)
doublereal * x
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
void filterCoordinatesByCorrelation(MultidimArray< double > volFiltered)
#define DIRECT_A1D_ELEM(v, i)
void centerCoordinates(MultidimArray< double > volFiltered)
const char * getParam(const char *param, int arg=0)
T z
Definition: point3D.h:56
void evaluateZScore(int NPCA, int Niter, bool trained=false, const char *filename="temp.txt", int numdesc=0)
Definition: basic_pca.cpp:384
bool setValue(const MDObject &mdValueIn, size_t id)
size_t addObject() override
double * f
X component (int)
void getHighContrastCoordinates(MultidimArray< double > &volFiltered)
void radialAverage(MultidimArray< float > &feature, MultidimArray< float > &radialAverage, size_t numSlices) const
#define XSIZE(v)
T x
Definition: point3D.h:54
#define ZSIZE(v)
double z
#define DIRECT_MULTIDIM_ELEM(v, n)
#define DIRECT_A3D_ELEM(v, k, i, j)
void FourierTransform(T &v, T1 &V, bool getCopy=true)
Definition: xmipp_fftw.h:166
__device__ float FFT_IDX2DIGFREQ(int idx, int size)
#define j
Z component (int)
std::vector< size_t > getCoordinatesInSliceIndex(size_t slice)
TYPE distance(struct Point_T *p, struct Point_T *q)
Definition: point.cpp:28
int labelImage2D(const MultidimArray< double > &I, MultidimArray< double > &label, int neighbourhood)
Definition: filters.cpp:648
bool filterLabeledRegions(std::vector< int > coordinatesPerLabelX, std::vector< int > coordinatesPerLabelY, double centroX, double centroY) const
#define DIRECT_ZYX_ELEM(v, k, i, j)
doublereal * u
void learnPCABasis(size_t NPCA, size_t Niter)
Learn basis.
Definition: basic_pca.cpp:170
bool checkParam(const char *param)
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false, int mode=WRITE_READONLY)
Y component (int)
std::string to_string(bond_type bondType)
Definition: compound.cpp:43
void addUsageLine(const char *line, bool verbatim=false)
void initZeros(const MultidimArray< T1 > &op)
#define PI
Definition: tools.h:43
int getIntParam(const char *param, int arg=0)
int * n
void addParamsLine(const String &line)
T y
Definition: point3D.h:55
void statisticsAdjust(U avgF, U stddevF)
double * delta