def next(self, seeking=False): """ Go to the next position (next iteration). seeking -- Boolean that indicates whether the explorer is calling next() from seek(). If True, the explorer should avoid unnecessary computation that would not affect the seek command. The last call to next() from seek() will be with seeking=False. """ BaseExplorer.next(self) if self.pointIndex is None: self.first() self.pointIndex += 1 if self.pointIndex < len(self.currentPoints): # Next fixation point for this image self._setOffset() else: # Ran out of points for this image image = self.position["image"] + 1 if image >= self.numImages: self.first() return while not self.names[image] in self.points: image += 1 if image >= self.numImages: self.first() return self.position["image"] = image self._firstPoint()
def update(self, **kwargs): """ Update state with new parameters from ImageSensor and call first(). """ numFilters = kwargs.get('numFilters', None) if numFilters is not None and self.allDimensions: # Remove existing filter dimensions for dimension in self.dimensions[:]: if type(dimension['name']) is int: self.dimensions.remove(dimension) # Reset the probabilities from the existing dimensions for d in self.dimensions: d['probability'] = None # Add the new filter dimensions self.dimensions += \ [self._newSweepDictionary(name=name) for name in range(numFilters)] numImages = kwargs.get('numImages', None) if numImages is not None and self.pattern: # Parse all the filenames self._parseFilenames(numImages) self._calculateProbabilities() BaseExplorer.update(self, **kwargs)
def __init__(self, sweepLength=4, numRepetitions=1, sweepOffMode=False, maxOffset=None, minVelocity=1, maxVelocity=3, seed=42, *args, **kwargs): """ @param sweepLen: number of presentations per sweep sequence. @param numRepetitions: number of times to present each inward sweep. """ BaseExplorer.__init__(self, *args, **kwargs) # Parameter checking if type(sweepLength) is not int or sweepLength < 1: raise RuntimeError("'sweepLength' should be a positive integer") if type(numRepetitions) is not int or numRepetitions < 1: raise RuntimeError("'numRepetitions' should be a positive integer") # Parameters self._sweepLength = sweepLength self._numRepetitions = numRepetitions self._minVelocity = minVelocity self._maxVelocity = maxVelocity self._sweepOffMode = sweepOffMode self._maxOffset = maxOffset # Internal state self._seqIndex = 0 self._repIndex = 0 self._state = None self._repMemory = None # Prepare PRNG self._rng = random.Random() self._rng.seed(seed)
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center=True) # Update the "home" position for the current image self._getHomePosition() if self._verbosity >= 1: print "BlockSpread: first():" # Set start position self._centerPosIdx = 0 # Which center point self._spreadPosIdx = 0 # radial position around the center point # Convert to X and Y offsets self._getPosition()
def __init__(self, numSteps, diagonals=False, jitterSize=0, *args, **kwargs): """ numSteps -- diagonals -- Whether to step along the diagonal jitterSize -- How much to jitter around each step of the onion trajectories. """ BaseExplorer.__init__(self, *args, **kwargs) self.numSteps = numSteps self.diagonals = diagonals if self.diagonals: self.offsetDelta = [[-1,-1],[-1,1],[1,1],[1,-1]] else: self.offsetDelta = [[-numSteps,-numSteps],[-numSteps,numSteps], \ [numSteps,numSteps],[numSteps,-numSteps]] if jitterSize == 0: self.jitter = [[0,0]] self.jitterLength = 1 else: # eg. jitterSize = 2 -> # self.jitter = [[-2,0],[-1,0],[1,0],[2,0], # [0,2],[0,1],[0,-1],[0,-2], # [0,0]] self.jitter = [] listi = range(-jitterSize,0) + range(1,jitterSize+1) for i in listi: self.jitter.append([i,0]) for i in listi: self.jitter.append([0,i]) self.jitter.append([0,0]) self.jitterLength = len(self.jitter) assert(self.jitterLength == 4*jitterSize+1)
def __init__(self, sweepDirections=['left', 'right', 'up', 'down'], shiftDuringSweep=1, sweepOffObject=False, *args, **kwargs): """ sweepDirections -- Directions for sweeping. Must be a list containing one or more of 'left', 'right', 'up', and 'down' for horizontal and vertical sweeps, or 'leftup', 'leftdown', 'rightup', and 'rightdown' for diagonal sweeps (or 'upleft, 'downleft', 'upright', and 'downright'). Can also be the string 'all', for all eight directions. shiftDuringSweep -- Number of pixels to jump with each step (during a sweep). sweepOffObject -- Whether the sensor can only include a part of the object, as specified by the bounding box. If False, it will only move to positions that include as much of the object as possible. """ BaseExplorer.__init__(self, *args, **kwargs) if sweepDirections == 'all': sweepDirections = ['left', 'right', 'up', 'down', 'leftdown', 'leftup', 'rightdown', 'rightup'] else: for direction in sweepDirections: if direction not in ('left', 'right', 'up', 'down', 'leftup', 'upleft', 'leftdown', 'downleft', 'rightup', 'upright', 'rightdown', 'downright'): raise RuntimeError('Unknown sweep direction: %s' % direction) if type(shiftDuringSweep) is not int: raise RuntimeError("'shiftDuringSweep' should be an integer") if type(sweepOffObject) not in (bool, int): raise RuntimeError("'sweepOffObject' should be a boolean") self.sweepDirections = sweepDirections self.shiftDuringSweep = shiftDuringSweep self.sweepOffObject = sweepOffObject
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self) if not self.numImages: return # Set up the list of filenames self.names = [] for i in xrange(self.numImages): path, filename = os.path.split(self.getImageInfo(i)["imagePath"]) name = os.path.join(os.path.split(path)[1], filename) self.names.append(name) # Find the first image with some fixation points image = 0 while not self.names[image] in self.points: # No fixation points for this image image += 1 if image >= self.numImages: raise RuntimeError("No fixation points for any loaded images") self.position["image"] = image self._firstPoint() self.position["reset"] = True
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center=False) if not self.numImages: return isBlank = True while isBlank: # Pick a random position if not self.numJumpsPerImage or self.lastImageIndex is None or \ (self.numJumpsThisImage % self.numJumpsPerImage == 0): # Pick new image image = self.pickRandomImage(self.random) self.lastImageIndex = image self.numJumpsThisImage = 0 else: image = self.lastImageIndex self.position['image'] = image self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() # Pick a random offset if self.spaceShape is not None: self.centerImage() # NOTE: self.position['offset'] is (x, y), whereas our spaceShape is # (height, width). Also note that the self.position['offset'] # direction is counter-intuitive: negative numbers move us to the RIGHT # and DOWN instead of LEFT and UP. xOffset = self.random.randint(-(self.spaceShape[1]//2), self.spaceShape[1]//2) yOffset = self.random.randint(-(self.spaceShape[0]//2), self.spaceShape[0]//2) #print "(yOffset, xOffset) = ", yOffset, xOffset self.position['offset'][0] += xOffset self.position['offset'][1] += yOffset else: ebbox = self._getEffectiveBoundingBox(filteredImages[0]) self.position['offset'] = [ self.random.randint(ebbox[0], ebbox[2]-1), self.random.randint(ebbox[1], ebbox[3]-1) ] # Check if the position is blank isBlank = self.isBlank(self.jumpOffObject) self.position['reset'] = True self.numJumpsThisImage += 1
def next(self, seeking=False): """ Go to the next position (next iteration). seeking -- Boolean that indicates whether the explorer is calling next() from seek(). If True, the explorer should avoid unnecessary computation that would not affect the seek command. The last call to next() from seek() will be with seeking=False. """ BaseExplorer.next(self) self._computeNextPosn()
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center=False) self._computeNextPosn()
def next(self, seeking=False): """ Go to the next position (next iteration). seeking -- Boolean that indicates whether the explorer is calling next() from seek(). If True, the explorer should avoid unnecessary computation that would not affect the seek command. The last call to next() from seek() will be with seeking=False. """ BaseExplorer.next(self) if self._verbosity >= 1: print "BlockSpread: next():" # ======================================================================== # Update to next position self._spreadPosIdx += 1 if self._spreadPosIdx == self._numSpreadOffsets: self._spreadPosIdx = 0 self._centerPosIdx += 1 # If we've run through all the center positions, advance to the next # filtered image if self._centerPosIdx == self._numCenterOffsets: self._centerPosIdx = 0 # -------------------------------------------------------------------- # Go to next filter for this image, or next image # Iterate through the filters first needNewImage = True for i in xrange(self.numFilters): self.position['filters'][i] += 1 if self.position['filters'][i] < self.numFilterOutputs[i]: needNewImage = False break else: self.position['filters'][i] = 0 # Go to the next image if ready if needNewImage: self.position['image'] += 1 if self.position['image'] == self.numImages: self.position['image'] = 0 # ----------------------------------------------------------------- # Get the home position for this new filtered image self._getHomePosition() # ======================================================================== # Get the X,Y corrdinates and reset signal if not seeking: self._getPosition()
def next(self, seeking=False): """ Go to the next position (next iteration). seeking -- Boolean that indicates whether the explorer is calling next() from seek(). If True, the explorer should avoid unnecessary computation that would not affect the seek command. The last call to next() from seek() will be with seeking=False. """ BaseExplorer.next(self) # If filters were changed, order may be invalid if self.order is None or \ len([x for x in self.order if type(x) == int]) != self.numFilters: # If user did not set a custom order, just create new one automatically if not self.customOrder: self.order = ["image"] self.order.extend(range(self.numFilters)) self.order += ["sweep"] # Otherwise, user needs to recreate the explorer with a new order else: raise RuntimeError("'order' is invalid. Must recreate explorer with " "valid order after changing filters.") if self.position['reset'] and self.blankWithReset: # Last iteration was a blank, so don't increment the position self.position['reset'] = False else: self.position['reset'] = False for x in reversed(self.order): if x == 'image': # Iterate the image self.position['image'] += 1 if self.position['image'] == self.numImages: self.position['image'] = 0 self.position['reset'] = True else: break elif x == 'sweep': # Iterate the sweep position nextImage = self._nextSweepPosition() if not nextImage: break else: # Iterate the filter with index x self.position['filters'][x] += 1 if self.position['filters'][x] == self.numFilterOutputs[x]: self.position['filters'][x] = 0 self.position['reset'] = True else: break if nextImage: self._firstSweepPosition()
def __init__(self, radius=1, stepsize=1, minradius=None, includeCenter=False, sweepOffObject=True, randomSelections=0, *args, **kwargs): """ radius - the radius of the spiral sweep """ if minradius is None: minradius = stepsize assert (radius >= 1) if not ((radius >= stepsize) and (radius % stepsize == 0)): raise RuntimeError("radius must be a multiple of stepsize") if not ((minradius >= stepsize) and (minradius % stepsize == 0)): raise RuntimeError("minradius must be a multiple of stepsize") if type(sweepOffObject) not in (bool, int): raise RuntimeError("'sweepOffObject' should be a boolean") BaseExplorer.__init__(self, *args, **kwargs) self.sweepOffObject = sweepOffObject # Generate a list of possible offsets for this stepsize and radius self.offsets = [] if includeCenter: self.offsets += [(0, 0)] for i in range(minradius, radius + 1, stepsize): # Generate top row (not including sides) self.offsets += [(x, -i) for x in range(-i + stepsize, i, stepsize)] # Generate right edge (including top row, but not bottom row) self.offsets += [(i, y) for y in range(-i, i, stepsize)] # Generate bottom edge (not including left edge, including right edge) self.offsets += [(x, i) for x in range(i, -i, -stepsize)] # Generate left edge (including top and bottom row) self.offsets += [(-i, y) for y in range(i, -i - stepsize, -stepsize)] self.index = 0 # User-set parameters to control random selection. self.randomSelections = randomSelections # The cache of randomly selected offsets for the current image/filter. self._selectedOffsets = None
def __init__(self, shift=1, aggregate='sum', *args, **kwargs): """ @param shift -- Number of pixels to move from the center ("radius" of the eye movement square). @param aggregate -- A function that's used by inference analysis to aggregate the results of different eye movement presentations. Valid values are 'sum', 'average', 'product' and 'max'. The default is 'sum'. """ BaseExplorer.__init__(self, *args, **kwargs) assert aggregate in ('sum', 'average', 'max', 'product') self.aggregate_func = aggregate self.shift = shift
def __init__(self, shift=1, aggregate="sum", *args, **kwargs): """ @param shift -- Number of pixels to move from the center ("radius" of the eye movement square). @param aggregate -- A function that's used by inference analysis to aggregate the results of different eye movement presentations. Valid values are 'sum', 'average', 'product' and 'max'. The default is 'sum'. """ BaseExplorer.__init__(self, *args, **kwargs) assert aggregate in ("sum", "average", "max", "product") self.aggregate_func = aggregate self.shift = shift
def __init__(self, radius=4, *args, **kwargs): """ @param radius: the distance from the center, in pixels, at which the sweeps start; @param numRepetitions: number of times to present each inward sweep. """ BaseExplorer.__init__(self, *args, **kwargs) # Parameter checking if type(radius) is not int or radius < 1: raise RuntimeError("'radius' should be a positive integer") # Parameters self._radius = radius # Internal state self._itersDone = 0
def __init__(self, shift=1, replacement=True, *args, **kwargs): """ shift -- Number of pixels to move from the center ("radius" of the eye movement square). replacement -- Whether the same image/position can be picked twice. """ BaseExplorer.__init__(self, *args, **kwargs) self.shift = shift self.replacement = replacement if not self.replacement: self.history = []
def __init__(self, sweepDirections=["right", "down"], shiftDuringSweep=1, shiftBetweenSweeps=1, sweepOffObject=False, order=None, *args, **kwargs): """ sweepDirections -- Directions for sweeping (a list containing one or more of 'left', 'right', 'up', and 'down'). shiftDuringSweep -- Number of pixels to jump with each step (during a sweep). shiftBetweenSweeps -- Number of pixels to jump in between sweeps (for example, when moving down a line after sweeping across). sweepOffObject -- Whether the sensor can only include a part of the object, as specified by the bounding box. If False, it will only move to positions that include as much of the object as possible. If True, it will sweep until all of the object moves off the sensor. If set to a floating point number between 0 and 1, then it will sweep until that fraction of the object moves off the sensor. order -- Order in which to iterate (outer to inner). Default progresses through switching images, filters, and sweeping, where switching images is the outer loop and sweeping is the inner loop. Should be a list containing 'image', 'sweep', and 0, 1, ... numFilters-1. """ BaseExplorer.__init__(self, *args, **kwargs) for direction in sweepDirections: if direction not in ('left', 'right', 'up', 'down'): raise RuntimeError("Unknown sweep direction: '%s'" % direction) if type(shiftDuringSweep) is not int: raise RuntimeError("'shiftDuringSweep' must be an integer") if type(shiftBetweenSweeps) is not int: raise RuntimeError("'shiftBetweenSweeps' must be an integer") if float(sweepOffObject) < 0 or float(sweepOffObject) > 1.0: raise RuntimeError("'sweepOffObject' should be a boolean, or floating point" " number between 0 and 1") if order is not None: if 'image' not in order or 'sweep' not in order: raise RuntimeError("'order' must contain both 'image' and 'sweep'") if len([x for x in order if type(x) == str]) > 2: raise RuntimeError("'order' must contain no other strings besides " "'image' and 'sweep'") self.customOrder = True else: self.customOrder = False self.sweepDirections = sweepDirections self.shiftDuringSweep = shiftDuringSweep self.shiftBetweenSweeps = shiftBetweenSweeps self.sweepOffObject = sweepOffObject self.order = order
def first(self, center=True): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center) self._resetIndex() offsets = self._getCurrentOffsets() # Set the 2 dimensions of the position. for i in (0, 1): self.position['offset'][i] = offsets[self.index][i]
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self) self.diagdiri = 0 self.diagi = 0 self.position['offset'][0] += self.numSteps self.cent = list(self.position['offset']) self.jitteri = 0
def first(self, center=True): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center) self._resetIndex() offsets = self._getCurrentOffsets() # Set the 2 dimensions of the position. for i in (0,1): self.position['offset'][i] = offsets[self.index][i]
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self) if not self.numImages: return if not self.replacement \ and len(self.history) == self.getNumIterations(None): # All images have been visited self.history = [] while True: self.position['image'] = self.pickRandomImage(self.random) self.position['filters'] = self.pickRandomFilters(self.random) index = self.random.randint(0, 8) historyItem = (self.position['image'], self.position['filters'][:], index) if self.replacement or historyItem not in self.history: # Use this position if not self.replacement: # Add to the history self.history.append(historyItem) # Calculate the offset from the eye movement index if index in (1, 2, 3): self.position['offset'][1] -= self.shift elif index in (5, 6, 7): self.position['offset'][1] += self.shift if index in (1, 7, 8): self.position['offset'][0] -= self.shift elif index in (3, 4, 5): self.position['offset'][0] += self.shift break self.position['reset'] = True
def __init__(self, jumpOffObject=False, numJumpsPerImage=None, numVisitsPerImage=None, spaceShape=None, *args, **kwargs): """ Parameters: ----------------------------------------------------------------- jumpOffObject: Whether the sensor can only include a part of the object, as specified by the bounding box. If False, it will only move to positions that include as much of the object as possible. numJumpsPerImage: The number of iterations for which RandomJump should dwell on one image before moving on to the next one. numVisitsPerImage: The number of times RandomJump should visit each image (and do numJumpsPerImage jumps on it). spaceShape: The (height, width) of the 2-D space to explore. This constrains how far away from the center point an image is allowed to be presented. """ BaseExplorer.__init__(self, *args, **kwargs) if type(jumpOffObject) not in (bool, int): raise RuntimeError("'jumpOffObject' should be a boolean") if numJumpsPerImage is not None and type(numJumpsPerImage) is not int: raise RuntimeError("'numJumpsPerImage' should be an integer") if numVisitsPerImage is not None and type(numVisitsPerImage) is not int: raise RuntimeError("'numVisitsPerImage' should be an integer") if numVisitsPerImage is not None and numJumpsPerImage is None: raise RuntimeError("Must specify 'numJumpsPerImage'" " when using 'numVisitsPerImage'") if spaceShape is not None and \ (len(spaceShape) != 2 or spaceShape[0] < 1 or spaceShape[1] < 1): raise RuntimeError("'spaceShape' should be a 2-item tuple specifying the" "(height, width) of the overall space to explore.") self.jumpOffObject = jumpOffObject self.numJumpsPerImage = numJumpsPerImage self.numVisitsPerImage = numVisitsPerImage self.spaceShape = spaceShape # Keeps track of how many jumps on this image self.numJumpsThisImage = 0 self.lastImageIndex = None
def __init__(self, radius=1, stepsize=1, minradius=None, includeCenter=False, sweepOffObject=True, randomSelections=0, *args, **kwargs): """ radius - the radius of the spiral sweep """ if minradius is None: minradius = stepsize assert(radius >= 1) if not ((radius >= stepsize) and (radius % stepsize == 0)): raise RuntimeError("radius must be a multiple of stepsize") if not ((minradius >= stepsize) and (minradius % stepsize == 0)): raise RuntimeError("minradius must be a multiple of stepsize") if type(sweepOffObject) not in (bool, int): raise RuntimeError("'sweepOffObject' should be a boolean") BaseExplorer.__init__(self, *args, **kwargs) self.sweepOffObject = sweepOffObject # Generate a list of possible offsets for this stepsize and radius self.offsets = [] if includeCenter: self.offsets += [(0,0)] for i in range(minradius, radius+1, stepsize): # Generate top row (not including sides) self.offsets += [(x, -i) for x in range(-i+stepsize, i, stepsize)] # Generate right edge (including top row, but not bottom row) self.offsets += [(i, y) for y in range(-i, i, stepsize)] # Generate bottom edge (not including left edge, including right edge) self.offsets += [(x, i) for x in range(i, -i, -stepsize)] # Generate left edge (including top and bottom row) self.offsets += [(-i, y) for y in range(i, -i-stepsize, -stepsize)] self.index = 0 # User-set parameters to control random selection. self.randomSelections = randomSelections # The cache of randomly selected offsets for the current image/filter. self._selectedOffsets = None
def seek(self, iteration=None, position=None): """ Seek to the specified position or iteration. iteration -- Target iteration number (or None). position -- Target position (or None). ImageSensor checks validity of inputs, checks that one (but not both) of position and iteration are None, and checks that if position is not None, at least one of its values is not None. Updates value of position. """ # Zero out the history when seeking to iteration 0. This so we can replicate # how random explorers behave in the vision framework and NVT. if iteration is not None and iteration == 0: if not self.replacement: self.history = [] BaseExplorer.seek(self, iteration=iteration, position=position)
def next(self, seeking=False): """ Go to the next position (next iteration). seeking -- Boolean that indicates whether the explorer is calling next() from seek(). If True, the explorer should avoid unnecessary computation that would not affect the seek command. The last call to next() from seek() will be with seeking=False. """ BaseExplorer.next(self) if self.position['reset'] and self.blankWithReset: # Last iteration was a blank, so don't increment the position self.position['reset'] = False else: self.position['reset'] = False self._nextSweepPosition() # Begin a new sweep if necessary if self.position['reset']: self.first()
def __init__(self, replacement=True, start=0, equalizeCategories=False, *args, **kwargs): """ replacement -- Whether the same image can be picked multiple times. start -- Number of random choices to skip at the beginning, useful when seeding the random number generator. """ BaseExplorer.__init__(self, *args, **kwargs) if type(replacement) not in (bool, int): raise RuntimeError("'replacement' should be a boolean") if type(start) is not int: raise RuntimeError("'start' should be an integer") self.replacement = replacement self.start = start self.equalizeCategories = equalizeCategories self.imagesByCat = None if not self.replacement: self.history = []
def __init__(self, filename, *args, **kwargs): """ filename -- Path to the file with the pickled dictionary mapping image filenames to fixation points. """ BaseExplorer.__init__(self, *args, **kwargs) # Load the fixation points self.points = pickle.load(open(filename)) self.pointIndex = None self.currentPoints = None # Retain just the enclosing directory and filename, not the full path self.doSaliencySize = True keys = self.points.keys() for key in keys: path, filename = os.path.split(key) key2 = os.path.join(os.path.split(path)[1], filename) if key2 != key: self.points[key2] = self.points[key] self.points.pop(key) if "saliencySize" not in self.points[key2]: self.doSaliencySize = False
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center=False) if not self.numImages: return # Pick a random direction and filtered image self.direction = self.random.choice(self.sweepDirections) self.position['image'] = self.random.randint(0, self.numImages - 1) for i in xrange(self.numFilters): self.position['filters'][i] = self.random.randint(0, self.numFilterOutputs[i] - 1) filteredImages = self.getFilteredImages() # Pick a random starting position on the appropriate edge of the image sbbox = self._getSweepBoundingBox(filteredImages[0]) if self.direction == 'left': self.position['offset'][0] = sbbox[2] - 1 self.position['offset'][1] = self.random.randint(sbbox[1], sbbox[3] - 1) elif self.direction == 'right': self.position['offset'][0] = sbbox[0] self.position['offset'][1] = self.random.randint(sbbox[1], sbbox[3] - 1) elif self.direction == 'up': self.position['offset'][0] = self.random.randint(sbbox[0], sbbox[2] - 1) self.position['offset'][1] = sbbox[3] - 1 elif self.direction == 'down': self.position['offset'][0] = self.random.randint(sbbox[0], sbbox[2] - 1) self.position['offset'][1] = sbbox[1] elif self.direction in ('leftup', 'upleft'): if self.random.randint(0,1): self.position['offset'][0] = \ self.random.randint(sbbox[0] + (sbbox[2] - sbbox[0])/2, sbbox[2] - 1) self.position['offset'][1] = sbbox[3] - 1 else: self.position['offset'][0] = sbbox[2] - 1 self.position['offset'][1] = \ self.random.randint(sbbox[1] + (sbbox[3] - sbbox[1])/2, sbbox[3] - 1) elif self.direction in ('leftdown', 'downleft'): if self.random.randint(0,1): self.position['offset'][0] = \ self.random.randint(sbbox[0] + (sbbox[2] - sbbox[0])/2, sbbox[2] - 1) self.position['offset'][1] = sbbox[1] else: self.position['offset'][0] = sbbox[2] - 1 self.position['offset'][1] = \ self.random.randint(sbbox[1], sbbox[3] - 1 - (sbbox[3] - sbbox[1])/2) elif self.direction in ('rightup', 'upright'): if self.random.randint(0,1): self.position['offset'][0] = \ self.random.randint(sbbox[0], sbbox[2] - 1 - (sbbox[2] - sbbox[0])/2) self.position['offset'][1] = sbbox[3] - 1 else: self.position['offset'][0] = sbbox[0] self.position['offset'][1] = \ self.random.randint(sbbox[1] + (sbbox[3] - sbbox[1])/2, sbbox[3] - 1) elif self.direction in ('rightdown', 'downright'): if self.random.randint(0,1): self.position['offset'][0] = \ self.random.randint(sbbox[0], sbbox[2] - 1 - (sbbox[2] - sbbox[0])/2) self.position['offset'][1] = sbbox[1] else: self.position['offset'][0] = sbbox[0] self.position['offset'][1] = \ self.random.randint(sbbox[1], sbbox[3] - 1 - (sbbox[3] - sbbox[1])/2) # Increment the position by a random amount in the range # [0, shiftDuringSweep) if self.shiftDuringSweep > 1: prevShiftDuringSweep = self.shiftDuringSweep self.shiftDuringSweep = self.random.randint(0, self.shiftDuringSweep) self._nextSweepPosition() self.shiftDuringSweep = prevShiftDuringSweep if self.position['reset']: self.first() self.position['reset'] = True
def __init__(self, spaceShape=(5, 5), spreadShape=None, spreadRadius=None, stepSize=1, resetEveryPos=False, verbosity=0, *args, **kwargs): """ spaceShape: The (height, width) of the 2-D space to explore. This sets the number of center-points. spreadShape: The shape (height, width) of the area around each center-point to explore if you want to spread in a square area. If this is specified, then radius must be None. spreadRadius: The radius of the spread if you want to spread in a circular area. If this is specified, then spreadShape must be None. When set to R, this explorer will visit all positions where: int(round(sqrt(dx*dx + dy*dy))) <= radius stepSize: The step size. How big each step is, in pixels. This controls *both* the spacing of the center-points within the block and the points we explore around each center-point. When spreadRadius is used to define the spread shape, then it will only visit points within stepSize*spreadRadius of the center point and insure that no two points it visits within this area are closer than stepSize from each other, where distance is defined as: int(round(sqrt(dx*dx + dy*dy))) This euclidean distance is NOT used to determine where the center points are - they are always laid out in a grid with x spacing and y spacing of stepSize. resetEveryPos: If False (the default), output a reset only when we first visit a new center point. This is what is normally used for training. If True, then output a reset on every iteration. This is often used for flash inference testing. """ BaseExplorer.__init__(self, *args, **kwargs) # Parameter checking if type(stepSize) is not int or stepSize < 1: raise RuntimeError("'stepSize' should be a positive integer") if len(spaceShape) != 2 or spaceShape[0] < 1 or spaceShape[1] < 1: raise RuntimeError( "'spaceShape' should be a 2-item tuple specifying the" "(height, width) of the overall space to explore.") if spreadShape is not None: if spreadRadius is not None: raise RuntimeError( "When spreadShape is used, spreadRadius must be set to None" ) if len(spreadShape ) != 2 or spreadShape[0] < 1 or spreadShape[1] < 1: raise RuntimeError( "'spreadShape' should be a 2-item tuple specifying the" "(height, width) of the of the area round each center point to" "explore.") if spreadRadius is None and spreadShape is None: raise RuntimeError( "Either spreadRadius or spreadShape must be defined") # Parameters self._spaceShape = spaceShape self._spreadShape = spreadShape self._spreadRadius = spreadRadius self._stepSize = stepSize self._verbosity = verbosity self._resetEveryPos = resetEveryPos # ===================================================================== # Init data structures # What is the range on the X and Y offsets of the center points? shape = self._spaceShape # If the shape is (1,1), special case of just 1 center point if shape[0] == 1 and shape[1] == 1: self._centerOffsets = [(0, 0)] else: xMin = -1 * (shape[1] // 2) xMax = xMin + shape[1] - 1 xPositions = range(stepSize * xMin, stepSize * xMax + 1, stepSize) yMin = -1 * (shape[0] // 2) yMax = yMin + shape[0] - 1 yPositions = range(stepSize * yMin, stepSize * yMax + 1, stepSize) self._centerOffsets = list(cross(yPositions, xPositions)) self._numCenterOffsets = len(self._centerOffsets) # ---------------------------------------------------------------- # Figure out the spread points based on spreadShape: if self._spreadShape is not None: # What is the range on the X and Y offsets of the spread points? shape = self._spreadShape # If the shape is (1,1), special case of no spreading around each center # point if shape[0] == 1 and shape[1] == 1: self._spreadOffsets = [(0, 0)] else: xMin = -1 * (shape[1] // 2) xMax = xMin + shape[1] - 1 xPositions = range(stepSize * xMin, stepSize * xMax + 1, stepSize) yMin = -1 * (shape[0] // 2) yMax = yMin + shape[0] - 1 yPositions = range(stepSize * yMin, stepSize * yMax + 1, stepSize) self._spreadOffsets = list(cross(yPositions, xPositions)) # Put the (0,0) entry first self._spreadOffsets.remove((0, 0)) self._spreadOffsets.insert(0, (0, 0)) # --------------------------------------------------------------------- # Figure out the spread points based on spreadRadius else: # Special case of spreadRadius = 0:, no spreading around each center point if spreadRadius == 0: self._spreadOffsets = [(0, 0)] # Build up a list of all offsets within spreadRadius * stepSize else: self._spreadOffsets = [] for y in range(-spreadRadius * stepSize, spreadRadius * stepSize + 1): for x in range(-spreadRadius * stepSize, spreadRadius * stepSize + 1): distance = int(round(math.sqrt(x * x + y * y))) if distance > spreadRadius * stepSize: continue # Make sure it's not closer than stepSize to another point within # the spread if not (x == 0 and y == 0) and stepSize > 1: tooClose = False for (otherY, otherX) in self._spreadOffsets: dx = x - otherX dy = y - otherY distance = int( round(math.sqrt(dx * dx + dy * dy))) if distance < stepSize: tooClose = True break if tooClose: continue self._spreadOffsets.append((y, x)) # Put the (0,0) entry first self._spreadOffsets.remove((0, 0)) self._spreadOffsets.insert(0, (0, 0)) if self._verbosity >= 1: print "Visiting spread positions:", self._spreadOffsets self._numSpreadOffsets = len(self._spreadOffsets) # Set start position self._centerPosIdx = 0 # Which center point self._spreadPosIdx = 0 # radial position around the center point
def first(self, seeking=False): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). seeking -- Passed from seek() through next() to avoid loading images unnecessarily when seeking. """ BaseExplorer.first(self, center=False) if not self.numImages: return if not self.replacement \ and len(self.history) == self.getNumIterations(None): # All images have been visited self.history = [] if self.equalizeCategories: # Breakdown the images by category if self.imagesByCat is None: categoryIndex = [] for k in range(self.numImages): categoryIndex += [self.getImageInfo(k)['categoryIndex']] categories = list(set(categoryIndex)) numCats = len(categories) catPopulation = {} imagesByCat = {} for catIndex in categories: #catPopulation[catIndex] = len([c for c in categoryIndex if c == catIndex]) imagesByCat[catIndex] = [k for k, c in enumerate(categoryIndex) if c == catIndex] catPopulation[catIndex] = len(imagesByCat[catIndex]) minNumSamples = min([pop for (cat, pop) in catPopulation.items()]) totalNumSamples = minNumSamples * numCats # Store self.imagesByCat = imagesByCat self.categories = categories self.numCategories = numCats self.nextCatIndex = 0 # Pick random image from next category thisCat = self.imagesByCat[self.nextCatIndex] #randomImageIndex = random.randint(0, len(thisCat)) self.position['image'] = self.random.choice(thisCat) self.position['filters'] = self.pickRandomFilters(self.random) self.nextCatIndex = (self.nextCatIndex + 1) % self.numCategories else: # Pick a random image and set of filters while self.start >= 0: finished = False while not finished: # Pick a position randomly self.position['image'] = self.pickRandomImage(self.random) self.position['filters'] = self.pickRandomFilters(self.random) # Pick again if not replacing and this position has been visited if self.replacement or (self.position['image'], self.position['filters']) not in self.history: finished = True if not self.replacement: # Remember this position self.history.append( (self.position['image'], self.position['filters'][:])) self.start -= 1 self.start = 0 if not seeking: self.centerImage()
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center=False) if not self.numImages: return # Pick a random dimension (exclude filters without multiple outputs) filters = [] for i in xrange(self.numFilters): if self.numFilterOutputs[i] > 1: filters.append(i) legalDimensions = self.dimensions[:] for d in self.dimensions: if type(d['name']) is int and d['name'] not in filters: legalDimensions.remove(d) # Choice is weighted by probabilities r = self.random.uniform(0, sum([d['probability'] for d in legalDimensions])) for i, d in enumerate(legalDimensions): if r <= d['probability']: self.dimension = d break r -= d['probability'] self.start = None restart = True while restart: self.position['reset'] = False restart = False # Translation sweep if self.dimension['name'] == 'translation': # Pick a random direction, image, and set of filters self.direction = self.random.choice(('left', 'right', 'up', 'down', 'leftdown', 'leftup', 'rightdown', 'rightup')) self.position['image'] = self.pickRandomImage(self.random) self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() ebbox = self._getEffectiveBoundingBox(filteredImages[0]) # Align starting position at zero offset position. forceAlignment = self.dimension.get('forceAlignment') if forceAlignment is not None and forceAlignment: self.position['offset'] = [0,0] # Pick a random starting position on the appropriate edge of the image else: self._firstTranslationPosition(ebbox, filteredImages[0]) # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextTranslationPosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) if not forceAlignment: self._nextTranslationPosition(randomShift=True) # Image sweep elif self.dimension['name'] == 'image': # Pick a random direction self.direction = self.random.choice(('up', 'down')) # Pick a random image and find the first or last image in the category image = self.pickRandomImage(self.random) startCategory = self.getImageInfo(image)['categoryIndex'] if self.direction == 'up': while image > 0 and \ self.getImageInfo(image-1)['categoryIndex'] == startCategory: image -= 1 else: while image < self.numImages - 1 and \ self.getImageInfo(image+1)['categoryIndex'] == startCategory: image += 1 self.position['image'] = image # Pick the filters self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() # Pick a random position within the bounding box ebbox = self._getEffectiveBoundingBox(filteredImages[0]) self.position['offset'] = [ self.random.randint(ebbox[0], ebbox[2]-1), self.random.randint(ebbox[1], ebbox[3]-1) ] # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextImagePosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) self._nextImagePosition(randomShift=True) # Parsed dimension sweep elif self.dimension['name'] in self.parsedDimensions: # Pick a random direction self.direction = self.random.choice(('up', 'down')) # Pick a random image image = self.pickRandomImage(self.random) # Create a list of filenames that will be included in this sweep self._createParsedDimension(image) # Find the first or last image if self.direction == 'up': self.parsedIndex = 0 else: self.parsedIndex = len(self.parsedIndices) - 1 self.position['image'] = self.parsedIndices[self.parsedIndex] # Pick the filters self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() # Pick a random position within the bounding box ebbox = self._getEffectiveBoundingBox(filteredImages[0]) self.position['offset'] = [ self.random.randint(ebbox[0], ebbox[2]-1), self.random.randint(ebbox[1], ebbox[3]-1) ] # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextParsedPosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) self._nextParsedPosition(randomShift=True) # Filter sweep else: # Pick a random direction, image, and set of filters self.direction = self.random.choice(('up', 'down')) self.position['image'] = self.pickRandomImage(self.random) self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() # Go to one end of the selected filter if self.direction == 'up': self.position['filters'][self.dimension['name']] = 0 else: self.position['filters'][self.dimension['name']] = \ self.numFilterOutputs[self.dimension['name']] - 1 # Pick a random position within the bounding box filteredImages = self.getFilteredImages() ebbox = self._getEffectiveBoundingBox(filteredImages[0]) self.position['offset'] = [ self.random.randint(ebbox[0], ebbox[2]-1), self.random.randint(ebbox[1], ebbox[3]-1) ] self.prevImageSize = filteredImages[0].size # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextFilterPosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) self._nextFilterPosition(randomShift=True) self.start = self._copyPosition(self.position) self.position['reset'] = True self.length = 1
def __init__(self, spaceShape=(5,5), spreadShape=None, spreadRadius=None, stepSize=1, resetEveryPos=False, verbosity=0, *args, **kwargs): """ spaceShape: The (height, width) of the 2-D space to explore. This sets the number of center-points. spreadShape: The shape (height, width) of the area around each center-point to explore if you want to spread in a square area. If this is specified, then radius must be None. spreadRadius: The radius of the spread if you want to spread in a circular area. If this is specified, then spreadShape must be None. When set to R, this explorer will visit all positions where: int(round(sqrt(dx*dx + dy*dy))) <= radius stepSize: The step size. How big each step is, in pixels. This controls *both* the spacing of the center-points within the block and the points we explore around each center-point. When spreadRadius is used to define the spread shape, then it will only visit points within stepSize*spreadRadius of the center point and insure that no two points it visits within this area are closer than stepSize from each other, where distance is defined as: int(round(sqrt(dx*dx + dy*dy))) This euclidean distance is NOT used to determine where the center points are - they are always laid out in a grid with x spacing and y spacing of stepSize. resetEveryPos: If False (the default), output a reset only when we first visit a new center point. This is what is normally used for training. If True, then output a reset on every iteration. This is often used for flash inference testing. """ BaseExplorer.__init__(self, *args, **kwargs) # Parameter checking if type(stepSize) is not int or stepSize < 1: raise RuntimeError("'stepSize' should be a positive integer") if len(spaceShape) != 2 or spaceShape[0] < 1 or spaceShape[1] < 1: raise RuntimeError("'spaceShape' should be a 2-item tuple specifying the" "(height, width) of the overall space to explore.") if spreadShape is not None: if spreadRadius is not None: raise RuntimeError ("When spreadShape is used, spreadRadius must be set to None") if len(spreadShape) != 2 or spreadShape[0] < 1 or spreadShape[1] < 1: raise RuntimeError("'spreadShape' should be a 2-item tuple specifying the" "(height, width) of the of the area round each center point to" "explore.") if spreadRadius is None and spreadShape is None: raise RuntimeError ("Either spreadRadius or spreadShape must be defined") # Parameters self._spaceShape = spaceShape self._spreadShape = spreadShape self._spreadRadius = spreadRadius self._stepSize = stepSize self._verbosity = verbosity self._resetEveryPos = resetEveryPos # ===================================================================== # Init data structures # What is the range on the X and Y offsets of the center points? shape = self._spaceShape # If the shape is (1,1), special case of just 1 center point if shape[0] == 1 and shape[1] == 1: self._centerOffsets = [(0,0)] else: xMin = -1 * (shape[1] // 2) xMax = xMin + shape[1] - 1 xPositions = range(stepSize * xMin, stepSize * xMax + 1, stepSize) yMin = -1 * (shape[0] // 2) yMax = yMin + shape[0] - 1 yPositions = range(stepSize * yMin, stepSize * yMax + 1, stepSize) self._centerOffsets = list(cross(yPositions, xPositions)) self._numCenterOffsets = len(self._centerOffsets) # ---------------------------------------------------------------- # Figure out the spread points based on spreadShape: if self._spreadShape is not None: # What is the range on the X and Y offsets of the spread points? shape = self._spreadShape # If the shape is (1,1), special case of no spreading around each center # point if shape[0] == 1 and shape[1] == 1: self._spreadOffsets = [(0,0)] else: xMin = -1 * (shape[1] // 2) xMax = xMin + shape[1] - 1 xPositions = range(stepSize * xMin, stepSize * xMax + 1, stepSize) yMin = -1 * (shape[0] // 2) yMax = yMin + shape[0] - 1 yPositions = range(stepSize * yMin, stepSize * yMax + 1, stepSize) self._spreadOffsets = list(cross(yPositions, xPositions)) # Put the (0,0) entry first self._spreadOffsets.remove((0,0)) self._spreadOffsets.insert(0, (0,0)) # --------------------------------------------------------------------- # Figure out the spread points based on spreadRadius else: # Special case of spreadRadius = 0:, no spreading around each center point if spreadRadius == 0: self._spreadOffsets = [(0,0)] # Build up a list of all offsets within spreadRadius * stepSize else: self._spreadOffsets = [] for y in range(-spreadRadius*stepSize, spreadRadius*stepSize+1): for x in range(-spreadRadius*stepSize, spreadRadius*stepSize+1): distance = int(round(math.sqrt(x*x + y*y))) if distance > spreadRadius*stepSize: continue # Make sure it's not closer than stepSize to another point within # the spread if not (x==0 and y==0) and stepSize > 1: tooClose = False for (otherY, otherX) in self._spreadOffsets: dx = x - otherX dy = y - otherY distance = int(round(math.sqrt(dx*dx + dy*dy))) if distance < stepSize: tooClose = True break if tooClose: continue self._spreadOffsets.append((y,x)) # Put the (0,0) entry first self._spreadOffsets.remove((0,0)) self._spreadOffsets.insert(0, (0,0)) if self._verbosity >= 1: print "Visiting spread positions:", self._spreadOffsets self._numSpreadOffsets = len(self._spreadOffsets) # Set start position self._centerPosIdx = 0 # Which center point self._spreadPosIdx = 0 # radial position around the center point
def next(self, seeking=False): """ Go to the next position (next iteration). seeking -- Boolean that indicates whether the explorer is calling next() from seek(). If True, the explorer should avoid unnecessary computation that would not affect the seek command. The last call to next() from seek() will be with seeking=False. """ BaseExplorer.next(self) if self.position['reset'] and self.blankWithReset: # Last iteration was a blank, so don't increment the position self.position['reset'] = False return self.position['reset'] = False prevPosition = self._copyPosition(self.position) # Translation sweep if self.dimension['name'] == 'translation': self._nextTranslationPosition() bounceDirections = self._getBounceDirections() while self.position['reset'] and self.length < self.minSweepLength and \ bounceDirections: # Sweep is too short - bounce and continue self.position = self._copyPosition(prevPosition) self.direction = bounceDirections.pop(0) self._nextTranslationPosition() # Image sweep elif self.dimension['name'] == 'image': self._nextImagePosition() if self.position['reset'] and self.length < self.minSweepLength: # Sweep is too short - bounce and continue self.position = prevPosition if self.direction == 'up': self.direction = 'down' else: self.direction = 'up' self._nextImagePosition() # Parsed dimension sweep elif self.dimension['name'] in self.parsedDimensions: self._nextParsedPosition() if self.position['reset'] and self.length < self.minSweepLength: # Sweep is too short - bounce and continue self.position = prevPosition if self.direction == 'up': self.direction = 'down' else: self.direction = 'up' self._nextParsedPosition() # Filter sweep else: self._nextFilterPosition() if self.position['reset'] and self.length < self.minSweepLength: # Sweep is too short - bounce and continue self.position = prevPosition if self.direction == 'up': self.direction = 'down' else: self.direction = 'up' self._nextFilterPosition() # Stop the sweep if it has fallen off the object if not self.position['reset'] \ and self.isBlank(self.dimension['sweepOffObject']): self.position['reset'] = True # Begin a new sweep if necessary if self.position['reset']: self.first() else: self.length += 1
def __init__(self, dimensions=None, sweepOffObject=False, crossDirectories=False, minSweepLength=0, pattern=None, *args, **kwargs): """ dimensions -- List of dimensions through which to sweep. Each element is a string with the name of a dimension, or a dictionary with more options (see below). 'translation', is normal translation sweeping, and 'image' holds the position constant as it moves across images. Include an integer from [0, numFilters-1] to specifying sweeping across the outputs of a certain filter while holding the rest of the position constant. If None, all dimensions are used, with default options. sweepOffObject -- Whether the sensor can only include a part of the object, as specified by the bounding box. If False, it will only move to positions that include as much of the object as possible. crossDirectories -- ** DEPRECATED ** If False and sweeping through images, the explorer looks at the filename of the images and stops sweeping when it would go to an image whose enclosing directory is different than the current image. minSweepLength -- Minimum length for each sweep. If a sweep is too short, image and filter sweeps continue smoothly if 'wraparound' is True, and otherwise they switch directions. Translation sweeps bounce into a new direction, excluding the opposite direction of the current sweep. pattern -- Pattern to use for extracting extra dimensions from image filenames. If you use the 'dimensions' argument, make sure to list these extra dimensions or they won't be used. Sweeps will hold all other dimensions constant while going through the selected dimension in sorted order. Can either be a tuple: (separator, dimensionName, dimensionName, ...), or a regular expression that extracts named dimensions. Example: If the filenames look like this: "Apple_1 50 90 foo.png", where "Apple_1" is the name of the object, "50" is the vertical angle, "90" is the horizontal angle, and "foo" is extra text to ignore, MultiSweep will sweep through the vertical and horizontal dimensions with either of these values for 'pattern' (and ['vertical', 'horizontal'] as the value for 'dimensions'): Tuple: (" ", "object", "vertical", "horizontal", None) The separator tells MultiSweep to split up the name on spaces, and the None argument specifies that the "foo" part of the name is not a dimension and should be ignored. Regular expression: "^(?P<object>\w+)\s(?P<vertical>\d+)\s(?P<horizontal>\d+)\s\w+$" "(?P<NAME>PATTERN)" is a Python-specific syntax for extracting named groups. Note that "object" is extracted as its own dimension even though it could have been ignored. This allows for multiple objects (such as "Apple_1" and "Apple_2") to appear in the same directory without MultiSweep generating sweeps across objects. After the dimensions are extracted, they are converted to ints or floats if possible. Then they are sorted using Python's list.sort() method. Dictionaries for dimensions take the following keywords: name : Name of the dimension, one of: - 'translation' (translation sweeping) - 'image' (cycle through images) - the name of a dimension extracted via 'pattern' - an integer specifying the index of a filter shift : Number of steps to jump on each iteration. For example, 2 means to jump by 2 pixels or 2 images. probability : Probability of randomly selecting this dimension. wraparound : Whether to 'wrap around' from one end of the dimension to the other, rather than stopping the sweep (or changing directions, if minSweepLength has not been met). ** ONLY IMPLEMENTED FOR SWEEPING THROUGH FILTER OUTPUTS WITH SHIFT == 1 ** sweepOffObject : Overrides the main 'sweepOffObject' parameter. """ BaseExplorer.__init__(self, *args, **kwargs) if type(sweepOffObject) not in (bool, int): raise RuntimeError("'sweepOffObject' should be a boolean") if type(crossDirectories) not in (bool, int): raise RuntimeError("'crossDirectories' should be a boolean") if type(minSweepLength) is not int: raise RuntimeError("'minSweepLength' should be an integer") self.sweepOffObject = sweepOffObject self.crossDirectories = crossDirectories self.minSweepLength = minSweepLength # Get dimensions to be parsed from filenames self.pattern = pattern self.parsedDimensions = [] if pattern: if type(pattern) in (list, tuple): if type(pattern) is tuple: pattern = list(pattern) self.parsedDimensions = pattern[1:] while None in self.parsedDimensions: self.parsedDimensions.remove(None) elif isinstance(pattern, basestring): self.parsedDimensions = re.findall("\(\?P<([^>]+)>", pattern) else: raise ValueError("'pattern' should be a list/tuple or string") # Extra instance variables for parsed dimensions self.parsedIndices = [] self.parsedIndex = 0 # Figure out all the dimensions if not dimensions: self.allDimensions = True self.dimensions = ['translation'] if not self.parsedDimensions: self.dimensions.append('image') else: self.allDimensions = False if type(dimensions) in (str, int): dimensions = [dimensions] self.dimensions = list(dimensions) # Add the dimensions to be parsed from filenames self.dimensions += self.parsedDimensions for i, d in enumerate(self.dimensions): if type(d) in (str, int): self.dimensions[i] = self._newSweepDictionary(name=d) else: self.dimensions[i] = self._newSweepDictionary(**d) self._calculateProbabilities()
def first(self): """ Set up the position. BaseExplorer picks image 0, offset (0,0), etc., but explorers that wish to set a different first position should extend this method. Such explorers may wish to call BaseExplorer.first(center=False), which initializes the position tuple but does not call centerImage() (which could cause unnecessary filtering to occur). """ BaseExplorer.first(self, center=False) if not self.numImages: return # Pick a random dimension (exclude filters without multiple outputs) filters = [] for i in xrange(self.numFilters): if self.numFilterOutputs[i] > 1: filters.append(i) legalDimensions = self.dimensions[:] for d in self.dimensions: if type(d['name']) is int and d['name'] not in filters: legalDimensions.remove(d) # Choice is weighted by probabilities r = self.random.uniform( 0, sum([d['probability'] for d in legalDimensions])) for i, d in enumerate(legalDimensions): if r <= d['probability']: self.dimension = d break r -= d['probability'] self.start = None restart = True while restart: self.position['reset'] = False restart = False # Translation sweep if self.dimension['name'] == 'translation': # Pick a random direction, image, and set of filters self.direction = self.random.choice( ('left', 'right', 'up', 'down', 'leftdown', 'leftup', 'rightdown', 'rightup')) self.position['image'] = self.pickRandomImage(self.random) self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() ebbox = self._getEffectiveBoundingBox(filteredImages[0]) # Align starting position at zero offset position. forceAlignment = self.dimension.get('forceAlignment') if forceAlignment is not None and forceAlignment: self.position['offset'] = [0, 0] # Pick a random starting position on the appropriate edge of the image else: self._firstTranslationPosition(ebbox, filteredImages[0]) # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextTranslationPosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) if not forceAlignment: self._nextTranslationPosition(randomShift=True) # Image sweep elif self.dimension['name'] == 'image': # Pick a random direction self.direction = self.random.choice(('up', 'down')) # Pick a random image and find the first or last image in the category image = self.pickRandomImage(self.random) startCategory = self.getImageInfo(image)['categoryIndex'] if self.direction == 'up': while image > 0 and \ self.getImageInfo(image-1)['categoryIndex'] == startCategory: image -= 1 else: while image < self.numImages - 1 and \ self.getImageInfo(image+1)['categoryIndex'] == startCategory: image += 1 self.position['image'] = image # Pick the filters self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() # Pick a random position within the bounding box ebbox = self._getEffectiveBoundingBox(filteredImages[0]) self.position['offset'] = [ self.random.randint(ebbox[0], ebbox[2] - 1), self.random.randint(ebbox[1], ebbox[3] - 1) ] # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextImagePosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) self._nextImagePosition(randomShift=True) # Parsed dimension sweep elif self.dimension['name'] in self.parsedDimensions: # Pick a random direction self.direction = self.random.choice(('up', 'down')) # Pick a random image image = self.pickRandomImage(self.random) # Create a list of filenames that will be included in this sweep self._createParsedDimension(image) # Find the first or last image if self.direction == 'up': self.parsedIndex = 0 else: self.parsedIndex = len(self.parsedIndices) - 1 self.position['image'] = self.parsedIndices[self.parsedIndex] # Pick the filters self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() # Pick a random position within the bounding box ebbox = self._getEffectiveBoundingBox(filteredImages[0]) self.position['offset'] = [ self.random.randint(ebbox[0], ebbox[2] - 1), self.random.randint(ebbox[1], ebbox[3] - 1) ] # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextParsedPosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) self._nextParsedPosition(randomShift=True) # Filter sweep else: # Pick a random direction, image, and set of filters self.direction = self.random.choice(('up', 'down')) self.position['image'] = self.pickRandomImage(self.random) self.position['filters'] = self.pickRandomFilters(self.random) filteredImages = self.getFilteredImages() # Go to one end of the selected filter if self.direction == 'up': self.position['filters'][self.dimension['name']] = 0 else: self.position['filters'][self.dimension['name']] = \ self.numFilterOutputs[self.dimension['name']] - 1 # Pick a random position within the bounding box filteredImages = self.getFilteredImages() ebbox = self._getEffectiveBoundingBox(filteredImages[0]) self.position['offset'] = [ self.random.randint(ebbox[0], ebbox[2] - 1), self.random.randint(ebbox[1], ebbox[3] - 1) ] self.prevImageSize = filteredImages[0].size # Increment the start position until it is not blank while self.isBlank(self.dimension['sweepOffObject']): self._nextFilterPosition(shift=1) if self.position['reset'] or not self.isValid(): restart = True break if restart: continue # Increment the position by a random amount in the range [0, shift) self._nextFilterPosition(randomShift=True) self.start = self._copyPosition(self.position) self.position['reset'] = True self.length = 1