def startLoad(self, dirpath): '''Creates a load thread to process the current directory. If a directory has already been chosen, the display will be reset first. ''' #print 'Load Started' if self.hasImage == True: self.initData() self.loadimage = LoadThread(self.jobqueue, dirpath) self.loadimage.start() return
class ProcessCenter(HasTraits): '''Delegates tasks to the appropriate resources and stores data. Manages GUI events and decides who should handle them. Also, serves as the central data structure to store all of the information related to the current data set. ''' ############################################## # Initialize ############################################## def __init__(self, **kwargs): super(ProcessCenter, self).__init__() self.processing_job = threading.Thread(target=self.processJob) self.processing_job.daemon = True self.jobqueue = Queue.Queue() self.add_trait('display', Display(self.jobqueue)) self.add_trait('datalist', List()) self.add_trait('datalistlength', Int()) self.add_trait('message', Str('')) self.add_trait('cache', Instance(ImageCache, ImageCache())) self.add_trait('pic', Instance(Image)) self.add_trait('hasImage', Bool()) self.initDisplay() self.initData() return def initDisplay(self): '''Plots are initialized as None. This allows for consistency with the plot methods of the Display class. They will be created when these methods are called the first time. ''' self.imageplot = None self.histogram = None self.plot1d = None return def initData(self): '''Initializes all values before a data set is chosen. This method is used both at start and when switching directories in order to reset the display and internal mechanisms. ''' del self.datalist[:] self.datalistlength = 0 self.message = '' self.hasImage = False self.cache.clear() self.newndx = -1 self.rrplots = {} pic = Image(-1, '') pic.data = np.zeros((2048, 2048)) self.pic = pic self.plotData() self.on_trait_change(self.plotData, 'pic', dispatch='new') return ############################################## # Jobs ############################################## def addNewImage(self, path, **kwargs): '''Adds a new image to the list of data in the directory. path -- the filepath of the image Displays warning if there is no associated metadata file named path.metadata. ''' #print 'Image Added:' n = len(self.datalist) self.datalist.append(Image(n, path)) self.hasImage = True self.datalistlength += 1 if not self.datalist[n].metadata: self.message = 'No metadata found for %s.' % os.path.split(path)[1] print self.message return def plotData(self): '''Updates the plots to display data related to the current image.''' #print 'Plot Data' self.pic.load() self.imageplot = self.display.plotImage(self.pic, self.imageplot) self.histogram = self.display.plotHistogram(self.pic, self.histogram) self.plot1d = self.display.plot1DCut(self.pic, self.plot1d) return def startLoad(self, dirpath): '''Creates a load thread to process the current directory. If a directory has already been chosen, the display will be reset first. ''' #print 'Load Started' if self.hasImage == True: self.initData() self.loadimage = LoadThread(self.jobqueue, dirpath) self.loadimage.start() return def initCache(self): '''Initializes the cache by placing the first 2 images in the cache.''' #print 'Init Cache' self.pic = self.datalist[0] for i in range(2): pic = self.datalist[i] self.cache.append(pic) pic.load() return def changeIndex(self, newndx): '''Determines how the new image selection should be processed.''' #print 'Change Index' self.newndx = newndx currentpos = self.pic.n if newndx - currentpos == -1: #print 'Click left' self.updateCache('left') elif newndx - currentpos == 1: #print 'Click right' self.updateCache('right') elif newndx - currentpos == 0: #print 'Click same' return elif newndx < self.datalistlength and newndx >= 0: #print 'Click skip' self.updateCache('click') return def updateCache(self, strnext): '''Updates the image cache based on the current image. strnext -- the type of traversal: either left, right, or click | Warning: No images loaded. | Warning: Cannot traverse LEFT. | Warning: Cannot traverse RIGHT. ''' #print 'Update Cache' #print self.cache n = self.pic.n if n == -1: self.message = 'WARNING: No images loaded.' print self.message return if strnext == 'left': self.newndx = n - 1 #print '%d -> %d' % (n, self.newndx) if n == 0: self.message = 'WARNING: Cannot traverse LEFT.' print self.message return else: self._innerCache(n, -1) elif strnext == 'right': self.newndx = n + 1 #print '%d -> %d' % (n, self.newndx) if n == self.datalistlength - 1: self.message = 'WARNING: Cannot traverse RIGHT.' print self.message return else: self.cache.reverse() self._innerCache(n, 1) self.cache.reverse() elif strnext == 'click': #print '%d -> %d' % (n, self.newndx) self.cache.clear() if self.newndx == 0: self.initCache() else: self.pic = self.datalist[self.newndx] self.cache.append(self.datalist[self.newndx-1]) self.cache.append(self.pic) if self.newndx != self.datalistlength - 1: self.cache.append(self.datalist[self.newndx+1]) else: self.cache.append(Image(-1, '')) #print self.cache return def _innerCache(self, n, i): '''Internal cache method that deals with cache logic when updating.''' self.pic = self.cache.popleft() self.cache.appendleft(self.pic) if (n > 1 and i == -1) or (n < self.datalistlength-2 and i == 1): pic = self.datalist[n+i*2] self.cache.appendleft(pic) if (n == 1 and i == -1) or (n == self.datalistlength-2 and i == 1): self.cache.pop() return # TODO: As more RRs are supported, move them to a separate file. def countLowPixels(self, image): '''Finds the percentage of pixels below the selected threshold. image -- Image object ''' selection = self.display._selection data = image.ravel() limit = selection[0] count = np.count_nonzero(data < limit) rv = count/float(np.size(data)) return rv*100 def countHighPixels(self, image): '''Finds the percentage of pixels above the selected threshold. image -- Image object ''' selection = self.display._selection data = image.ravel() limit = selection[1] count = np.count_nonzero(data > limit) rv = count/float(np.size(data)) return rv*100 def createRRPlot(self, rrchoice): '''Generates a new plot based on the RR given and the current data. rrchoice -- the reduced representation | Warning: RR Plot Cannot be (Re)created | Warning: No RR selected. ''' if self.datalistlength == 0: self.message = 'WARNING: RR Plot Cannot be (Re)created' print self.message return elif rrchoice == 'Choose a Reduced Representation': self.message = 'WARNING: No RR selected.' print self.message return if rrchoice == 'Mean': f = lambda x: np.mean(x) elif rrchoice == 'Total Intensity': f = lambda x: np.sum(x) elif rrchoice == 'Standard Deviation': f = lambda x: np.std(x) elif rrchoice == '% Pixels Below Threshold': if self.display._selection != None: f = self.countLowPixels else: self.message = 'A range selection must be chosen.' print self.message return elif rrchoice == '% Pixels Above Threshold': if self.display._selection != None: f = self.countHighPixels else: self.message = 'A range selection must be chosen.' print self.message return if rrchoice not in self.rrplots: self.rrplots[rrchoice] = rrplot = self.display.plotRRMap( np.array([0]), rrchoice, None) else: return rrdata = np.array([]) self.message = 'Generating RR Plot........' print self.message for i, image in enumerate(self.datalist): image.load() self.message = '%d: %s........Loaded' % (i+1, image.name) print self.message rr = f(image.data) rrdata = np.append(rrdata, rr) rrplot = self.display.plotRRMap(rrdata, rrchoice, rrplot) image.data = None self.message = 'Loading Complete.' print self.message return ############################################## # Job Processing ############################################## def startProcessJob(self): '''Starts a thread to process tasks in the jobqueue.''' self.processing_job.start() return def processJob(self): '''Translates a job into the appropriate method calls. A job must be in the following form: ['task', [kwargs]] ''' while True: # retrieve job data jobdata = self.jobqueue.get(block=True) jobtype = jobdata[0] kwargs = jobdata[1] if len(jobdata)==2 else {} # deal with different jobs if jobtype == 'newimage': self.addNewImage(**kwargs) elif jobtype == 'updatecache': self.updateCache(*kwargs) elif jobtype == 'initcache': self.initCache() elif jobtype == 'plotrr': self.createRRPlot(*kwargs) elif jobtype == 'changendx': self.changeIndex(*kwargs) elif jobtype == 'startload': self.startLoad(*kwargs) elif jobtype == 'updatecmap': self.display.updateColorMap(*kwargs) elif jobtype == 'updatemsg': self.message = jobdata[1] self.jobqueue.task_done() return