Example #1
0
    def getSamples(self, className):
        self._loadInfos()
        strPathSamples = os.path.join(self._oLearner.dctEnvPaths['samples'],
                                      className)
        lstResults = []
        if os.path.isdir(strPathSamples):
            #print len(self._oLearner.lstFeatureNames), len()
            dctImagePairs = OrderedDict()
            for strName, oMatch in collect_files_by_regex(strPathSamples, '(?P<prefix>.+?)__(?P<type>(img)|(msk)).+?', ['.png', '.jpg']):
                strPrefix = oMatch.group('prefix')
                strType = oMatch.group('type')
                if not strPrefix in dctImagePairs:
                    dctImagePairs[strPrefix] = {}
                dctImagePairs[strPrefix][strType] = strName

            iIdx = 0
            for dctPair in dctImagePairs.values():
                #oContainer = ccore.SingleObjectContainer(dctPair['img'], dctPair['msk'])
                #strCoords = ",".join(map(str,flatten(oContainer.getCrackCoordinates(1))))
                #print dctPair['img'], dctPair['msk']
                #dctFeatures = {}
                #for iF, strFeatureName in enumerate(self._oLearner.lstFeatureNames):
                #    dctFeatures[strFeatureName] = self._oLearner.dctFeatureData[className][iIdx][iF]
                oSample = Sample(dctPair['img'])
                lstResults.append(oSample)
                iIdx += 1
                #break
        return lstResults
Example #2
0
class ClassifierService(object):

    def __init__(self, path):
        self.strPath = path
        self._dctClassifiers = None
        self._updateClassifiers()

    def _updateClassifiers(self):
        self._dctClassifiers = OrderedDict()
        for strName in os.listdir(self.strPath):
            strPathClassifier = os.path.join(self.strPath, strName)
            if os.path.isdir(strPathClassifier) and strName[0] not in ['.', '_']:
                oClassifier = Classifier(strName, strPathClassifier)
                self._dctClassifiers[strName] = oClassifier

    def getAll(self, update):
        logging.info("getAll, update: %s" % update)
        if update:
            self._updateClassifiers()
        return self._dctClassifiers.values()

    def getClassInfos(self, name):
        logging.info("getClassInfos")
        oClassifier = self._dctClassifiers[name]
        return oClassifier.classInfos

    def getFeatureInfos(self, name):
        logging.info("getFeatureInfos")
        oClassifier = self._dctClassifiers[name]
        return oClassifier.featureInfos

    def getSampleInfos(self, classifierName, className):
        logging.info("getClassSamples %s %s" % (classifierName, className))
        oClassifier = self._dctClassifiers[classifierName]
        return oClassifier.getSamples(className)

    def getFeatureData(self, classifierName, featureNames):
        logging.info("getFeatureData %s %s" % (classifierName, featureNames))
        oClassifier = self._dctClassifiers[classifierName]
        return oClassifier.getFeatureData(featureNames)
Example #3
0
File: config.py Project: cmci/cecog
class _Section(object):

    SECTION_NAME = None
    OPTIONS = None

    def __init__(self):
        self._registry = OrderedDict()
        self._traitname_grpname = OrderedDict()

        for grp_name, grp_items in self.OPTIONS:
            grp = TraitGroup(grp_name)
            self._registry[grp_name] = grp
            for trait_name, trait in grp_items:
                trait_name = trait_name.lower()
                grp.register_trait(trait_name, trait)
                self._traitname_grpname[trait_name] = grp_name

    def get_group(self, name):
        return self._registry[name]

    def get_group_names(self):
        return self._registry.keys()

    def get_trait(self, trait_name):
        grp_name = self._traitname_grpname[trait_name]
        grp = self._registry[grp_name]
        return grp.get_trait(trait_name)

    def get_trait_names(self):
        names = []
        for grp in self._registry.values():
            names += grp.get_trait_names()
        return set(names)

    def get_trait_names_for_group(self, name):
        grp = self.get_group(name)
        return grp.get_trait_names()
Example #4
0
class BaseLearner(LoggerMixin, OptionManager):

    ANNOTATIONS = 'annotations'

    OPTIONS = {"strEnvPath" :          Option(".", callback="_onEnvPath"),
               "lstClassDefinitions" : Option([], callback="_onDefineClasses"),
               "strArffFileName" :     Option("features.arff"),
               "strSparseFileName" :   Option("features.sparse"),
               "strDefinitionFileName" :   Option("class_definition.txt"),
               "filename_pickle" :     Option("learner.pkl"),
              }

    __attributes__ = ['dctFeatureData',
                      'dctSampleData',
                      'dctClassNames',
                      'dctClassLabels',
                      'lstFeatureNames',
                      'dctHexColors',
                      'dctEnvPaths',
                      'dctImageObjects']

    def __init__(self, **options):
        self.dctFeatureData = OrderedDict()
        self.dctClassNames = {}
        self.dctClassLabels = {}
        self.lstFeatureNames = None
        self.dctHexColors = {}
        self.dctSampleNames = {}
        self.dctEnvPaths = {}
        self.hasZeroInsert = False
        self.dctImageObjects = OrderedDict()

        super(BaseLearner, self).__init__(**options)

    def __getstate__(self):
        dctState = get_attribute_values(self)
        return dctState

    def __setstate__(self, state):
        set_attribute_values(self, state)

    def clear(self):
        self.dctFeatureData.clear()
        self.dctClassNames.clear()
        self.dctClassLabels.clear()
        self.lstFeatureNames = None
        self.dctHexColors.clear()
        self.dctSampleNames.clear()
        self.dctImageObjects.clear()

    def mergeClasses(self, info, mapping):
        newl = copy.deepcopy(self)

        newl.dctClassNames = {}
        newl.dctClassLabels = {}
        newl.dctHexColors = {}
        for label, name, color in info:
            newl.dctClassNames[label] = name
            newl.dctClassLabels[name] = label
            newl.dctHexColors[name] = color
        data = OrderedDict()
        for new_label, label_list in mapping.iteritems():
            new_name = newl.dctClassNames[new_label]
            if not new_name in data:
                data[new_name] = []
            for old_label in label_list:
                old_name = self.dctClassNames[old_label]
                data[new_name].extend(self.dctFeatureData[old_name])
        for name in data:
            data[name] = numpy.asarray(data[name])
        newl.dctFeatureData = data
        return newl

    @property
    def lstClassNames(self):
        return [self.dctClassNames[x] for x in self.lstClassLabels]

    @property
    def lstClassLabels(self):
        return sorted(self.dctClassNames.keys())

    @property
    def iClassNumber(self):
        return len(self.dctClassNames)

    @property
    def lstHexColors(self):
        return [self.dctHexColors[x] for x in self.lstClassNames]

    @property
    def names2samples(self):
        return dict([(n, len(self.dctFeatureData.get(n, [])))
                     for n in self.lstClassNames])


    @property
    def l2nl(self):
        '''
        convert a label into a new label
        (new labels are continuous from 0..number of classes
        '''
        return dict([(l,i) for i,l in enumerate(self.lstClassLabels)])

    @property
    def nl2l(self):
        '''
        convert a new label into the original label
        '''
        return dict([(i,l) for i,l in enumerate(self.lstClassLabels)])


    #def getFeaturesByName(self, featureName):


    def initEnv(self):
        env_path = self.getOption('strEnvPath')
        if not os.path.isdir(env_path):
            raise IOError("Classifier environment path '%s' does not exist." %
                          env_path)
        for strName, strPath in self.dctEnvPaths.iteritems():
            safe_mkdirs(strPath)

    def _onDefineClasses(self, lstClassDefinitions):
        for dctClassDescription in lstClassDefinitions:
            strClassName = dctClassDescription['name']
            iClassLabel  = dctClassDescription['label']
            tplColor     = dctClassDescription['color']

            # FIXME: folders not supported yet!!!
            if ('folders' not in dctClassDescription or
                dctClassDescription['folders'] is None or
                len(dctClassDescription['folders']) == 0):
                lstFolders = [strClassName]
            else:
                lstFolders = dctClassDescription['folders']

            self.dctClassNames[iClassLabel] = strClassName
            self.dctClassLabels[strClassName] = iClassLabel
            self.dctHexColors[strClassName] = rgbToHex(*tplColor)


    def _onEnvPath(self, strEnvPath):
        self.dctEnvPaths = {'samples' :    os.path.join(strEnvPath, "samples"),
                            self.ANNOTATIONS : os.path.join(strEnvPath, self.ANNOTATIONS),
                            'data':        os.path.join(strEnvPath, "data"),
                            'controls':    os.path.join(strEnvPath, "controls"),
                       }

    def getPath(self, strName):
        path = self.dctEnvPaths[strName]
        if not os.path.exists(path):
            os.mkdir(path)
        return path

    def get_env_path(self):
        return self.getOption('strEnvPath')

    def set_env_path(self, path):
        self.setOption('strEnvPath', path)
        self._onEnvPath(path)

    def loadDefinition(self, path=None, filename=None):
        if filename is None:
            filename = self.getOption('strDefinitionFileName')
        if path is None:
            path = self.getOption('strEnvPath')
        f = open(os.path.join(path, filename), "rb")
        reader = csv.reader(f, delimiter='\t', quoting=csv.QUOTE_NONE)
        self.dctClassNames.clear()
        self.dctClassLabels.clear()
        self.dctHexColors.clear()
        for row in reader:
            label = int(row[0])
            name = row[1]
            color = row[2]
            self.dctClassNames[label] = name
            self.dctClassLabels[name] = label
            self.dctHexColors[name] = color
        f.close()

    def saveDefinition(self, path=None, filename=None):
        if filename is None:
            filename = self.getOption('strDefinitionFileName')
        if path is None:
            path = self.getOption('strEnvPath')
        f = open(os.path.join(path, filename), "wb")
        writer = csv.writer(f, delimiter='\t', quoting=csv.QUOTE_NONE)
        for class_name in self.lstClassNames:
            class_label = self.dctClassLabels[class_name]
            color = self.dctHexColors[class_name]
            writer.writerow([class_label, class_name, color])
        f.close()

    def exportRanges(self, strFilePath=None, strFileName=None):
        if strFileName is None:
            strFileName = os.path.splitext(self.getOption('strArffFileName'))[0]
            strFileName += '.range'
        if strFilePath is None:
            strFilePath = self.dctEnvPaths['data']

        all_features = numpy.asarray(flatten(self.dctFeatureData.values()))
        features_min = numpy.min(all_features, 0)
        features_max = numpy.max(all_features, 0)

        f = file(os.path.join(strFilePath, strFileName), 'w')
        f.write('x\n')
        f.write('-1 1\n')
        for idx, (m1, m2) in enumerate(zip(features_min, features_max)):
            f.write('%d %.10e %.10e\n' % (idx+1, m1, m2))
        f.close()

    def importFromArff(self, strFilePath=None, strFileName=None):
        if strFileName is None:
            strFileName = self.getOption('strArffFileName')
        if strFilePath is None:
            strFilePath = self.dctEnvPaths['data']

        oReader = ArffReader(os.path.join(strFilePath, strFileName))
        self.dctFeatureData = oReader.dctFeatureData
        self.dctClassNames = oReader.dctClassNames
        self.dctClassLabels = oReader.dctClassLabels
        self.lstFeatureNames = oReader.lstFeatureNames
        self.dctHexColors = oReader.dctHexColors
        self.hasZeroInsert = oReader.hasZeroInsert
        #print self.dctClassLabels
        #print self.dctClassNames
        #print self.dctFeatureData.keys()

    def check(self):
        filename = os.path.splitext(self.getOption('strArffFileName'))[0]
        result = {'path_env' : self.getOption('strEnvPath'),
                  'path_data' : self.dctEnvPaths['data'],
                  'path_samples' : self.dctEnvPaths['samples'],
                  'path_annotations' : self.dctEnvPaths['annotations'],
                  'model' : os.path.join(self.dctEnvPaths['data'], '%s.model' % filename),
                  'range' : os.path.join(self.dctEnvPaths['data'], '%s.range' % filename),
                  'conf' : os.path.join(self.dctEnvPaths['data'], '%s.confusion.txt' % filename),
                  'arff' : os.path.join(self.dctEnvPaths['data'], self.getOption('strArffFileName')),
                  'definition' : os.path.join(self.getOption('strEnvPath'), self.getOption('strDefinitionFileName')),
                  }
        result.update({'has_path_data' : os.path.isdir(self.dctEnvPaths['data']),
                       'has_path_samples' : os.path.isdir(self.dctEnvPaths['samples']),
                       'has_path_annotations' : os.path.isdir(self.dctEnvPaths['annotations']),
                       'has_model' : os.path.isfile(os.path.join(self.dctEnvPaths['data'], '%s.model' % filename)),
                       'has_range' : os.path.isfile(os.path.join(self.dctEnvPaths['data'], '%s.range' % filename)),
                       'has_conf' : os.path.isfile(os.path.join(self.dctEnvPaths['data'], '%s.confusion.txt' % filename)),
                       'has_arff' : os.path.isfile(os.path.join(self.dctEnvPaths['data'], self.getOption('strArffFileName'))),
                       'has_definition' : os.path.isfile(os.path.join(self.getOption('strEnvPath'), self.getOption('strDefinitionFileName'))),
                       }
                      )
        return result


    def exportToArff(self, strFilePath=None, strFileName=None):
        if strFileName is None:
            strFileName = self.getOption('strArffFileName')
        if strFilePath is None:
            strFilePath = self.dctEnvPaths['data']

        #print self.hasZeroInsert
        oWriter = ArffWriter(os.path.join(strFilePath, strFileName),
                             self.lstFeatureNames,
                             self.dctClassLabels,
                             dctHexColors=self.dctHexColors,
                             hasZeroInsert=self.hasZeroInsert)
        oWriter.writeAllFeatureData(self.dctFeatureData)
        oWriter.close()

    def exportToSparse(self, strFilePath=None, strFileName=None):
        if strFileName is None:
            strFileName = self.getOption('strSparseFileName')
        if strFilePath is None:
            strFilePath = self.dctEnvPaths['data']

        oWriter = SparseWriter(os.path.join(strFilePath, strFileName),
                               self.lstFeatureNames,
                               self.dctClassLabels)
        oWriter.writeAllFeatureData(self.dctFeatureData)
        oWriter.close()

    def importSampleNames(self, strFilePath=None, strFileName=None):
        if strFileName is None:
            strFileName = os.path.splitext(self.getOption('strArffFileName'))[0]
            strFileName = '%s.samples.txt' % strFileName
        if strFilePath is None:
            strFilePath = self.dctEnvPaths['data']
        f = file(os.path.join(strFilePath, strFileName), 'r')
        self.dctSampleNames = {}
        for line in f:
            class_name, file_name = line.strip().split('\t')
            if class_name in self.dctClassLabels:
                if not class_name in self.dctSampleNames:
                    self.dctSampleNames[class_name] = []
            self.dctSampleNames[class_name].append(file_name)
        f.close()

    def exportSampleNames(self, strFilePath=None, strFileName=None):
        if strFileName is None:
            strFileName = os.path.splitext(self.getOption('strArffFileName'))[0]
            strFileName = '%s.samples.txt' % strFileName
        if strFilePath is None:
            strFilePath = self.dctEnvPaths['data']
        f = file(os.path.join(strFilePath, strFileName), 'w')
        for class_name, samples in self.dctSampleNames.iteritems():
            for sample_name in samples:
                f.write('%s\t%s\n' % (class_name, sample_name))
        f.close()

    def export(self):
        self.exportToArff()
        self.exportToSparse()
        self.exportSampleNames()
Example #5
0
class Classifier(object):

    def __init__(self, name=None, path=None):
        #super(Classifier, self).__init__()
        self.name = name
        self.path = path

        self.dctClassInfos = OrderedDict()
        self.dctFeatureInfos = OrderedDict()
        self.isInitialized = False
        #self._loadInfos()

    def _loadInfos(self):
        print "LOAD"
        if not self.isInitialized:
            self._oLearner = BaseLearner(strEnvPath=self.path)
            try:
                self._oLearner.importFromArff()
                try:
                    self._oLearner.importSampleNames()
                except IOError:
                    has_samples = False
                else:
                    has_samples = True
                #print has_samples
            except IOError:
                pass
            else:
                print "import %s" % self.name

                for iLabel in self._oLearner.lstClassLabels:
                    strName = self._oLearner.dctClassNames[iLabel]
                    strHexColor = self._oLearner.dctHexColors[strName]
                    if strName in self._oLearner.dctFeatureData:
                        oClass = Class(strName, iLabel,
                                       len(self._oLearner.dctFeatureData[strName]),
                                       hexToFlexColor(strHexColor))
                        oClass.oClassifier = self
                        dctFeatures = {}
                        for iIdx, strFeatureName in enumerate(self._oLearner.lstFeatureNames):
                            dctFeatures[strFeatureName] = list(self._oLearner.dctFeatureData[strName][:,iIdx])
                        oClass.features = dctFeatures
                        if has_samples:
                            oClass.sample_names = [Sample(os.path.join(self._oLearner.dctEnvPaths['samples'], strName, filename))
                                                   for filename in self._oLearner.dctSampleNames[strName]]
                            #print strName,self._oLearner.dctSampleNames[strName]
                        self.dctClassInfos[strName] = oClass
                self.isInitialized = True

                for strFeatureName in self._oLearner.lstFeatureNames:
                    self.dctFeatureInfos[strFeatureName] = Feature(strFeatureName)

    @property
    def classes(self):
        self._loadInfos()
        return self.dctClassInfos.values()

    @property
    def classInfos(self):
        self._loadInfos()
        logging.debug("classes: %s" % len(self.dctClassInfos.values()))
        return self.dctClassInfos.values()

    @property
    def featureInfos(self):
        self._loadInfos()
        logging.debug("features: %s" % len(self.dctFeatureInfos.values()))
        return self.dctFeatureInfos.values()

    def getSamples(self, className):
        self._loadInfos()
        strPathSamples = os.path.join(self._oLearner.dctEnvPaths['samples'],
                                      className)
        lstResults = []
        if os.path.isdir(strPathSamples):
            #print len(self._oLearner.lstFeatureNames), len()
            dctImagePairs = OrderedDict()
            for strName, oMatch in collect_files_by_regex(strPathSamples, '(?P<prefix>.+?)__(?P<type>(img)|(msk)).+?', ['.png', '.jpg']):
                strPrefix = oMatch.group('prefix')
                strType = oMatch.group('type')
                if not strPrefix in dctImagePairs:
                    dctImagePairs[strPrefix] = {}
                dctImagePairs[strPrefix][strType] = strName

            iIdx = 0
            for dctPair in dctImagePairs.values():
                #oContainer = ccore.SingleObjectContainer(dctPair['img'], dctPair['msk'])
                #strCoords = ",".join(map(str,flatten(oContainer.getCrackCoordinates(1))))
                #print dctPair['img'], dctPair['msk']
                #dctFeatures = {}
                #for iF, strFeatureName in enumerate(self._oLearner.lstFeatureNames):
                #    dctFeatures[strFeatureName] = self._oLearner.dctFeatureData[className][iIdx][iF]
                oSample = Sample(dctPair['img'])
                lstResults.append(oSample)
                iIdx += 1
                #break
        return lstResults

    def getFeatureData(self, featureNames):
        self._loadInfos()
        lstFeatureData = []
        if len(featureNames) == 1:
            strFeatureName = featureNames[0]
            for strClassName, oClass in self.dctClassInfos.iteritems():
                aY, aX = numpy.histogram(oClass.features[strFeatureName], normed=True)
                lstData = [dict(x=fX, y=fY) for fX,fY in zip(aX, aY)]
                lstFeatureData.append(lstData)
        elif len(featureNames) == 2:
            for strClassName, oClass in self.dctClassInfos.iteritems():
                iSize = len(oClass.features.values()[0])
                lstData = [dict([(strFeatureName, oClass.features[strFeatureName][iIdx])
                                 for strFeatureName in featureNames])
                           for iIdx in range(iSize)]
                lstFeatureData.append(lstData)
        #print lstFeatureData
        return lstFeatureData
Example #6
0
class CellAnalyzer(PropertyManager):

    PROPERTIES = \
        dict(P =
                 StringProperty(True, doc=''),
             bCreateImages =
                 BooleanProperty(True, doc="Create output images"),
             iBinningFactor =
                 IntProperty(None,
                             is_mandatory=True,
                             doc=''),
             detect_objects =
                 BooleanProperty(True),


             time_holder =
                 InstanceProperty(None,
                                  TimeHolder,
                                  doc="Instance of TimeHolder.",
                                  is_mandatory=True),
            )

    __attributes__ = [Attribute('_channel_registry'),
                      Attribute('_iT'),
                      Attribute('_oLogger'),
                      ]

    def __init__(self, **dctOptions):
        super(CellAnalyzer, self).__init__(**dctOptions)
        self._oLogger = logging.getLogger(self.__class__.__name__)

    def initTimepoint(self, iT):
        self._channel_registry = OrderedDict()
        self._iT = iT
        self.time_holder.initTimePoint(iT)

    def register_channel(self, channel):
        self._channel_registry[channel.NAME] = channel

    def get_channel_names(self):
        return self._channel_registry.keys()

    def get_channel(self, name):
        return self._channel_registry[name]

    def process(self, apply=True, extract_features=True):
        # sort by Channel `RANK`
        channels = sorted(self._channel_registry.values())
        primary_channel = None
        for channel in channels:

            self.time_holder.prepare_raw_image(channel)

            if self.detect_objects:
                self.time_holder.apply_segmentation(channel, primary_channel)
                if extract_features:
                    self.time_holder.apply_features(channel)

                if primary_channel is None:
                    assert channel.RANK == 1
                    primary_channel = channel

        if apply:
            for channel in channels:
                self.time_holder.apply_channel(channel)

    def purge(self, features=None):
        for oChannel in self._channel_registry.values():
            if not features is None and oChannel.strChannelId in features:
                channelFeatures = features[oChannel.strChannelId]
            else:
                channelFeatures = None
            oChannel.purge(features=channelFeatures)

    def exportLabelImages(self, pathOut, compression='LZW'):
        for name, channel in self._channel_registry.iteritems():
            channel_id = channel.strChannelId
            for strRegion, oContainer in channel.dctContainers.iteritems():
                strPathOutImage = os.path.join(pathOut,
                                               channel_id,
                                               strRegion)
                safe_mkdirs(strPathOutImage)
                oContainer.exportLabelImage(os.path.join(strPathOutImage,
                                                         'P%s_T%05d.tif' % (self.P, self._iT)),
                                            compression)

    def getImageSize(self, name):
        oChannel = self._channel_registry[name]
        w = oChannel.meta_image.width
        h = oChannel.meta_image.height
        return (w,h)

    def render(self, strPathOut, dctRenderInfo=None,
               strFileSuffix='.jpg', strCompression='98', writeToDisc=True,
               images=None):
        lstImages = []
        if not images is None:
            lstImages += images

        if dctRenderInfo is None:
            for name, oChannel in self._channel_registry.iteritems():
                for strRegion, oContainer in oChannel.dctContainers.iteritems():
                    strHexColor, fAlpha = oChannel.dctAreaRendering[strRegion]
                    imgRaw = oChannel.meta_image.image
                    imgCon = ccore.Image(imgRaw.width, imgRaw.height)
                    ccore.drawContour(oContainer.getBinary(), imgCon, 255, False)
                    lstImages.append((imgRaw, strHexColor, 1.0))
                    lstImages.append((imgCon, strHexColor, fAlpha))
        else:
            for channel_name, dctChannelInfo in dctRenderInfo.iteritems():
                if channel_name in self._channel_registry:
                    oChannel = self._channel_registry[channel_name]
                    if 'raw' in dctChannelInfo:
                        strHexColor, fAlpha = dctChannelInfo['raw']
                        lstImages.append((oChannel.meta_image.image, strHexColor, fAlpha))

                    if 'contours' in dctChannelInfo:
                        # transform the old dict-style to the new tuple-style,
                        # which allows multiple definitions for one region
                        if type(dctChannelInfo['contours']) == types.DictType:
                            lstContourInfos = [(k,)+v
                                               for k,v in dctChannelInfo['contours'].iteritems()]
                        else:
                            lstContourInfos = dctChannelInfo['contours']

                        for tplData in lstContourInfos:
                            strRegion, strNameOrColor, fAlpha, bShowLabels = tplData[:4]

                            # draw contours only if region is present
                            if oChannel.has_region(strRegion):
                                if len(tplData) > 4:
                                    bThickContours = tplData[4]
                                else:
                                    bThickContours = False
                                if strNameOrColor == 'class_label':
                                    oContainer = oChannel.dctContainers[strRegion]
                                    oRegion = oChannel.get_region(strRegion)
                                    dctLabels = {}
                                    dctColors = {}
                                    for iObjId, oObj in oRegion.iteritems():
                                        iLabel = oObj.iLabel
                                        if not iLabel is None:
                                            if not iLabel in dctLabels:
                                                dctLabels[iLabel] = []
                                            dctLabels[iLabel].append(iObjId)
                                            dctColors[iLabel] = oObj.strHexColor
                                    #print dctLabels
                                    imgRaw = oChannel.meta_image.image
                                    imgCon2 = ccore.Image(imgRaw.width, imgRaw.height)
                                    for iLabel, lstObjIds in dctLabels.iteritems():
                                        imgCon = ccore.Image(imgRaw.width, imgRaw.height)
                                        oContainer.drawContoursByIds(lstObjIds, 255, imgCon, bThickContours, False)
                                        lstImages.append((imgCon, dctColors[iLabel], fAlpha))

                                        if type(bShowLabels) == types.BooleanType and bShowLabels:
                                        #    oContainer.drawTextsByIds(lstObjIds, lstObjIds, imgCon2)
                                        #else:
                                            oContainer.drawTextsByIds(lstObjIds, [str(iLabel)]*len(lstObjIds), imgCon2)
                                    lstImages.append((imgCon2, '#FFFFFF', 1.0))

                                else:
                                    oContainer = oChannel.dctContainers[strRegion]
                                    oRegion = oChannel.get_region(strRegion)
                                    lstObjIds = oRegion.keys()
                                    imgRaw = oChannel.meta_image.image
                                    imgCon = ccore.Image(imgRaw.width, imgRaw.height)
                                    if not strNameOrColor is None:
                                        oContainer.drawContoursByIds(lstObjIds, 255, imgCon, bThickContours, False)
                                    else:
                                        strNameOrColor = '#FFFFFF'
                                    lstImages.append((imgCon, strNameOrColor, fAlpha))
                                    if bShowLabels:
                                        imgCon2 = ccore.Image(imgRaw.width, imgRaw.height)
                                        oContainer.drawLabelsByIds(lstObjIds, imgCon2)
                                        lstImages.append((imgCon2, '#FFFFFF', 1.0))


        if len(lstImages) > 0:
            imgRgb = ccore.makeRGBImage([x[0].getView() for x in lstImages],
                                        [ccore.RGBValue(*hexToRgb(x[1])) for x in lstImages],
                                        [x[2] for x in lstImages])

            if writeToDisc:
                strFilePath = os.path.join(strPathOut, "P%s_T%05d%s" % (self.P, self._iT, strFileSuffix))
                safe_mkdirs(strPathOut)
                ccore.writeImage(imgRgb, strFilePath, strCompression)
                self._oLogger.debug("* rendered image written '%s'" % strFilePath)
            else:
                strFilePath = ''
            return imgRgb, strFilePath


    def collectObjects(self, plate_id, P, lstReader, oLearner, byTime=True):

        #channel_name = oLearner.strChannelId
        strRegionId = oLearner.strRegionId
        img_rgb = None

        self._oLogger.debug('* collecting samples...')

#        bSuccess = True
#        channels = sorted(self._channel_registry.values())
#        primary_cChannel = None
#        for channel2 in lstChannels:
#
#            self.time_holder.prepare_raw_image(channel)
#            self.time_holder.apply_segmentation(oChannel2, oPrimaryChannel)
#
#            if oPrimaryChannel is None:
#                assert oChannel2.RANK == 1
#                oPrimaryChannel = oChannel2
        self.process(apply = False, extract_features = False)

        # self._channel_registry
        oChannel = self._channel_registry[oLearner.channel_name]
        oContainer = oChannel.get_container(strRegionId)
        objects = oContainer.getObjects()

        object_lookup = {}
        for oReader in lstReader:
            lstCoordinates = None
            if (byTime and P == oReader.getPosition() and self._iT in oReader):
                lstCoordinates = oReader[self._iT]
            elif (not byTime and P in oReader):
                lstCoordinates = oReader[P]
            #print "moo", P, oReader.getPosition(), byTime, self._iT in oReader
            #print lstCoordinates, byTime, self.P, oReader.keys()

            if not lstCoordinates is None:
                #print self.iP, self._iT, lstCoordinates
                for dctData in lstCoordinates:
                    label = dctData['iClassLabel']
                    if (label in oLearner.dctClassNames and
                        dctData['iPosX'] >= 0 and
                        dctData['iPosX'] < oContainer.width and
                        dctData['iPosY'] >= 0 and
                        dctData['iPosY'] < oContainer.height):

                        center1 = ccore.Diff2D(dctData['iPosX'],
                                               dctData['iPosY'])

                        # test for obj_id "under" annotated pixel first
                        obj_id = oContainer.img_labels[center1]

                        # if not background: valid obj_id found
                        if obj_id > 0:
                            dict_append_list(object_lookup, label, obj_id)

                        # otherwise try to find nearest object in a search
                        # radius of 30 pixel (compatibility with CellCounter)
                        else:
                            dists = []
                            for obj_id, obj in objects.iteritems():
                                diff = obj.oCenterAbs - center1
                                dist_sq = diff.squaredMagnitude()
                                # limit to 30 pixel radius
                                if dist_sq < 900:
                                    dists.append((obj_id, dist_sq))
                            if len(dists) > 0:
                                dists.sort(lambda a,b: cmp(a[1], b[1]))
                                obj_id = dists[0][0]
                                dict_append_list(object_lookup, label, obj_id)

        object_ids = set(flatten(object_lookup.values()))
        objects_del = set(objects.keys()) - object_ids
        for obj_id in objects_del:
            oContainer.delObject(obj_id)

        self.time_holder.apply_features(oChannel)
        region = oChannel.get_region(strRegionId)

        learner_objects = []
        for label, object_ids in object_lookup.iteritems():
            class_name = oLearner.dctClassNames[label]
            hex_color = oLearner.dctHexColors[class_name]
            rgb_value = ccore.RGBValue(*hexToRgb(hex_color))
            for obj_id in object_ids:
                obj = region[obj_id]
                obj.iLabel = label
                obj.strClassName = class_name
                obj.strHexColor = hex_color

                if (obj.oRoi.upperLeft[0] >= 0 and
                    obj.oRoi.upperLeft[1] >= 0 and
                    obj.oRoi.lowerRight[0] < oContainer.width and
                    obj.oRoi.lowerRight[1] < oContainer.height):
                    iCenterX, iCenterY = obj.oCenterAbs

                    strPathOutLabel = os.path.join(oLearner.dctEnvPaths['samples'],
                                                   oLearner.dctClassNames[label])
                    safe_mkdirs(strPathOutLabel)

                    strFilenameBase = 'PL%s___P%s___T%05d___X%04d___Y%04d' % (plate_id, self.P, self._iT, iCenterX, iCenterY)

                    obj.sample_id = strFilenameBase
                    learner_objects.append(obj)

                    strFilenameImg = os.path.join(strPathOutLabel, '%s___img.png' % strFilenameBase)
                    strFilenameMsk = os.path.join(strPathOutLabel, '%s___msk.png' % strFilenameBase)
                    # FIXME: export Objects is segfaulting for objects
                    #        where its bounding box is touching the border
                    #        i.e. one corner point equals zero!
                    oContainer.exportObject(obj_id,
                                            strFilenameImg,
                                            strFilenameMsk)

                    oContainer.markObjects([obj_id], rgb_value, False, True)

                    #print obj_id, obj.oCenterAbs, iCenterX, iCenterY
                    print '*** CSdebug: drawFilledCircle', iCenterX, iCenterY
                    ccore.drawFilledCircle(ccore.Diff2D(iCenterX, iCenterY),
                                           3, oContainer.img_rgb, rgb_value)


        if len(learner_objects) > 0:
            oLearner.applyObjects(learner_objects)
            # we don't want to apply None for feature names
            oLearner.setFeatureNames(oChannel.lstFeatureNames)

        strPathOut = os.path.join(oLearner.dctEnvPaths['controls'])
        safe_mkdirs(strPathOut)
        oContainer.exportRGB(os.path.join(strPathOut,
                                          "P%s_T%05d_C%s_R%s.jpg" %\
                                           (self.P, self._iT, oLearner.strChannelId, oLearner.strRegionId)),
                            '90')
        img_rgb = oContainer.img_rgb
        return img_rgb


    def classifyObjects(self, oPredictor):
        channel_name = oPredictor.strChannelId
        strRegionId = oPredictor.strRegionId
        oChannel = self._channel_registry[channel_name]
        oRegion = oChannel.get_region(strRegionId)
        for iObjId, oObj in oRegion.iteritems():
            iLabel, dctProb = oPredictor.predict(oObj.aFeatures.copy(), oRegion.getFeatureNames())
            oObj.iLabel = iLabel
            oObj.dctProb = dctProb
            oObj.strClassName = oPredictor.dctClassNames[iLabel]
            oObj.strHexColor = oPredictor.dctHexColors[oObj.strClassName]