Source code for xmipp3.protocols.protocol_preprocess.protocol_image_operate

# *****************************************************************************
# *
# * Authors:  Carlos Oscar Sanchez Sorzano (coss@cnb.csic.es), Sep 2013
# * Ported to Scipion:
# *           Vahid Abrishami (vabrishami@cnb.csic.es), Oct 2014
# *
# * Refactored/Updated: Josue Gomez-Blanco (josue.gomez-blanco@mcgill.ca), Jun 2016
# *
# * 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'
# *
# *****************************************************************************

from collections import OrderedDict

from pwem.constants import ALIGN_NONE
import pyworkflow.protocol.params as params
from pwem.protocols import ProtOperateParticles, ProtOperateVolumes

from xmipp3.convert import (writeSetOfParticles, writeSetOfVolumes,
                            getImageLocation)
from .protocol_process import XmippProcessParticles, XmippProcessVolumes


# Operands enum
OP_PLUS = 0
OP_MINUS = 1
OP_MULTIPLY = 2
OP_DIVIDE = 3
OP_MINIMUM = 4
OP_MAXIMUM = 5
OP_DOTPRODUCT = 6
OP_LOG = 7
OP_LOG10 = 8
OP_SQRT = 9
OP_ABS = 10
OP_POW = 11
OP_SLICE = 12
OP_COLUNM = 13
OP_ROW = 14
OP_RADIAL = 15
OP_RESET = 16

OP_CHOICES = OrderedDict() #[-1]*(OP_RESET+1)

OP_CHOICES[OP_PLUS]  = 'plus'
OP_CHOICES[OP_MINUS] = 'minus'
OP_CHOICES[OP_MULTIPLY] = 'multiply'
OP_CHOICES[OP_DIVIDE] = 'divide'
OP_CHOICES[OP_MINIMUM] = 'minimum'
OP_CHOICES[OP_MAXIMUM] = 'maximum'
OP_CHOICES[OP_DOTPRODUCT]  = 'dot product'
OP_CHOICES[OP_LOG] = 'log'
OP_CHOICES[OP_LOG10] = 'log10'
OP_CHOICES[OP_SQRT] = 'sqrt'
OP_CHOICES[OP_ABS] = 'abs'
OP_CHOICES[OP_POW] = 'pow'
OP_CHOICES[OP_COLUNM] = 'colunm'
OP_CHOICES[OP_SLICE] = 'slice'
OP_CHOICES[OP_ROW] = 'row'
OP_CHOICES[OP_RADIAL] = 'radial average'
OP_CHOICES[OP_RESET] = 'reset'


binaryCondition = ('(operation == %d or operation == %d or operation == %d or '
                   'operation == %d or operation == %d or operation == %d) ' %
                   (OP_PLUS, OP_MINUS, OP_MULTIPLY,
                    OP_DIVIDE, OP_MINIMUM, OP_MAXIMUM))

#noValueCondition = '(operation == 7 or operation == 8 or operation == 9 or '\
#                   'operation == 10 or operation == 15 or operation == 16) '
noValueCondition = '(operation == %d or operation == %d or operation == %d or '\
                   'operation == %d or operation == %d or operation == %d) '%\
                   (OP_LOG, OP_LOG10, OP_SQRT,\
                    OP_ABS, OP_POW, OP_RESET)

intValueCondition = '(operation == %d or operation == %d)'%(OP_COLUNM, OP_ROW)

dotCondition = 'operation == %d'%OP_DOTPRODUCT
powCondition = 'operation == %d'%OP_POW

operationDict = {OP_PLUS : ' --plus ', OP_MINUS : ' --minus ',
                 OP_MULTIPLY : ' --mult ', OP_DIVIDE : ' --divide ',
                 OP_MINIMUM : ' --min ', OP_MAXIMUM : ' --max ',
                 OP_DOTPRODUCT : ' --dot_product ', OP_LOG : ' --log ',
                 OP_LOG10 : ' --log10', OP_SQRT : ' --sqrt ',
                 OP_ABS : ' --abs ', OP_POW : ' --pow ',
                 OP_SLICE : ' --slice ',  OP_RADIAL : ' --radial_avg ',
                 OP_RESET : ' --reset ', OP_COLUNM: '--column',
                 OP_ROW: '--row'}


[docs]class XmippOperateHelper(): """ Some image operations such as: Dot product or Summation. """ _label = 'image operate' def __init__(self, **args): self._program = "xmipp_image_operate" #--------------------------- DEFINE param functions ----------------------- def _defineProcessParams(self, form): form.addParam('operation', params.EnumParam, choices=list(OP_CHOICES.values()), default=OP_PLUS, label="Operation", help="Binary operations: \n" "*plus*: Sums two images, volumes or adds a " "numerical value to an image. \n" "*minus*: Subtracts two images, volumes or " "subtracts a numerical value to an image. \n" "*multiply*: Multiplies two images, volumes, or " "multiplies per a given number. \n" "*divide*: Divides two images, volumes, or divides " "per a given number. \n" "*minimum*: Minimum of two images, volumes, or " "number (pixel-wise). \n" "*maximum*: Maximum of two images, volumes, or " "number (pixel-wise). \n" "*dot product*: Dot product between two images or" " volumes. \n" "Unary operations: \n" "*log*: Computes the natural logarithm of an " "image. \n" "*log10*: Computes the decimal logarithm of " "an image. \n" "*sqrt*: Computes the square root of an image \n" "*abs*: Computes the absolute value of an image. \n" "*pow*: Computes the power of an image. \n" "*slice*: Extracts a given slice from a volume " "(first slice=0). \n" "*column*: Extracts a given column from a image " "or volume. \n" "*row*: Extracts a given row from a image or " "volume. \n" "*radial average*: Compute the radial average of " "an image. \n" "*reset*: Set the image to 0") form.addParam('isValue', params.BooleanParam, default=False, label="Second operand is a value?", condition=binaryCondition, help="Set to true if you want to use a " "value of the second operand") self._defineSpecificParams(form) form.addParam('value', params.FloatParam, allowNull=True, condition='isValue and %s or %s' % (binaryCondition, powCondition), label='Input value ', help = 'Set the desire float value') form.addParam('intValue', params.IntParam, allowNull=True, condition=intValueCondition, label='Input value ', help = 'This value must be integer') #--------------------------- INSERT STEPS functions ------------------------ def _insertProcessStep(self): operationStr = operationDict[self.operation.get()] self._insertFunctionStep("operationStep", operationStr) #--------------------------- UTILS functions ------------------------------ def _isBinaryCond(self): operation = self.operation.get() return (operation == OP_PLUS or operation == OP_MINUS or operation == OP_MULTIPLY or operation == OP_DIVIDE or operation == OP_MINIMUM or operation == OP_MAXIMUM) def _isNoValueCond(self): operation = self.operation.get() return (operation == OP_LOG or operation == OP_LOG10 or operation == OP_SQRT or operation == OP_ABS or operation == OP_RADIAL or operation == OP_RESET) def _isPowCond(self): operation = self.operation.get() return operation == OP_POW def _isDotCond(self): operation = self.operation.get() return operation == OP_DOTPRODUCT def _isintValueCond(self): operation = self.operation.get() return (operation == OP_SLICE or operation == OP_COLUNM or operation == OP_ROW) def _getSecondSetFn(self): return self._getTmpPath("images_to_apply.xmd")
[docs]class XmippProtImageOperateParticles(ProtOperateParticles, XmippProcessParticles, XmippOperateHelper): """Performs operations between two sets of particles or to a set of particles. The mathematical operations are: plus, minus multiply, divide, minimum, maximum, dot product, log, log10, sqrt, abs, pow, column, slice, row, mn, radial average or reset. This protocol supports comparative analysis or creation of difference maps between conditions. """ _label = 'operate particles' def __init__(self, **args): ProtOperateParticles.__init__(self, **args) XmippProcessParticles.__init__(self) XmippOperateHelper.__init__(self, **args) self.allowMpi = False self.allowThreads = False #--------------------------- DEFINE param functions ----------------------- def _defineProcessParams(self, form): XmippOperateHelper._defineProcessParams(self, form) def _defineSpecificParams(self, form): form.addParam('inputParticles2', params.PointerParam, allowNull=True, condition=(binaryCondition+' and (not isValue) or ' +dotCondition), label='Input Particles (2nd)', help = 'Set a SetOfParticles. The particles must be ' 'the same dimensions as the input particles.', pointerClass='SetOfParticles') #--------------------------- STEPS functions ------------------------------
[docs] def convertInputStep(self): """ convert to Xmipp image model""" writeSetOfParticles(self.inputParticles.get(), self.inputFn, alignType=ALIGN_NONE) if self.inputParticles2.get() is not None: writeSetOfParticles(self.inputParticles2.get(), self._getSecondSetFn(), alignType=ALIGN_NONE)
[docs] def operationStep(self, operationStr): dictImgFn = {"inputFn" : self.inputFn} args = self._args % dictImgFn + operationStr if self._isBinaryCond(): if self.isValue: args += ' %f' % self.value.get() else: args += ' %s' % self._getSecondSetFn() elif self._isPowCond(): args += ' %f' % self.value.get() elif self._isDotCond(): args += ' %s' % self._getSecondSetFn() elif self._isintValueCond(): args += ' %d' % self.intValue.get() args += " -o %s --save_metadata_stack %s" % (self.outputStk, self.outputMd) args += " --keep_input_columns" self.runJob(self._program, args)
#--------------------------- INFO functions ------------------------------- def _validate(self): errors = [] def _errorDimensions(): if not (self.inputParticles.get() is None and self.inputParticles2.get() is None): dim1 = self.inputParticles.get().getDimensions() dim2 = self.inputParticles2.get().getDimensions() if dim1 != dim2: errors.append("The number of images in two operands are " "not the same. ") def _errorSize(): if not (self.inputParticles.get() is None and self.inputParticles2.get() is None): size1 = self.inputParticles.get().getSize() size2 = self.inputParticles2.get().getSize() if size1 != size2: errors.append("Size of both *SetOfParticles* are not the" " same. ") if self._isBinaryCond(): if not self.isValue: if not self.inputParticles2.get() is None: _errorSize() _errorDimensions() elif self._isDotCond(): if not self.inputParticles2.get() is None: _errorDimensions() return errors
[docs]class XmippProtImageOperateVolumes(ProtOperateVolumes, XmippProcessVolumes, XmippOperateHelper): """ A Executes arithmetic operations between two volumesor to a volume. The mathematical operations are: plus, minus multiply, divide, minimum, maximum, dot product, log, log10, sqrt, abs, pow, column, slice, row, mn, radial average or resetThis enables structural comparisons, highlighting conformational changes or shared features between datasets.""" _label = 'operate volumes' def __init__(self, **args): ProtOperateVolumes.__init__(self, **args) XmippProcessVolumes.__init__(self) XmippOperateHelper.__init__(self, **args) self.allowMpi = False self.allowThreads = False #--------------------------- DEFINE param functions ----------------------- def _defineProcessParams(self, form): XmippOperateHelper._defineProcessParams(self, form) def _defineSpecificParams(self, form): form.addParam('inputVolumes2', params.PointerParam, allowNull=True, condition=(binaryCondition + ' and (not isValue) or ' + dotCondition), label='Input Volumes (2nd)', help = 'This parameter depends of the input volume(s). ' 'If it is set a volume (or a SetOfVolumes) as ' 'input, this must be a *Volume* (or ' '*SetOfVolumes*) object.', pointerClass='Volume, SetOfVolumes') #--------------------------- STEPS functions ------------------------------
[docs] def convertInputStep(self): """ convert to Xmipp image model""" if not self._isSingleInput(): writeSetOfVolumes(self.inputVolumes.get(), self.inputFn) if self.inputVolumes2.get() is not None: writeSetOfVolumes(self.inputVolumes2.get(), self._getSecondSetFn())
[docs] def operationStep(self, operationStr): dictImgFn = {"inputFn" : self.inputFn} args = self._args % dictImgFn + operationStr if self._isBinaryCond(): if self.isValue: args += ' %f' % self.value.get() else: args += ' %s' % self._getSecondVolumeFn() elif self._isPowCond(): args += ' %f' % self.value.get() elif self._isDotCond(): args += ' %s' % self._getSecondVolumeFn() elif self._isintValueCond(): args += ' %d' % self.intValue.get() args += " -o %s " % self.outputStk if not self._isSingleInput(): args += " --save_metadata_stack %s" \ " --keep_input_columns" % self.outputMd self.runJob(self._program, args)
#--------------------------- INFO functions ------------------------------- def _validate(self): errors = [] def _errorDimensions(): if not (self.inputVolumes.get() is None and self.inputVolumes2.get() is None): dim1 = self.inputVolumes.get().getDimensions() dim2 = self.inputVolumes2.get().getDimensions() if dim1 != dim2: errors.append("The number of volumes in two operands are " "not the same. ") def _errorSize(): if (not (self.inputVolumes.get() is None and self.inputVolumes2.get() is None) and not self._isSingleInput()): size1 = self.inputVolumes.get().getSize() size2 = self.inputVolumes2.get().getSize() if size1 != size2: errors.append("Size of both volumes are not the same. ") if self._isBinaryCond(): if not self.isValue: if not self.inputVolumes2.get() is None: _errorSize() _errorDimensions() elif self._isDotCond(): if not self.inputVolumes2.get() is None: _errorDimensions() return errors #--------------------------- UTILS functions ------------------------------ def _getSecondVolumeFn(self): if self._isSingleInput(): return getImageLocation(self.inputVolumes2.get()) else: return self._getSecondSetFn()