예제 #1
0
 def __call__(self, img, prev_detected, **params):
     if "tiles" in params:
         params["tiles_v"] = params["tiles"]
         params["tiles_h"] = params["tiles"]
     elif not ("tiles_v" in params and "tiles_h" in params):
         logger.error(
             (
                 "Invalid tiling information given to "
                 "TiledFCDProcessor. Provide either 'tiles' or both 'tiles_h' "
                 "and 'tiles_v'."
             )
         )
         return []
     # Copy given parameters and check for completeness
     self.p.update(params)
     if not self.all_params_set(params):
         logger.critical("First FCD parameter set must be complete")
         return []
     if self.img is None:
         self.img = np.copy(img)
     if self.neighbourhood_max_img is None and self.p["mincenterlevel"] is not None:
         self.neighbourhood_max_img = self.generic_filter(self.img, np.max, 3)
     if self.prev_detected is None:
         self.prev_detected = list(prev_detected)  # copy
     # Process
     firstnewcircle = len(self.allcircles)
     logger.debug("Preprocessing image...")
     # try:
     #    import pickle
     #    gradcircles = pickle.load(open("testdata/circles.pickle_5tiles", 'r'))
     # except IOError:
     if True:
         img_preproc = self.preprocess(self.img, self.p["gaussian"], self.p["sobel"])
         logger.debug("Computing gradient...")
         grads = self.tiled_gradients(
             img_preproc, prev_detected, self.p["tiles_v"], self.p["tiles_h"], self.p["maxr"] + 3
         )
         gradcircles = []
         for i, grad in enumerate(grads):
             logger.debug("Tile {} / {}".format(i + 1, len(grads)))
             logger.debug("Finding circle candidates...")
             candidates = self.findcandidates(
                 grad,
                 self.p["alpha"],
                 self.p["beta"],
                 self.p["gamma"],
                 self.p["minnorm"],
                 self.p["maxr"],
                 self.p["mincenterlevel"],
             )
             logger.debug("Number of candidates: {}".format(len(candidates)))
             logger.debug("Clustering...")
             circles = self.cluster(
                 candidates,
                 self.p["minr"],
                 self.p["maxr"],
                 self.p["radiusscaler"],
                 self.p["minmembers"],
                 self.p["epsilon"],
                 self.p["minsamples"],
                 self.p["maxangspread"],
             )
             logger.debug("Number of detected circles: {}".format(len(circles)))
             # Attach index of this tile to circles
             circles = np.hstack((circles, i * np.ones((circles.shape[0], 1))))
             gradcircles.append(circles)
         # import pickle
         # pickle.dump(gradcircles, open("testdata/circles.pickle", 'w'), -1)
     logger.debug("Cleaning circle list...")
     self.totmergers = 0
     self.totoverl = 0
     for i in range(self.p["tiles_v"] - 1):
         for j in range(self.p["tiles_h"] - 1):
             logger.debug(
                 "Circle group {} / {}".format(
                     i * (self.p["tiles_h"] - 1) + j + 1, (self.p["tiles_v"] - 1) * (self.p["tiles_h"] - 1)
                 )
             )
             tileindices = (
                 i * self.p["tiles_h"] + j,
                 i * self.p["tiles_h"] + j + 1,
                 (i + 1) * self.p["tiles_h"] + j,
                 (i + 1) * self.p["tiles_h"] + j + 1,
             )
             # Put circles of four-tile-groups into same list and clean
             groupcircles = np.concatenate(tuple(gradcircles[ti] for ti in tileindices))
             groupcircles = self.cleancirclelist(groupcircles)
             # Split returned list back into corresponding gradcircles
             for x in tileindices:
                 gradcircles[x] = groupcircles[groupcircles[:, -1] == x]
     logger.debug("Total mergers: {}".format(self.totmergers))
     logger.debug("Total overlaps: {}".format(self.totoverl))
     newcircles = np.concatenate(gradcircles)
     logger.debug("Number of new circles: {}".format(len(newcircles)))
     self.allcircles = np.concatenate((self.allcircles, newcircles))
     return [DiskInfo(c[0], c[1], c[2]) for c in self.allcircles[firstnewcircle:]]
예제 #2
0
    def __call__(self, img, prev_detected, **params):
        """Get list of circles in image using FCD.

        Args:
            img: Image to process (as nparray)
            gaussian: standard deviation for Gaussian kernel
            sobel: boolean value specifying whether to apply sobel
                filter
            minnorm: Gradient norm cutoff
            alpha: FCD gradient angle difference tolerance
            beta: FCD connecting line angle difference tolerance
            gamma: FCD relative gradient norm difference tolerance
            minr: Lower radius cutoff
            maxr: Upper radius cutoff
            radiusscaler: DBSCAN preprocessing radius coefficient
            minmembers: Minimum number of cluster members PER UNIT
                RADIUS for a cluster to be considered a detected circle
            epsilon: DBSCAN neighbourhood size
            minsamples: DBSCAN minimum cluster density in neighbourhood
            maxangspread: TODO DOCUMENT THIS

        Returns:
            A list of DiskInfos
        """
        # Copy given parameters and check for completeness
        self.p.update(params)
        if not self.all_params_set(params):
            logger.critical("First FCD parameter set must be complete")
            return []
        # Figure out if we can use some previous calculations
        startat = self.where_to_start(params)
        logger.debug("Starting at {}".format(startat))
        if self.img is None:
            self.img = np.copy(img)
        if self.neighbourhood_max_img is None and self.p["mincenterlevel"] is not None:
            self.neighbourhood_max_img = self.generic_filter(self.img, np.max, 3)
        if self.prev_detected is None:
            self.prev_detected = list(prev_detected)  # copy
        # Process
        firstnewcircle = len(self.allcircles)
        if startat <= self.PREPROCESS:
            logger.debug("Preprocessing image...")
            self.img_preproc = self.preprocess(self.img, self.p["gaussian"], self.p["sobel"])
        if startat <= self.GRADIENT:
            logger.debug("Computing gradient...")
            self.grad = self.gradient(self.img_preproc, prev_detected)
        if startat <= self.FINDCANDIDATES:
            logger.debug("Finding circle candidates...")
            self.candidates = self.findcandidates(
                self.grad,
                self.p["alpha"],
                self.p["beta"],
                self.p["gamma"],
                self.p["minnorm"],
                self.p["maxr"],
                self.p["mincenterlevel"],
            )
            logger.debug("Number of candidates: {}".format(len(self.candidates)))
        if startat <= self.CLUSTER:
            logger.debug("Clustering...")
            circles = self.cluster(
                self.candidates,
                self.p["minr"],
                self.p["maxr"],
                self.p["radiusscaler"],
                self.p["minmembers"],
                self.p["epsilon"],
                self.p["minsamples"],
                self.p["maxangspread"],
            )
            logger.debug("Number of detected circles: {}".format(len(circles)))
            # Shift circles by current offset and append index of this
            # parameter set to all circles
            if len(circles) > 0:
                newcircles = np.hstack((circles, self.paramindex * np.ones((circles.shape[0], 1))))
                self.allcircles = np.append(self.allcircles, newcircles, axis=0)
            # OLD:
            #   All detected circles, EXCEPT THE ONES JUST DETECTED IN THIS
            #   RUN, should be removed for future calls to findcandidates
            # NOW:
            #   All detected circles are removed from the gradient map for
            #   future calls to findcandidates
            # return allcircles
            logger.debug("Cleaning circle list...")
            self.allcircles = self.cleancirclelist(self.allcircles)
            logger.debug("Number of new circles: {}".format(len(self.allcircles) - firstnewcircle))
            self.paramindex += 1
        return [DiskInfo(c[0], c[1], c[2]) for c in self.allcircles[firstnewcircle:]]
예제 #3
0
파일: manager.py 프로젝트: jdemaeyer/fire
 def loadconfig(self, configfile):
     logger.debug("Loading configuration from '{}'".format(configfile))
     # Lazy load yaml so we don't require it
     if configfile.endswith('.yml') or configfile.endswith('.yaml'):
         import yaml
         with open(configfile, 'r') as f:
             cfg = yaml.load(f)
     else:
         # FIXME: Assume JSON?
         logger.critical("Unknown config file type")
         raise NotImplementedError
     # Set default modules if none given:
     if not 'imgloaders' in cfg:
         cfg['imgloaders'] = [
             'fire.imageloaders.MahotasImageLoader',
             ]
     if not 'preprocessors' in cfg:
         cfg['preprocessors'] = {
             'crop': 'fire.preprocessors.CropPreprocessor',
             'makefloat': 'fire.preprocessors.MakeFloatPreprocessor',
             'greyscale': 'fire.preprocessors.GreyscalePreprocessor',
             'removebg': 'fire.preprocessors.RemoveBackgroundPreprocessor',
             }
     if not 'processors' in cfg:
         cfg['processors'] = {
             'threshold': 'fire.processors.ThresholdProcessor',
             'watershed': 'fire.processors.WatershedProcessor',
             'fcd': 'fire.processors.FCDProcessor',
             'tiledfcd': 'fire.processors.TiledFCDProcessor',
             'diskextend': 'fire.processors.DiskExtendProcessor',
             'removeouter': 'fire.processors.RemoveOuterProcessor',
             'dirtyremoveedges': 'fire.processors.DirtyRemoveEdgesProcessor',
             }
     if not 'exporters' in cfg:
         cfg['exporters'] = {
             'string': 'fire.exporters.StringExporter',
             'save': 'fire.exporters.SaveExporter',
             }
     # Load and set config
     for what in ('imgloaders', ):
         instances = []
         for modclass in cfg[what]:
             modulename, classname = modclass.rsplit('.', 1)
             mod = import_module(modulename)
             instances.append(getattr(mod, classname)(manager = self))
         setattr(self, what, instances)
     for what in ('preprocessors', 'processors', 'exporters'):
         instances = {}
         for modname, modclass in cfg[what].items():
             modulename, objectname = modclass.rsplit('.', 1)
             mod = import_module(modulename)
             obj = getattr(mod, objectname)
             if isinstance(obj, type):
                 # obj is a class and should be initialised
                 instances[modname] = obj(manager = self)
             else:
                 # Assume that obj is a function
                 instances[modname] = obj
         setattr(self, what, instances)
     for what in ('preprocsteps', 'procsteps', 'exportsteps'):
         steplist = []
         for rawstep in cfg[what]:
             if isinstance(rawstep, dict):
                 stepname = rawstep.keys()[0]
                 steplist.append( (stepname, {} if rawstep[stepname] is None
                                                else rawstep[stepname]) )
             else:
                 steplist.append( (rawstep, {}) )
         setattr(self, what, steplist)