def __call__(self, img, bgsource = None, methods = ['subtract'], **kwargs): if bgsource is None: logger.error(("No background image given to " "RemoveBackgroundPreprocessor, doing nothing!")) return img if bgsource not in self.bgs: logger.debug("Loading background image {}".format(bgsource)) # Load background image try: self.bgs[bgsource] = self.manager.loadimage(bgsource) except IOError, fire.errors.ImageCannotBeLoadedError: logger.error(("Unable to load background image '{}', doing " "nothing!").format(bgsource)) return img # If preprocessing steps are not explicity given, use preprocessing # chain used for all images, up to the point where background is # removed if not 'preprocsteps' in kwargs: preprocsteps = self.get_previous_preprocsteps() if preprocsteps is None: return img else: preprocsteps = kwargs['preprocsteps'] self.bgs[bgsource] = self.manager.preprocess(self.bgs[bgsource], preprocsteps) self.bgs_nonzero[bgsource] = self.bgs[bgsource].copy() self.bgs_nonzero[bgsource][self.bgs[bgsource] == 0.] = (0.01 * self.bgs[bgsource].max()) logger.debug("Background image {} loaded".format(bgsource))
def smallest_uint_type(maxval): for dtype in (np.uint8, np.uint16, np.uint32, np.uint64): if maxval < np.iinfo(dtype).max: return dtype # Hopefully never happens, who has an image that fits that many areas? logger.error("No numpy uint type can hold {}".format(maxval)) return np.uint64
def process(self, configfile, infiles, overwrite = False): self.loadconfig(configfile) for infile in infiles: infile = os.path.abspath(infile) if not overwrite: ename = self.check_skip(infile, self.exportsteps) if ename is not None: logger.warning( ("Skipping '{}', rejected by exporter '{}'. Set " "overwrite = True to ignore.").format(infile, ename)) continue logger.info("Processing '{}'".format(infile)) try: img = self.loadimage(infile) except IOError, fire.errors.ImageCannotBeLoadedError: logger.error("Unable to load '{}'".format(infile)) continue img = self.preprocess(img, self.preprocsteps) # DEBUG #import numpy as np #np.save("testdata/img_preproc_cropped.npy", img) #from fire.debug import showimg, saveimg #showimg(img) #exit() #saveimg("testdata/img_preproc_cropped.png", img) detected = self.processchain(img, self.procsteps) self.export(infile, detected, self.exportsteps)
def __call__(self, img, just_filter = True): """just_filter: Will not binarise if set to True (default)""" try: return self.mh.edge.sobel(img, just_filter = just_filter) except ValueError: logger.error(("Sobel preprocessor can only work on greyscale " "images, doing nothing!")) return img
def loadimage(self, infile): fileext = os.path.splitext(infile)[1][1:] for loader in self.imgloaders: if fileext.lower() in loader.supported_file_types: return loader.load(infile) logger.error( "No image loader that can read {} files! (File: {})".format( fileext, infile)) raise fire.errors.ImageCannotBeLoadedError
def get_steps(self, steplist): steps = [] for step in steplist: try: method, args = step.items()[0] except AttributeError: # step is not a dict (no args) method = step args = [] if not isinstance(args, list): args = [args] # Does method exist? if not hasattr(self, method): logger.error("Unknown method: '{}', ignoring".format(method)) continue steps.append((method, args)) return steps
def get_previous_preprocsteps(self): # Find myself in preprocessor list mykey = None for key, preproc in self.manager.preprocessors.iteritems(): if preproc is self: mykey = key break if mykey is None: logger.error(("RemoveBackgroundProcessor lives outside of " "manager.preprocessors? Doing nothing!")) return None try: mypreprocindex = [ x[0] for x in self.manager.preprocsteps ].index(mykey) except ValueError: logger.error(("RemoveBackgroundProcessor is not in " "preprocessing chain? Doing nothing!")) return None return self.manager.preprocsteps[:mypreprocindex]
def __call__(self, img, croptype = "rect", **ppargs): if croptype == "rect": if not all(( z in ppargs for z in ['x', 'y', 'dx', 'dy'] )): logger.error(("Crop processor needs x, y, dx, and dy parameters" " for type 'rect'. Doing nothing!")) return img return img[ ppargs['y'] : ppargs['y'] + ppargs['dy'], ppargs['x'] : ppargs['x'] + ppargs['dx'] ] elif croptype == "circular": if not all(( z in ppargs for z in ['x', 'y', 'r'] )): logger.error(("Crop processor needs x, y, and r parameters for " "type 'circular'. Doing nothing!")) return img xmin = np.floor(ppargs['x'] - ppargs['r']) xmax = np.ceil(ppargs['x'] + ppargs['r']) + 1 ymin = np.floor(ppargs['y'] - ppargs['r']) ymax = np.ceil(ppargs['y'] + ppargs['r']) + 1 procimg = img[ymin:ymax, xmin:xmax] ys = np.arange(ymax - ymin) xs = np.arange(xmax - xmin) procimg[(ys[:, None] + ymin - ppargs['y'])**2 + (xs[None, :] + xmin - ppargs['x'])**2 > ppargs['r']**2] = procimg.min() procimg[(ys[:, None] + ymin - ppargs['y'])**2 + (xs[None, :] + xmin - ppargs['x'])**2 > (ppargs['r']+2)**2] = procimg.max() return procimg else: logger.error("Unknown crop method: '{}', doing nothing!".format( croptype))
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:]]