Xmipp  v3.23.11-Nereus
transform_geometry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Authors: Joaquin Oton (joton@cnb.csic.es)
3  * J.M. De la Rosa (jmdelarosa@cnb.csic.es)
4  *
5  *
6  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  * 02111-1307 USA
22  *
23  * All comments concerning this program package may be sent to the
24  * e-mail address 'xmipp@cnb.csic.es'
25  ***************************************************************************/
26 #include "transform_geometry.h"
27 #include "core/geometry.h"
28 #include "core/transformations.h"
29 
31 {}
32 
34 {}
35 
37 {
39  save_metadata_stack = true;
40  keep_input_columns = true;
41  allow_apply_geo = true;
42  mdVol = false;
44  //usage
45  addUsageLine("Apply geometric transformations to images. You can shift, rotate and scale a group of images/volumes.");
46  addUsageLine("+ By default the geometric transformations will be read from a metadata, if provided. Also, ");
47  addUsageLine("+ the original images will be preserved if possible, trying to write out transformations to ");
48  addUsageLine("+ the output metadata. If output is not specified, the original files will be overwritten.");
49  addUsageLine("+ When output param -o is a stack file, associated metadata file is also generated using same rootname.");
50  addUsageLine("+ If geometrical transformation are applied, involved labels are reset in output metadata.");
51  //keywords
52  addKeywords("transform, geometry, shift, rotate, scale, flip");
53  //params
54  addParamsLine("== Transformations ==");
55  addParamsLine("[--rotate <ang=0>] : Inplane rotation in 2D images.");
56  addParamsLine(" : Positive angle is a clockwise rotation");
57  addParamsLine("[--rotate_volume <rotation_type>] : Rotation of volumes.");
58  addParamsLine(" where <rotation_type>");
59  addParamsLine(" euler <rot> <tilt> <psi> : Rotate with these Euler angles (ZYZ convention)");
60  addParamsLine(" matrix <r11> <r12> <r13> <r21> <r22> <r23> <r31> <r32> <r33> : 3x3 rotation matrix, first index is row");
61  addParamsLine(" alignZ <x> <y> <z> : Align (x,y,z) with Z axis");
62  addParamsLine(" axis <ang> <x=0> <y=0> <z=1> : Rotate <ang> degrees around (x,y,z)");
63  addParamsLine(" icosahedral <from> <to> : Rotate an icosahedral volume from i1 to i2, for instance");
64  addParamsLine(" : valid symmetries are i1, i2, i3 and i4");
65  addParamsLine("[--scale <factor=1>] : Perfom Scaling. Factor 0.5 halves and 2 doubles");
66  addParamsLine(" alias -s;");
67  addParamsLine("[--shift <x=0> <y=0> <z=0>] : Shift by x, y and z");
68  addParamsLine("[--flip] : Flip images, only valid for 2D");
69  addParamsLine("[--matrix <...>] : Apply directly the matrix transformation");
70  addParamsLine("== Other options ==");
71  addParamsLine(" [--interp <interpolation_type=spline>] : Interpolation type to be used. ");
72  addParamsLine(" where <interpolation_type>");
73  addParamsLine(" spline : Use spline interpolation");
74  addParamsLine(" linear : Use bilinear/trilinear interpolation");
75  addParamsLine("[--inverse] : Apply inverse transformations");
76  addParamsLine("[--apply_transform] : By default, the original images are preserved");
77  addParamsLine(" : and the alignment information is stored in metadata");
78  addParamsLine("[--dont_wrap] : By default, the image/volume is wrapped");
79  addParamsLine("[--write_matrix] : Print transformation matrix to screen");
80  addParamsLine("[--shift_to <x=0> <y=0> <z=0>] : Shift each particle to x,y,z position");
81  //examples
82  addExampleLine("Write a metadata with geometrical transformations keeping the reference to original images:", false);
83  addExampleLine("xmipp_transform_geometry -i mD1.xmd --shift 2 3 4 --scale 1.2 --rotate 23 -o newGeo.xmd");
84  addExampleLine("Write a metadata with geometrical transformations copying original images to new stack file:", false);
85  addExampleLine("xmipp_transform_geometry -i mD1.xmd --shift 2 3 4 --scale 1.2 --rotate 23 -o newGeo.stk");
86  addExampleLine("Apply geometrical transformations to images ,reset involved labels and save in new metadata and stack files:", false);
87  addExampleLine("xmipp_transform_geometry -i mD1.xmd --shift 2 3 4 --scale 1.2 --rotate 23 -o newGeo.xmd --apply_transform");
88  addExampleLine("To simply apply the transformations in a metadata to the images:", false);
89  addExampleLine("xmipp_transform_geometry -i mD1.xmd --apply_transform");
90  addExampleLine("Shift a volume by 10, 5 and -10 in x,y and z and do not wrap", false);
91  addExampleLine("xmipp_transform_geometry -i a.vol --shift 10 5 -10 -o b.vol --dont_wrap");
92  addExampleLine("Scale a group of images to half size, not modifying image dimensions neither original image files", false);
93  addExampleLine("xmipp_transform_geometry -i images.xmd --scale 0.5 -o halvedOriginal.xmd");
94 
95 }
96 
98 {
100  applyTransform = checkParam("--apply_transform");
101  inverse = checkParam("--inverse");
102  wrap = ! checkParam("--dont_wrap");
103  String degree = getParam("--interp");
104  if (degree == "spline")
106  else if (degree == "linear")
108  flip = checkParam("--flip");
109 
114  if ( !checkParam("--oroot") && fn_out.hasMetadataExtension())
115  {
118  else
121  fn_out = fn_out.replaceExtension("stk");
122  }
123  else if ( !checkParam("--oroot") && !checkParam("-o") )
124  produces_a_metadata = true;
125 }
126 
127 
129 {
130  const char * rotateType = getParam("--rotate_volume");
131  Matrix1D<double> xyz(3);
132  if (!STR_EQUAL(rotateType, "icosahedral"))
133  { // params are char for icosahedral option
134  XX(xyz) = getDoubleParam("--rotate_volume", 1); //rot
135  YY(xyz) = getDoubleParam("--rotate_volume", 2); //tilt
136  ZZ(xyz) = getDoubleParam("--rotate_volume", 3); //psi
137  }
138 
139  if (STR_EQUAL(rotateType, "euler"))
140  Euler_angles2matrix(XX(xyz), YY(xyz), ZZ(xyz), R, true);
141  else if (STR_EQUAL(rotateType, "matrix"))
142  {
143  R.initZeros(4,4);
144  MAT_ELEM(R, 3, 3) = 1;
145  for (int i = 0; i < 9; ++i)
146  {
147  int r = i / 3;
148  int c = i % 3;
149  MAT_ELEM(R, r, c) = getDoubleParam("--rotate_volume", i+1);
150  }
151  }
152  else if (STR_EQUAL(rotateType, "alignZ"))
153  alignWithZ(xyz, R);
154  else if (STR_EQUAL(rotateType, "icosahedral"))
155  {
156  const char * icoFrom = getParam("--rotate_volume", 1);
157  const char * icoTo = getParam("--rotate_volume", 2);
158  rotation3DMatrixFromIcoOrientations(icoFrom, icoTo, R);
159  }
160  else
161  {
162  double ang = getDoubleParam("--rotate_volume", 1);
163  XX(xyz) = getDoubleParam("--rotate_volume", 2); //axis x
164  YY(xyz) = getDoubleParam("--rotate_volume", 3); //y
165  ZZ(xyz) = getDoubleParam("--rotate_volume", 4);//z
166  rotation3DMatrix(ang, xyz, R, true);
167  }
168 }
169 
171 {
172  //If zdimOut greater than 1, is a volume and should apply transform
173  dim = (isVol = (zdimOut > 1)) ? 3 : 2;
174 
176  R.initIdentity(dim + 1);
177  A.initIdentity(dim + 1);
178 
179  MDRowVec rowGeo;
180  rowGeo.setValue(MDL_SHIFT_X, getDoubleParam("--shift", 0));
181  rowGeo.setValue(MDL_SHIFT_Y, getDoubleParam("--shift", 1));
182  rowGeo.setValue(MDL_SCALE, getDoubleParam("--scale"));
183 
184  if (isVol)
185  {
186  if (checkParam("--rotate_volume"))
188  else
189  mdVol = true;
190  rowGeo.setValue(MDL_SHIFT_Z, getDoubleParam("--shift", 2));
191 
192  }
193  else
194  rowGeo.setValue(MDL_ANGLE_PSI, getDoubleParam("--rotate"));
195 
196  geo2TransformationMatrix(rowGeo, A);
197 
198  A = A * R;
199 
200  if (flip)
201  {
202  MAT_ELEM(A, 0, 0) *= -1.;
203  MAT_ELEM(A, 0, 1) *= -1.;
204  if (dim == 3)
205  MAT_ELEM(A, 0, 2) *= -1.;
206  }
207  if (inverse)
208  A = A.inv();
209 }
210 
212  const FileName &fnImgOut,
213  const MDRow &rowIn,
214  MDRow &rowOut)
215 {
216 
217  if (checkParam("--matrix"))
218  {
219  // In this case we are directly reading the transformation matrix
220  // from the arguments passed
221  matrixStr = getParam("--matrix");
223  }
224  else
225  {
226  B.initIdentity(dim + 1);
227 
228 
229  if (apply_geo || mdVol || applyTransform)
230  geo2TransformationMatrix(rowOut, B);
231 
232  T = A * B;
233  }
234 
235  if (checkParam("--write_matrix"))
236  std::cerr << T << std::endl;
237 
238  if (applyTransform || fnImg != fnImgOut)
239  img.read(fnImg);
240 
241 
242  if (checkParam("--shift_to"))
243  {
244  double rot, tilt, psi;
245  rowIn.getValue(MDL_ANGLE_ROT, rot);
246  rowIn.getValue(MDL_ANGLE_TILT, tilt);
247  rowIn.getValue(MDL_ANGLE_PSI, psi);
248  Matrix1D<double> pos, posp;
249  pos.initZeros(3);
250  posp.initZeros(3);
251  pos(0) = getDoubleParam("--shift_to", 0);
252  pos(1) = getDoubleParam("--shift_to", 1);
253  pos(2) = getDoubleParam("--shift_to", 2);
254  R.initIdentity(3);
255  Euler_angles2matrix(rot, tilt, psi, R, false);
256  if (checkParam("--inverse"))
257  R = R.inv();
258  posp = R * pos;
259  rowOut.setValue(MDL_SHIFT_X, -posp(0));
260  rowOut.setValue(MDL_SHIFT_Y, -posp(1));
261  T.initIdentity(3);
262  int nx;
263  rowIn.getValue(MDL_XCOOR, nx);
264  nx += int(-posp(0));
265  rowOut.setValue(MDL_XCOOR, nx);
266  int ny;
267  rowIn.getValue(MDL_YCOOR, ny);
268  ny += int(-posp(1));
269  rowOut.setValue(MDL_YCOOR, ny);
270  geo2TransformationMatrix(rowOut, T, true);
271  }
272 
273  if (applyTransform)
274  {
275  img().setXmippOrigin();
277  imgOut().resize(1, zdimOut, ydimOut, xdimOut, false);
278  imgOut().setXmippOrigin();
279  applyGeometry(splineDegree, imgOut(), img(), T, xmipp_transformation::IS_NOT_INV, wrap, 0.);
280  imgOut.write(fnImgOut);
281  rowOut.resetGeo(false);
282  }
283  else
284  {
285  transformationMatrix2Geo(T, rowOut);
286  if (fnImg != fnImgOut )
287  img.write(fnImgOut);
288  }
289 }
Matrix2D< double > T
Rotation angle of an image (double,degrees)
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 resize(int Xdim, int Ydim, int Zdim, size_t Ndim, bool copy=true)
double getDoubleParam(const char *param, int arg=0)
Matrix2D< double > A
size_t mdInSize
Number of input elements.
void string2TransformationMatrix(const String &matrixStr, Matrix2D< double > &matrix, size_t dim)
FileName replaceExtension(const String &newExt) const
void geo2TransformationMatrix(const MDRow &imageGeo, Matrix2D< double > &A, bool only_apply_shifts)
void transformationMatrix2Geo(const Matrix2D< double > &A, MDRow &imageGeo)
void Euler_angles2matrix(T alpha, T beta, T gamma, Matrix2D< T > &A, bool homogeneous)
Definition: geometry.cpp:624
doublereal * c
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 inv(Matrix2D< T > &result) const
Definition: matrix2d.cpp:663
Special label to be used when gathering MDs in MpiMetadataPrograms.
#define i
DataType getDatatype() const
void rotation3DMatrix(double ang, char axis, Matrix2D< double > &result, bool homogeneous)
Matrix2D< double > B
void addKeywords(const char *keywords)
#define MAT_ELEM(m, i, j)
Definition: matrix2d.h:116
T & getValue(MDLabel label)
const char * getParam(const char *param, int arg=0)
#define XX(v)
Definition: matrix1d.h:85
X component (int)
void rotation3DMatrixFromIcoOrientations(const char *icoFrom, const char *icoTo, Matrix2D< double > &R)
void addExampleLine(const char *example, bool verbatim=true)
scaling factor for an image or volume (double)
virtual void resetGeo(bool addLabels=true)
#define STR_EQUAL(str1, str2)
Definition: xmipp_strings.h:42
void initZeros()
Definition: matrix1d.h:592
#define YY(v)
Definition: matrix1d.h:93
void setValue(MDLabel label, const T &d, bool addLabel=true)
void setDatatype(DataType _datatype)
bool save_metadata_stack
Save the associated output metadata when output file is a stack.
std::string String
Definition: xmipp_strings.h:34
double psi(const double x)
Shift for the image in the Z axis (double)
void initZeros()
Definition: matrix2d.h:626
bool keep_input_columns
Keep input metadata columns.
bool checkParam(const char *param)
Y component (int)
bool each_image_produces_an_output
Indicate that an output is produced for each image in the input.
Shift for the image in the Y axis (double)
void addUsageLine(const char *line, bool verbatim=false)
void alignWithZ(const Matrix1D< double > &axis, Matrix2D< double > &result, bool homogeneous)
int read(const FileName &name, DataMode datamode=DATA, size_t select_img=ALL_IMAGES, bool mapData=false)
Matrix2D< double > R
bool input_is_metadata
Input is a metadata.
bool hasMetadataExtension() const
void processImage(const FileName &fnImg, const FileName &fnImgOut, const MDRow &rowIn, MDRow &rowOut)
#define ZZ(v)
Definition: matrix1d.h:101
bool produces_a_metadata
Indicate that the unique final output file is a Metadata.
void addParamsLine(const String &line)
void initIdentity()
Definition: matrix2d.h:673