# **************************************************************************
# *
# * Authors: Josue Gomez Blanco (josue.gomez-blanco@mcgill.ca)
# * J.M. de la Rosa Trevin (jmdelarosa@cnb.csic.es)
# *
# *
# * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 2 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307 USA
# *
# * All comments concerning this program package may be sent to the
# * e-mail address 'scipion@cnb.csic.es'
# *
# **************************************************************************
import os
import pyworkflow.protocol.params as params
from pyworkflow import VERSION_1_1
import pyworkflow.utils as pwutils
import xmipp3.utils as xmutils
from pwem.protocols import ProtAlignMovies
from xmipp3.convert import writeMovieMd
CROP_NONE = 0
CROP_ALIGNMENT = 1
CROP_NEW = 2
[docs]class XmippProtMovieAverage(ProtAlignMovies):
"""
Protocol to average movies
"""
_label = 'movie average'
_lastUpdateVersion = VERSION_1_1
CONVERT_TO_MRC = 'mrcs'
doSaveAveMic = True
INTERP_LINEAR = 0
INTERP_CUBIC = 1
# Map to xmipp interpolation values in command line
INTERP_MAP = {INTERP_LINEAR: 1, INTERP_CUBIC: 3}
#--------------------------- DEFINE param functions ------------------------
def _defineAlignmentParams(self, form):
group = form.addGroup('Average')
line = group.addLine('Frames to SUM',
help='Frames range to SUM on each movie. The '
'first frame is 1. If you set 0 in the final '
'frame to sum, it means that you will sum '
'until the last frame of the movie.')
line.addParam('sumFrame0', params.IntParam, label='from')
line.addParam('sumFrameN', params.IntParam, label='to')
group.addParam('binFactor', params.FloatParam, default=1,
label='Binning factor',
help='Binning factor, it may be any floating number '
'Binning in Fourier is the first operation, so '
'that crop parameters are referred to the binned '
'images. ')
group.addParam('cropRegion', params.EnumParam,
choices=['None', 'From Alignment', 'New'],
label="Define crop region", default=CROP_NONE,
help="Select if you want to crop the final micrograph. "
"If you select: \n"
"*None*, the final micrographs will have the same "
"dimensions as the input movies. The region of "
"interest, if the input movies have alignment, is "
"ignored. \n"
"*from Alignment*, if the movies has alignment, "
"the region of interest is defined and will be "
"apply; else, micrographs will have the same "
"dimensions as the input movies. \n"
"*New*, All crop parameters should be defined below."
"The region of interest, if the input movies have "
"alignment, is ignored. ")
line = group.addLine('Crop offsets (px)',
condition='cropRegion==%d' % CROP_NEW)
line.addParam('cropOffsetX', params.IntParam, default=0, label='X')
line.addParam('cropOffsetY', params.IntParam, default=0, label='Y')
line = group.addLine('Crop dimensions (px)',
condition='cropRegion==%d' % CROP_NEW,
help='How many pixels to crop from offset\n'
'If equal to 0, use maximum size.')
line.addParam('cropDimX', params.IntParam, default=0, label='X')
line.addParam('cropDimY', params.IntParam, default=0, label='Y')
group.addParam('useAlignment', params.BooleanParam, default=True,
label="Use previous movie alignment to SUM frames?",
help="Input movies could have alignment information from"
"a previous protocol. If you select *Yes*, the "
"previous alignment will be taken into account.")
form.addParam('splineOrder', params.EnumParam,
default=self.INTERP_CUBIC, choices=['linear', 'cubic'],
expertLevel=params.LEVEL_ADVANCED,
label='Interpolation',
help="linear (faster but lower quality), "
"cubic (slower but more accurate).")
form.addParallelSection(threads=1, mpi=1)
#--------------------------- STEPS functions -------------------------------
def _processMovie(self, movie):
movieFolder = self._getOutputMovieFolder(movie)
x, y, n = movie.getDim()
s0, sN = self._getFrameRange(n, 'sum')
inputMd = os.path.join(movieFolder, 'input_movie.xmd')
writeMovieMd(movie, inputMd, s0, sN,
useAlignment=(movie.hasAlignment() and self.useAlignment))
outputMicFn = self._getExtraPath(self._getOutputMicName(movie))
if self.cropRegion == CROP_ALIGNMENT and movie.hasAlignment():
roi = movie.getAlignment().getRoi()
elif self.cropRegion == CROP_NEW:
roi = [self.cropOffsetX.get(), self.cropOffsetY.get(),
self.cropDimX.get(), self.cropDimY.get()]
else:
roi = None
gainFn = self.inputMovies.get().getGain()
ext = pwutils.getExt(self.inputMovies.get().getFirstItem().getFileName()).lower()
if self.inputMovies.get().getGain() and ext in ['.tif', '.tiff']:
self.flipY = True
inGainFn = self.inputMovies.get().getGain()
gainFn = xmutils.flipYImage(inGainFn, outDir=self._getExtraPath())
self.averageMovie(movie, inputMd, outputMicFn, self.binFactor.get(),
roi, self.inputMovies.get().getDark(), gainFn,
splineOrder=self.INTERP_MAP[self.splineOrder.get()],
outxmd="\"\"") # we're not interested in the metadata
self._storeSummary(movie)
#--------------------------- INFO functions --------------------------------
# def _validate(self):
# errors = []
# if (self.cropDimX > 0 and self.cropDimY <= 0 or
# self.cropDimY > 0 and self.cropDimX <= 0):
# errors.append("If you give cropDimX, you should also give cropDimY "
# "and viceversa")
# return errors
#--------------------------- UTILS functions -------------------------------
def _getShiftsFile(self, movie):
return self._getExtraPath(self._getMovieRoot(movie) + '_shifts.xmd')
def _getConvertExtension(self, filename):
ext = pwutils.getExt(filename).lower()
return None if ext in ['.mrc', '.mrcs', '.tiff', '.tif', '.stk'] else 'mrc'
def _createOutputMovies(self):
""" Returns True if an output set of movies will be generated.
The most common case is to always generate output movies,
either with alignment only or the binary aligned movie files.
Subclasses can override this function to change this behavior.
"""
return False
def _storeSummary(self, movie):
if movie.hasAlignment():
s0, sN = self._getFrameRange(movie.getNumberOfFrames(), 'sum')
fstFrame, lstFrame = movie.getAlignment().getRange()
if self.useAlignment and (fstFrame > s0 or lstFrame < sN):
self.summaryVar.set("Warning!!! You have selected a frame range "
"wider than the range selected to align. All "
"the frames selected without alignment "
"information, will be aligned by setting "
"alignment to 0")
else:
if self.cropRegion == CROP_ALIGNMENT:
self.summaryVar.set("Warning!!! You select *from Alignment* crop "
"region, but your movies have not alignment."
"Your resulting micrographs were not cropped."
"If you want to crop, please use *New* option.")