Skip to content
Snippets Groups Projects
registration.py 8.89 KiB
Newer Older
import os

import utils
import config

from java.lang import RuntimeException
from java.io import File
from java.util import Properties

from ch.systemsx.cisd.common.fileconverter import FileConverter, Tiff2PngConversionStrategy
from ch.systemsx.cisd.openbis.generic.shared.basic.dto.api import ValidationException

tpylak's avatar
tpylak committed
from ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.transformations import ImageTransformationBuffer 
from ch.systemsx.cisd.openbis.dss.etl.dto.api.v1 import SimpleImageDataConfig, ImageMetadata, OriginalDataStorageFormat, Location 
from ch.systemsx.cisd.openbis.dss.etl.custom.geexplorer import GEExplorerImageAnalysisResultParser
from ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto import Geometry

tpylak's avatar
tpylak committed
#reload(config)

class MyImageDataSetConfig(SimpleImageDataConfig):
    
    def __init__(self, incomingDir):
        self.incomingDir = incomingDir
        self.setStorageConfiguration()
        
    def setStorageConfiguration(self):
        self.setStoreChannelsOnExperimentLevel(config.STORE_CHANNELS_ON_EXPERIMENT_LEVEL)
        self.setOriginalDataStorageFormat(config.ORIGINAL_DATA_STORAGE_FORMAT)
        if config.GENERATE_THUMBNAILS:
            self.setGenerateThumbnails(True)
            #self.setUseImageMagicToGenerateThumbnails(True)
            self.setAllowedMachineLoadDuringThumbnailsGeneration(config.ALLOWED_MACHINE_LOAD_DURING_THUMBNAIL_GENERATION)
            self.setMaxThumbnailWidthAndHeight(config.MAX_THUMNAIL_WIDTH_AND_HEIGHT)
    
    """
    Creates ImageFileInfo for a given ImageTokens.
    Converts tile number to coordinates on the 'well matrix'.
    Example file name: A - 1(fld 1 wv Cy5 - Cy5).tif
    Returns:
        ImageTokens
    """
    def extractImageMetadata(self, path):
        imageTokens = ImageMetadata()
        
        imageFile = File(self.incomingDir, path)
        if not self.incomingDir.equals(imageFile.getParentFile()):
            return None
    
        basename = os.path.splitext(imageFile.name)[0]
        wellText = basename[0:utils.find(basename, "(")] # A - 1
        imageTokens.well = wellText.replace(" - ", "")
        
        if " wv " in basename:
            fieldText = basename[utils.find(basename, "fld ") + 4 : utils.find(basename, " wv")]
            imageTokens.channelCode = basename[utils.rfind(basename, " - ") + 3 :-1]
        else:
            fieldText = basename[utils.find(basename, "fld ") + 4 : utils.find(basename, ")")]
            imageTokens.channelCode = "DEFAULT"
        
        try:
            imageTokens.tileNumber = int(fieldText)
        except ValueError:
            raise ValidationException("Cannot parse field number from '" + fieldText + "' in '" + basename + "' file name.")
    
        return imageTokens
    
    def getTileCoordinates(self, tileNumber, tileGeometry):
        columns = tileGeometry.getWidth()
        row = ((tileNumber - 1) / columns) + 1
        col = ((tileNumber - 1) % columns) + 1
        return Location(row, col)
    
    def getTileGeometry(self, imageMetadataList, maxTile):
        if maxTile % 4 == 0 and maxTile != 4:
            (cols, rows) = (maxTile / 4, 4)
        elif maxTile % 3 == 0:
            (cols, rows) = (maxTile / 3, 3)
        elif maxTile % 2 == 0:
            (cols, rows) = (maxTile / 2, 2)
        else:
            (cols, rows) = (maxTile, 1)
        
        return Geometry.createFromRowColDimensions(cols, rows);
tpylak's avatar
tpylak committed
   
    def getAvailableChannelTransformations(self, channelCode):
        buffer = ImageTransformationBuffer()
        buffer.appendAllBitShiftsFor12BitGrayscale()
        buffer.appendAutoRescaleGrayscaleIntensity(0, "Original contrast")
        return buffer.getTransformations()
        
def createRawImagesDataset(incoming, plate, batchName, transaction, factory):
    imageDatasetConfig = MyImageDataSetConfig(incoming)
    imageDatasetConfig.setRawImageDatasetType()
    imageDatasetConfig.setFileFormatType(config.IMAGE_DATASET_FILE_FORMAT)
    imageDatasetConfig.setUseImageMagicToGenerateThumbnails(config.USE_IMAGE_MAGIC_CONVERT_TOOL)
tpylak's avatar
tpylak committed
   
    imageDatasetConfig.setImageLibrary("IJ", "tiff")
    
    #imageDatasetConfig.setComputeCommonIntensityRangeOfAllImagesForChannels(["DAPI"])
    #imageDatasetConfig.setComputeCommonIntensityRangeOfAllImagesIsDefault(False)
    #imageDatasetConfig.setComputeCommonIntensityRangeOfAllImagesForAllChannels()
    #imageDatasetConfig.setComputeCommonIntensityRangeOfAllImagesThreshold(0.01)

    # Available in the next release:
    #imageDatasetConfig.setThumbnailsGenerationImageMagicParams(["-contrast-stretch", "0"])
    imageDatasetDetails = factory.createImageRegistrationDetails(imageDatasetConfig, incoming)
    imageDataSet = transaction.createNewDataSet(imageDatasetDetails)
    imageDataSet.setPropertyValue(config.IMAGE_DATASET_BATCH_PROPCODE, batchName)
    imageDataSet.setSample(plate)
    return imageDataSet

def convertToPng(dir, transparentColor):
    delete_original_files = True
    strategy = Tiff2PngConversionStrategy(transparentColor, 0, delete_original_files)
    # Uses cores * machineLoad threads for the conversion, but not more than maxThreads
    machineLoad = config.ALLOWED_MACHINE_LOAD_DURING_THUMBNAIL_GENERATION
    maxThreads = 100
    errorMsg = FileConverter.performConversion(File(dir), strategy, machineLoad, maxThreads)
    if errorMsg:
        raise RuntimeException("Error converting overlays:" + errorMsg)

def registerSegmentationImages(overlaysDir, plate, imageDataSetCode, analysisProcedureCode, transaction, factory):
    convertToPng(overlaysDir.getPath(), config.OVERLAYS_TRANSPARENT_COLOR)
    overlayDatasetConfig = MyImageDataSetConfig(overlaysDir)
    overlayDatasetConfig.setSegmentationImageDatasetType()
    overlayDatasetConfig.setFileFormatType(config.OVERLAY_IMAGE_FILE_FORMAT)
    overlayDatasetConfig.setUseImageMagicToGenerateThumbnails(config.USE_IMAGE_MAGIC_CONVERT_TOOL)
tpylak's avatar
tpylak committed
    overlayDatasetConfig.setGenerateHighQualityThumbnails(True)
    overlayDatasetConfig.setImageLibrary("IJ", "tiff")
    # Available in the next release:
    #overlayDatasetConfig.setThumbnailsGenerationImageMagicParams(["-contrast-stretch", "0"])

    overlayDatasetDetails = factory.createImageRegistrationDetails(overlayDatasetConfig, overlaysDir)
    if analysisProcedureCode:
        overlayDatasetDetails.setPropertyValue("$ANALYSIS_PROCEDURE", analysisProcedureCode)
    overlayDataset = transaction.createNewDataSet(overlayDatasetDetails)
    overlayDataset.setSample(plate)
    overlayDataset.setParentDatasets([ imageDataSetCode ])
    transaction.moveFile(overlaysDir.getPath(), overlayDataset, "overlays")

def registerAnalysisData(analysisXmlFile, plate, parentDatasetCode, transaction, factory):
    analysisCSVFile = File(analysisXmlFile.getPath() + ".csv")
    geXmlParser = GEExplorerImageAnalysisResultParser(analysisXmlFile.getPath())
    geXmlParser.writeCSV(analysisCSVFile)
    
    featureProps = Properties()
    featureProps.setProperty("separator", ",")
    featureProps.setProperty("well-name-row", "Well")
    featureProps.setProperty("well-name-col", "Well")
    
    analysisDataSetDetails = factory.createFeatureVectorRegistrationDetails(analysisCSVFile.getPath(), featureProps)
    analysisProcedureCode = geXmlParser.getAnalysisProcedureName()
    analysisDataSetDetails.getDataSetInformation().setAnalysisProcedure(analysisProcedureCode)
    analysisDataSet = transaction.createNewDataSet(analysisDataSetDetails)
    analysisDataSet.setSample(plate)
    analysisDataSet.setParentDatasets([ parentDatasetCode ])
    analysisDataSet.setFileFormatType(config.ANALYSIS_FILE_FORMAT)
    parentDirName = "analysis"
    transaction.createNewDirectory(analysisDataSet, parentDirName)
    transaction.moveFile(analysisCSVFile.getPath(), analysisDataSet, parentDirName)
    transaction.moveFile(analysisXmlFile.getPath(), analysisDataSet, parentDirName)
    return analysisProcedureCode
        
        
""" 
Returns a tuple: 
 (plate sample connected to the dataset with the specified code, experiment connected to the plate) 
Raises exception is no sample is connected to the dataset.
"""
def findConnectedPlate(transaction, datasetCode):
    parentDataset = transaction.getDataSet(datasetCode)
    if not parentDataset:
        raise ValidationException("Cannot find a dataset with code '%s'" % (datasetCode))
    plate = parentDataset.getSample()
    if not plate:
        raise ValidationException("Dataset with code '%s' is not connected to any plate" % (datasetCode))
    
    # fetch the sample again to fetch connected experiment 
    plateIdentifier = plate.getSampleIdentifier()
    plate = transaction.getSample(plateIdentifier)
    plateExperiment = plate.getExperiment()
    if not plateExperiment:
        raise ValidationException("Cannot find experiment of a plate '%s' (connected to dataset with code '%s')" % (plateIdentifier, datasetCode))
    experimentIdent = plateExperiment.getExperimentIdentifier()
    # fetch the experiment again to have all its properties
    experiment = transaction.getExperiment(experimentIdent)

    return (plate, experiment)