# **************************************************************************
# *
# * Authors: J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [1]
# * Peter Horvath (phorvath@cnb.csic.es) [2]
# *
# * [1] SciLifeLab, Stockholm University
# * [2] I2PC
# *
# * 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 3 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 csv
import os
import pyworkflow.utils as pwutils
from pyworkflow.object import Float
from pwem.emlib.image import ImageHandler
from pwem.objects import Coordinate
from topaz import constants
[docs]class CsvImageList:
""" Handler class to write a list of images as expected by topaz. """
def __init__(self, filename, mode='r', **kwargs):
self.__file = None
if mode == 'r':
self.__file = open(filename, 'r')
self.__reader = csv.reader(self.__file, delimiter='\t')
elif mode == 'w':
self.__file = open(filename, 'w')
self.__writer = csv.writer(self.__file, delimiter='\t')
self.__writer.writerow(kwargs['columns'])
def _addRow(self, *values):
self.__writer.writerow(values)
[docs] def close(self):
self.__file.close()
def __iter__(self):
it = iter(self.__reader)
# Just discard the first row
self.__columns = next(it)
return it
[docs]class CsvMicrographList(CsvImageList):
""" Handler class to write a list of micrographs as expected by topaz. """
def __init__(self, filename, mode='r'):
CsvImageList.__init__(self, filename, mode,
columns=['image_name', 'path'])
[docs] def addMic(self, micId, micPath):
self._addRow('%06d' % micId, micPath)
[docs]class CsvCoordinateList(CsvImageList):
""" Handler class to write a list of particles as expected by topaz. """
def __init__(self, filename, mode='r', score=False):
columns = ['image_name', 'x_coord', 'y_coord']
if score:
columns.append('score')
CsvImageList.__init__(self, filename, mode, columns=columns)
[docs] def addCoord(self, micId, x, y):
self._addRow('%06d' % micId, x, y)
[docs]def convertMicrographs(micList, micDir):
""" Convert (or simply link) input micrographs into the given directory
in a format that is compatible with Topaz.
"""
ih = ImageHandler()
ext = pwutils.getExt(micList[0].getFileName())
def _convert(mic, newName):
ih.convert(mic, os.path.join(micDir, newName))
def _link(mic, newName):
pwutils.createAbsLink(os.path.abspath(mic.getFileName()),
os.path.join(micDir, newName))
if ext in constants.TOPAZ_SUPPORTED_FORMATS:
func = _link
else:
func = _convert
ext = '.mrc'
for mic in micList:
func(mic, getMicIdName(mic, suffix=ext))
[docs]def readSetOfCoordinates(coordinatesCsvFn, micSet, coordSet, scale):
""" Read coordinates produced by Topaz.
Coordinates are expected in a single csv file, with the following columns:
first: image_name (mic id)
second: x_coord
third: y_coord
forth: score
"""
csv = CsvCoordinateList(coordinatesCsvFn, score=True)
lastMicId = None
coord = Coordinate()
coord._topazScore = Float()
micDict = {}
# loop to generate a dictionary --> micBaseName : Micrograph
for mic in micSet:
micNew = mic.clone()
micDict[mic.getObjId()] = micNew
#loop the Topaz outputfile
for row in csv:
micId = int(row[0])
if micId != lastMicId:
mic = micDict[micId]
if mic is None:
print("Missing id: ", micId)
else:
coord.setMicrograph(mic)
lastMicId = micId
coord.setPosition(int(round(float(row[1])*scale)), int(round(float(row[2])*scale)))
coord._topazScore.set(float(row[3]))
coord.setObjId(None)
coordSet.append(coord)
csv.close()
[docs]def getMicIdName(mic, suffix=''):
""" Return a name for the micrograph based on its IDs. """
return '%d%s' % (mic.getObjId(), suffix)