Xmipp  v3.23.11-Nereus
align_tilt_pairs.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  *
3  * Authors: Carlos Oscar Sorzano (coss@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 #include "align_tilt_pairs.h"
26 
27 #include "core/geometry.h"
28 #include "core/matrix2d.h"
29 #include "core/metadata_vec.h"
30 #include "core/transformations.h"
31 #include "core/xmipp_image.h"
32 #include "data/filters.h"
33 
34 //#define DEBUG
35 
36 //Define Program parameters
38 {
39  //Usage
40  addUsageLine("Center the tilted images of all tilted-untilted image pairs.");
41  addUsageLine("+This program receives as input a metadata with two sets of images, untilted and tilted.");
42  addUsageLine("+Untilted images must have been previously classified and aligned. Then, the tilted images");
43  addUsageLine("+are aligned to their untilted versions. The alignment parameters from the classification plus");
44  addUsageLine("+the alignment parameters from the tilted-untilted comparison are used to deduce the 3D");
45  addUsageLine("+alignment parameters for the tilted images.");
46 
47  //Examples
48  addExampleLine("To center tilted images allowing a maximum shift of 10 pixels:",false);
49  addExampleLine("xmipp_align_tilt_pairs -i class_00001@classes.xmd -o alignedImages.xmd --max_shift 10");
50 
51  // Params
52  addParamsLine(" -i <metadata> : Input metadata with untilted and tilted images");
53  addParamsLine(" -o <metadata> : Output metadata file with rotations & translations for 3D reconstruction.");
54  addParamsLine(" --ref <file> : 2D average of the untilted images");
55  addParamsLine(" [--max_shift <value=10>] : Discard images shifting more than a given threshold (in percentage of the image size).");
56  addParamsLine(" :+Set it to 0 for no shift estimate between tilted and untilted images");
57  addParamsLine(" [--do_stretch] : Stretch tilted image to fit into the untilted one.");
58  addParamsLine(" :+Do it only with thin particles");
59  addParamsLine(" [--do_not_align_tilted] : Do not align tilted images to untilted ones.");
60  addParamsLine(" :+Do not align if the quality of the tilted images is low.");
61 }
62 
63 //Read params
65 {
66  fnIn = getParam("-i");
67  fnOut = getParam("-o");
68  fnRef = getParam("--ref");
69  max_shift = getDoubleParam("--max_shift");
70  do_stretch = checkParam("--do_stretch");
71  do_not_align_tilted = checkParam("--do_not_align_tilted");
72 }
73 
74 // Show ====================================================================
76 {
77  std::cout
78  << "Input metadata: " << fnIn << std::endl
79  << "Output metadata: " << fnOut << std::endl
80  << "Reference image: " << fnRef << std::endl;
81  if (max_shift != 0)
82  std::cout
83  << "Discard images that shift more than: " << max_shift << std::endl;
84  if (do_stretch)
85  std::cout << "Stretching tilted images\n";
86 }
87 
88 // Center one tilted image =====================================================
89 //#define DEBUG
91  bool flip,
92  double inPlaneU, double shiftXu, double shiftYu,
93  double alphaT, double alphaU,
94  double tilt, const MultidimArray<double> &imgT, double &shiftX,
95  double &shiftY, CorrelationAux &auxCorr)
96 {
97  // Cosine stretching, store stretched image in imgT2DClass
98  MultidimArray<double> imgT2DClass;
99  Matrix2D<double> E, E2D, Mu2D, A2D;
100 
101  if (!do_stretch)
102  tilt = flip ? 180. : 0.;
103 
104  Euler_angles2matrix(flip ? alphaU : -alphaU, tilt, alphaT, E, true);
105 
106  rotation2DMatrix(inPlaneU, Mu2D, true);
107  MAT_ELEM(Mu2D,0,2) = flip ? shiftXu : -shiftXu;
108  MAT_ELEM(Mu2D,1,2) = -shiftYu;
109 
110  if (flip)
111  {
112  // We need to multiply the first column by -1, because
113  // in Xmipp the Mu2D order is: first flip (if necessary), then rot, then shift
114  //MAT_ELEM(Mu2D,0,0)*=-1;
115 
116  MAT_ELEM(Mu2D,1,0)*=-1;
117  MAT_ELEM(Mu2D,2,0)*=-1;
118 
119  // We need to multiply the first row by -1, as needed by the RCT theory
120  MAT_ELEM(Mu2D,0,1)*=-1;
121  MAT_ELEM(Mu2D,0,2)*=-1;
122  }
123 
124  E2D.initIdentity(3);
125  MAT_ELEM(E2D,0,0)=MAT_ELEM(E,0,0);
126  MAT_ELEM(E2D,0,1)=MAT_ELEM(E,0,1);
127  MAT_ELEM(E2D,1,0)=MAT_ELEM(E,1,0);
128  MAT_ELEM(E2D,1,1)=MAT_ELEM(E,1,1);
129  A2D = Mu2D * E2D.inv();
130 
131  applyGeometry(xmipp_transformation::LINEAR, imgT2DClass, imgT, A2D, xmipp_transformation::IS_NOT_INV, xmipp_transformation::WRAP);
132 
133  // Calculate best shift
134  auto max_shift_pixels=(int)(max_shift/100.0*XSIZE(imgT));
135  CorrelationAux aux;
136  double corr=bestShift(imgRefU, imgT2DClass, shiftX, shiftY, auxCorr, nullptr, max_shift_pixels);
137  // double corr=bestShiftRealSpace(imgRefU, imgT2DClass, shiftX, shiftY, NULL, max_shift_pixels, 0.5);
138 
139 #ifdef DEBUG
140 
141  std::cout << "alphaU=" << alphaU << " inplaneU=" << inPlaneU << " tilt=" << tilt << " alphaT=" << alphaT << std::endl;
142  std::cout << "Best shift= " << shiftX << " " << shiftY << " corr=" << corr << std::endl;
143 #endif
144 
145  Matrix1D<double> vShift(2);
146  XX(vShift)=shiftX;
147  YY(vShift)=shiftY;
148  Matrix2D<double> Tt, Tt2D;
149  translation2DMatrix(vShift, Tt2D,true);
150  Tt=A2D.inv()*Tt2D.inv()*A2D;
151 
152  // Readjust shift
153  shiftX=MAT_ELEM(Tt,0,2);
154  shiftY=MAT_ELEM(Tt,1,2);
155  double shift = sqrt(shiftX * shiftX + shiftY * shiftY);
156 
157 //#define DEBUG_2
158 #ifdef DEBUG_2
159 
160  Image<double> save;
161  save() = imgT;
162  save.write("PPPtilted.xmp");
163  save() = imgRefU;
164  save.write("PPPuntiltedRef.xmp");
165  save() = imgT2DClass;
166  save.write("PPPtiltedAdjusted.xmp");
167  std::cout << "Corrected shift= " << shiftX << " " << shiftY << std::endl;
168  std::cout << "Press any key\n";
169  char c = getchar();
170 #endif
171 
172  return (shift < (double)max_shift_pixels) || corr<0;
173 }
174 //#undef DEBUG
175 
176 // Main program ===============================================================
178 {
179  Image<double> imgT;
181  Matrix2D<double> A(3, 3);
182 
183  MetaDataVec mdIn, mdOut;
184  mdIn.read(fnIn);
185  mdIn.removeDisabled();
186  if (!mdIn.containsLabel(MDL_ANGLE_TILT))
187  REPORT_ERROR(ERR_ARG_INCORRECT,"Input metadata does not have tilt information");
188 
189  initProgress(mdIn.size());
190 
191  Image<double> imgRef;
192  imgRef.read(fnRef);
193  imgRef().setXmippOrigin();
194 
195  size_t imgno = 0;
196  FileName fnTilted, fnUntilted;
197 
198  double alphaU, alphaT, tilt, inPlaneU, minusInPlaneU;
199  size_t nDiscarded = 0;
200  Matrix2D<double> E, Tu, Tup;
201  Matrix1D<double> vShift(3);
202  vShift.initZeros();
203  CorrelationAux auxCorr;
204  bool flip;
205 
206  for (const auto& row : mdIn)
207  {
208  row.getValue(MDL_FLIP, flip);
209  // Read untilted and tilted images
210  row.getValue(MDL_ANGLE_PSI, inPlaneU);
211  row.getValue(MDL_IMAGE, fnUntilted);
212  row.getValue(MDL_IMAGE_TILTED, fnTilted);
213  imgT.read(fnTilted);
214  imgT().setXmippOrigin();
215 
216 
217 #ifdef DEBUG
218  {
219  Image<double> imgU;
220  imgU.read(fnUntilted);
221  imgU().setXmippOrigin();
222  Image<double> save;
223  save() = imgU();
224  save.write("PPPuntilted.xmp");
226  save.readApplyGeo(fnUntilted, row);
227  save.write("PPPuntiltedAligned.xmp");
228  geo2TransformationMatrix(row, E);
229  //rotation2DMatrix(-inPlaneU,E);
230  //save() = imgU();
231  //applyGeometry(LINEAR, save(), imgU(), E, IS_NOT_INV, WRAP);
232  //save.write("PPPuntiltedAligned2.xmp");
233  }
234 #endif
235 
236  // Get alignment parameters
237  double shiftXu, shiftYu;
238  row.getValue(MDL_ANGLE_Y, alphaU);
239  row.getValue(MDL_ANGLE_Y2, alphaT);
240  row.getValue(MDL_ANGLE_TILT, tilt);
241  row.getValue(MDL_SHIFT_X, shiftXu);
242  row.getValue(MDL_SHIFT_Y, shiftYu);
243 
244  if (flip)
245  {
246  tilt += 180;
247  minusInPlaneU = inPlaneU+alphaU;
248  }
249  else
250  minusInPlaneU=-(inPlaneU+alphaU);
251 
252  // Correct untilted alignment
253  Euler_angles2matrix( minusInPlaneU, tilt, alphaT, E, true);
254  XX(vShift) = shiftXu;
255  YY(vShift) = shiftYu;
256  translation3DMatrix(vShift, Tu);
257  Tup = E * Tu * E.inv();
258 
259  // Align tilt and untilted projections
260  double shiftX = 0, shiftY = 0;
261  bool enable = true;
262  if (max_shift > 0)
263  enable = centerTiltedImage(imgRef(), flip, inPlaneU, shiftXu, shiftYu,
264  alphaT, alphaU, tilt, imgT(), shiftX, shiftY, auxCorr);
265  if (!enable)
266  {
267  ++nDiscarded;
268  shiftX = shiftY = 0;
269  }
270 
271  // Write results
272  MDRowVec rowOut;
273  rowOut.setValue(MDL_IMAGE, fnTilted);
274  rowOut.setValue(MDL_ANGLE_ROT, minusInPlaneU);
275  rowOut.setValue(MDL_ANGLE_TILT, tilt);
276  rowOut.setValue(MDL_ANGLE_PSI, alphaT);
277  rowOut.setValue(MDL_SHIFT_X, -MAT_ELEM(Tup,0,3) + shiftX);
278  rowOut.setValue(MDL_SHIFT_Y, -MAT_ELEM(Tup,1,3) + shiftY);
279  rowOut.setValue(MDL_ENABLED, (int) enable);
280  mdOut.addRow(rowOut);
281 
282  setProgress(++imgno);
283  }
284 
285  if (verbose && nDiscarded)
286  std::cout << " Discarded " << nDiscarded
287  << " tilted images that shifted too much" << std::endl;
288 
289  // Write out selfile
290  mdOut.write(fnOut);
291 }
292 
Rotation angle of an image (double,degrees)
bool centerTiltedImage(const MultidimArray< double > &imgU, bool flip, double inPlaneU, double shiftXu, double shiftYu, double alphaT, double alphaU, double tilt, const MultidimArray< double > &imgT, double &shiftX, double &shiftY, CorrelationAux &auxCorr)
Center one tilted image.
void run()
Run over the whole input metadata.
double getDoubleParam(const char *param, int arg=0)
template void translation2DMatrix(const Matrix1D< float > &, Matrix2D< float > &, bool inverse)
void read(const FileName &inFile, const std::vector< MDLabel > *desiredLabels=nullptr, bool decomposeStack=true) override
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
void geo2TransformationMatrix(const MDRow &imageGeo, Matrix2D< double > &A, bool only_apply_shifts)
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
void sqrt(Image< double > &op)
Tilting angle of an image (double,degrees)
void setValue(const MDObject &object) override
Shift for the image in the X axis (double)
void applyGeometry(int SplineDegree, MultidimArray< std::complex< double > > &V2, const MultidimArray< std::complex< double > > &V1, const Matrix2D< double > &A, bool inv, bool wrap, std::complex< double > outside, MultidimArray< double > *BcoeffsPtr)
void initProgress(size_t total, size_t stepBin=60)
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 inv(Matrix2D< T > &result) const
Definition: matrix2d.cpp:663
Special label to be used when gathering MDs in MpiMetadataPrograms.
void write(const FileName &outFile, WriteModeMetaData mode=MD_OVERWRITE) const
Name of the tilted images associated to MDL_IMAGE.
Angle between y-axis and tilt-axis (double, degrees) for tilted micrographs.
int readApplyGeo(const FileName &name, const MDRow &row, const ApplyGeoParams &params=DefaultApplyGeoParams)
size_t size() const override
Is this image enabled? (int [-1 or 1])
size_t addRow(const MDRow &row) override
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
const char * getParam(const char *param, int arg=0)
#define XX(v)
Definition: matrix1d.h:85
template void translation3DMatrix(const Matrix1D< float > &translation, Matrix2D< float > &resMatrix, bool inverse)
Incorrect argument received.
Definition: xmipp_error.h:113
Angle between y-axis and tilt-axis (double, degrees) for untilted micrographs.
Flip the image? (bool)
#define XSIZE(v)
void addExampleLine(const char *example, bool verbatim=true)
int verbose
Verbosity level.
void initZeros()
Definition: matrix1d.h:592
void rotation2DMatrix(T ang, Matrix2D< T > &result, bool homogeneous)
#define YY(v)
Definition: matrix1d.h:93
void defineParams()
Define parameters in the command line.
void setProgress(size_t value=0)
virtual void removeDisabled()
void readParams()
Read parameters from the command line.
template float bestShift(MultidimArray< float > &, float &, float &, const MultidimArray< int > *, int)
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)
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
bool containsLabel(const MDLabel label) const override
Name of an image (std::string)
void addParamsLine(const String &line)
void initIdentity()
Definition: matrix2d.h:673