def on_touch_up(self, touch): global userShape wordToLearn = wordManager.getCurrentCollection() if len(userShape) < 5: closeFigures(figuresToClose = range(1,len(wordToLearn)+1)) wordToLearn = raw_input("Next word:\n") newWord(wordToLearn) userInputCapture.display_grid(numColumns = len(wordToLearn)) else: userShape = downsampleShape(userShape,numPoints_shapeModeler,xyxyFormat=True) shapeCentre = ShapeModeler.getShapeCentre(userShape) for i in range(len(wordToLearn)): if(shapeCentre[0] > (self.width/len(wordToLearn))*i): shapeIndex_demoFor = i shapeType = wordManager.shapeAtIndexInCurrentCollection(shapeIndex_demoFor) print('Received demo for letter ' + shapeType) userShape = numpy.reshape(userShape, (-1, 1)); #explicitly make it 2D array with only one column userShape = ShapeModeler.normaliseShapeHeight(numpy.array(userShape)) shape = wordManager.respondToDemonstration(shapeType, userShape) userShape = [] self.canvas.remove(touch.ud['line']) if shape != -1: showShape(shape, shapeIndex_demoFor)
def param_gui(letter_name, shapeModeler): global sliders, mainPlot, fig, pca_params fig, ax = plt.subplots() whiteSpace = 0.15 + num_params*0.05 plt.subplots_adjust( bottom=whiteSpace) plt.axis('equal') #plot of initial shape params = np.zeros((num_params,1)) shape = shapeModeler.makeShape(params) shape = ShapeModeler.normaliseShape(shape) numPointsInShape = len(shape)/2 x_shape = shape[0:numPointsInShape] y_shape = shape[numPointsInShape:] mainPlot, = plt.plot(x_shape, -y_shape) plt.axis([-1, 1, -1, 1],autoscale_on=False, aspect='equal') plt.title(letter_name) #add sliders to modify parameter values parameterVariances = shapeModeler.getParameterVariances() sliders = [0]*num_params for i in range(num_params): slider = Slider(plt.axes([0.25, 0.1+0.05*(num_params-i-1), 0.65, 0.03], axisbg=axcolor), 'Parameter '+str(i+1), -5*parameterVariances[i], 5*parameterVariances[i], valinit=0) slider.on_changed(partial(update, shapeModeler)) sliders[i] = slider resetax = plt.axes([0.8, 0.025, 0.1, 0.04]) button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975') button.on_clicked(reset) plt.show() return pca_params
def downsampleShape(shape): #downsample user-drawn shape so appropriate size for shapeLearner numPointsInShape = len(shape)/2; x_shape = shape[0:numPointsInShape]; y_shape = shape[numPointsInShape:]; if isinstance(x_shape,numpy.ndarray): #convert arrays to lists for interp1d x_shape = (x_shape.T).tolist()[0]; y_shape = (y_shape.T).tolist()[0]; #make shape have the same number of points as the shape_modeler t_current = numpy.linspace(0, 1, numPointsInShape); t_desired = numpy.linspace(0, 1, numPoints_shapeModeler); f = interpolate.interp1d(t_current, x_shape, kind='cubic'); x_shape = f(t_desired); f = interpolate.interp1d(t_current, y_shape, kind='cubic'); y_shape = f(t_desired); shape = []; shape[0:numPoints_shapeModeler] = x_shape; shape[numPoints_shapeModeler:] = y_shape; shape = ShapeModeler.normaliseShapeHeight(numpy.array(shape)); shape = numpy.reshape(shape, (-1, 1)); #explicitly make it 2D array with only one column return shape
def downsampleShape(shape): #downsample user-drawn shape so appropriate size for shapeLearner numPointsInShape = len(shape)/2 x_shape = shape[0:numPointsInShape] y_shape = shape[numPointsInShape:] if isinstance(x_shape,numpy.ndarray): #convert arrays to lists for interp1d x_shape = (x_shape.T).tolist()[0] y_shape = (y_shape.T).tolist()[0] #make shape have the same number of points as the shape_modeler t_current = numpy.linspace(0, 1, numPointsInShape) t_desired = numpy.linspace(0, 1, NUMPOINTS_SHAPEMODELER) f = interpolate.interp1d(t_current, x_shape, kind='linear') x_shape = f(t_desired) f = interpolate.interp1d(t_current, y_shape, kind='linear') y_shape = f(t_desired) shape = [] shape[0:NUMPOINTS_SHAPEMODELER] = x_shape shape[NUMPOINTS_SHAPEMODELER:] = y_shape shape = ShapeModeler.normaliseShapeHeight(numpy.array(shape)) shape = numpy.reshape(shape, (-1, 1)) #explicitly make it 2D array with only one column return shape
def preparePlot(shapeModeler): global sliders, mainPlot, fig fig, ax = plt.subplots(); whiteSpace = 0.15 + numParams*0.05; plt.subplots_adjust( bottom=whiteSpace); plt.axis('equal'); #plot of initial shape params = np.zeros((numParams,1)); shape = shapeModeler.makeShape(params); shape = ShapeModeler.normaliseShape(shape); numPointsInShape = len(shape)/2; x_shape = shape[0:numPointsInShape]; y_shape = shape[numPointsInShape:]; mainPlot, = plt.plot(x_shape, -y_shape); plt.axis([-1, 1, -1, 1],autoscale_on=False, aspect='equal'); #add sliders to modify parameter values parameterVariances = shapeModeler.getParameterVariances(); sliders = [0]*numParams; for i in range(numParams): slider = Slider(plt.axes([0.25, 0.1+0.05*(numParams-i-1), 0.65, 0.03], axisbg=axcolor), 'Parameter '+str(i+1), -5*parameterVariances[i], 5*parameterVariances[i], valinit=0); slider.on_changed(update); sliders[i] = slider; resetax = plt.axes([0.8, 0.025, 0.1, 0.04]) button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975') button.on_clicked(reset) plt.show()
def shapeWord(word, downsampling_factor=None): """Assembles the paths of the letters of the given word into a global shape. :param word: a ShapeLearnerManager instance for the current word :param downsampling_factor: if provided, the final shape of each letter is (independantly) resampled to (nb_pts / downsampling_factor) points :returns: a ShapedWord that contains the path of individual letters """ paths = [] offset_x = offset_y = 0 for shape in word.shapesOfCurrentCollection(): path = [] w, ah, bh = LETTER_BOUNDINGBOXES[shape.shapeType] scale_factor = ah + bh # height ratio between this letter and a 'a' #no need for a width scaling since the shape are only *height*-normalized (cf below) glyph = ShapeModeler.normaliseShapeHeight(shape.path) numPointsInShape = len(glyph)/2 x_shape = glyph[0:numPointsInShape].flatten().tolist() y_shape = glyph[numPointsInShape:].flatten().tolist() if offset_x != 0 or offset_y != 0: # not the first letter offset_x -= x_shape[0] * SIZESCALE_WIDTH * scale_factor offset_y += y_shape[0] * SIZESCALE_HEIGHT * scale_factor for i in range(numPointsInShape): x = x_shape[i] * SIZESCALE_WIDTH * scale_factor y = -y_shape[i] * SIZESCALE_HEIGHT * scale_factor x += offset_x y += offset_y path.append((x,y)) paths.append(path) if shape.shapeType in ['i', 'j']: # HACK: waiting for proper multi-stroke learning logger.info("Adding a 'dot' to the letter") dot_path = [ (offset_x + 0.0 * SIZESCALE_WIDTH * scale_factor, offset_y + 0.8 * SIZESCALE_WIDTH * scale_factor), (offset_x + 0.05 * SIZESCALE_WIDTH * scale_factor, offset_y + 0.85 * SIZESCALE_HEIGHT * scale_factor), (offset_x + 0.0 * SIZESCALE_WIDTH * scale_factor, offset_y + 0.85 * SIZESCALE_HEIGHT * scale_factor), (offset_x + 0.0 * SIZESCALE_WIDTH * scale_factor, offset_y + 0.8 * SIZESCALE_HEIGHT * scale_factor) ] paths.append(dot_path) # connect the letter to the ending point of the previous one offset_x = path[-1][0] offset_y = path[-1][1] return ShapedWord(word.currentCollection, paths)
def downsampleShape(shape): #downsample user-drawn shape so appropriate size for shapeLearner numPointsInShape = len(shape) / 2 x_shape = shape[0:numPointsInShape] y_shape = shape[numPointsInShape:] if isinstance(x_shape, numpy.ndarray): #convert arrays to lists for interp1d x_shape = (x_shape.T).tolist()[0] y_shape = (y_shape.T).tolist()[0] #make shape have the same number of points as the shape_modeler t_current = numpy.linspace(0, 1, numPointsInShape) t_desired = numpy.linspace(0, 1, NUMPOINTS_SHAPEMODELER) f = interpolate.interp1d(t_current, x_shape, kind='linear') x_shape = f(t_desired) f = interpolate.interp1d(t_current, y_shape, kind='linear') y_shape = f(t_desired) shape = [] shape[0:NUMPOINTS_SHAPEMODELER] = x_shape shape[NUMPOINTS_SHAPEMODELER:] = y_shape shape = ShapeModeler.normaliseShapeHeight(numpy.array(shape)) shape = numpy.reshape( shape, (-1, 1)) #explicitly make it 2D array with only one column return shape
def on_touch_up(self, touch): global userShape touch.ud['line'].points userShape = downsampleShape(userShape, numPoints_shapeModeler, xyxyFormat=True) shapeCentre = ShapeModeler.getShapeCentre(userShape) for i in range(len(wordToLearn)): if (shapeCentre[0] > (self.width / len(wordToLearn)) * i): shapeIndex_demoFor = i shapeType = wordManager.shapeAtIndexInCurrentCollection( shapeIndex_demoFor) print('Received demo for letter ' + shapeType) userShape = np.reshape(userShape, (-1, 1)) #explicitly make it 2D array with only one column shape = wordManager.respondToDemonstration(shapeIndex_demoFor, userShape) wordManager.save_all(shapeIndex_demoFor) userShape = [] self.canvas.remove(touch.ud['line']) showShape(shape, shapeIndex_demoFor)
def on_touch_up(self, touch): global userShape touch.ud['line'].points userShape = downsampleShape(userShape,numPoints_shapeModeler,xyxyFormat=True) shapeCentre = ShapeModeler.getShapeCentre(userShape) shapeType = letter print('Received reference for letter ' + shapeType) userShape = numpy.reshape(userShape, (-1, 1)); userShape = ShapeModeler.normaliseShapeHeight(numpy.array(userShape)) filename = dataSetFile print('saving in'+filename) # scan the dataset : lines = [] try: with open(filename, 'r') as f: lines.append(f.readline()) nb_samples = int(lines[0].strip()) for i in range(nb_samples+1): lines.append(f.readline()) except IOError: raise RuntimeError("no reading permission for file"+filename) nb_samples+=1 # past the dataset : try: with open(filename, 'w') as f: f.write('nb_sample:\n') f.write('%i\n'%nb_samples) f.write('nb_pts:\n') f.write('70\n') f.write('ref:\n') f.write(' '.join(map(str,userShape.T[0]))+'\n') f.write('...\n') for i in range(nb_samples-1): f.write(lines[i+2]) except IOError: raise RuntimeError("no writing permission for file"+filename) userShape = [] self.canvas.remove(touch.ud['line'])
def prepareShapeModel(datasetDirectory, shape): import glob datasetFiles_shape = glob.glob(datasetDirectory + '/' + shape + '.dat') if (len(datasetFiles_shape) < 1): raise Exception("Dataset not available at " + datasetDirectory + " for shape " + shape) shapeModeler = ShapeModeler(filename=datasetFiles_shape[0], num_principle_components=numParams) #import pdb; pdb.set_trace() return shapeModeler
def update(val): global sliders, mainPlot, fig params = np.zeros((numParams, 1)) for i in range(numParams): params[i] = sliders[i].val shape = shapeModeler.makeShape(params) shape = ShapeModeler.normaliseShape(shape) numPointsInShape = len(shape) / 2 x_shape = shape[0:numPointsInShape] y_shape = shape[numPointsInShape:] mainPlot.set_data(x_shape, -y_shape) fig.canvas.draw_idle()
def update(val): global sliders , mainPlot, fig params = np.zeros((numParams,1)); for i in range(numParams): params[i] = sliders[i].val; shape = shapeModeler.makeShape(params); shape = ShapeModeler.normaliseShape(shape); numPointsInShape = len(shape)/2; x_shape = shape[0:numPointsInShape]; y_shape = shape[numPointsInShape:]; mainPlot.set_data(x_shape, -y_shape); fig.canvas.draw_idle();
def make_traj_msg(shape, shapeCentre, headerString, startTime, downsample, deltaT): if(startTime!=t0): penUpToFirst = True; else: penUpToFirst = False; traj = Path(); traj.header.frame_id = FRAME#headerString; traj.header.stamp = rospy.Time.now()+rospy.Duration(delayBeforeExecuting); shape = ShapeModeler.normaliseShapeHeight(shape); numPointsInShape_orig = len(shape)/2; x_shape = shape[0:numPointsInShape_orig]; y_shape = shape[numPointsInShape_orig:]; if(downsample): #make shape have the appropriate number of points t_current = numpy.linspace(0, 1, numPointsInShape_orig); t_desired = numpy.linspace(0, 1, numDesiredShapePoints); f = interpolate.interp1d(t_current, x_shape[:,0], kind='cubic'); x_shape = f(t_desired); f = interpolate.interp1d(t_current, y_shape[:,0], kind='cubic'); y_shape = f(t_desired); numPointsInShape = len(x_shape); downsampleFactor = numPointsInShape_orig/float(numPointsInShape); else: numPointsInShape = numPointsInShape_orig; for i in range(numPointsInShape): point = PoseStamped(); point.pose.position.x = x_shape[i]*sizeScale_width; point.pose.position.y = -y_shape[i]*sizeScale_height; point.pose.position.x+= + shapeCentre[0]; point.pose.position.y+= + shapeCentre[1]; point.header.frame_id = FRAME; point.header.stamp = rospy.Time(startTime+i*deltaT+t0); #@TODO allow for variable time between points for now if(penUpToFirst and i==0): point.header.seq = 1; traj.poses.append(deepcopy(point)); if(downsample): return traj, downsampleFactor else: return traj
def update(shapeModeler, val): global sliders , mainPlot, fig, pca_params pca_params = np.zeros((num_params, 1)) for i in range(num_params): pca_params[i] = sliders[i].val shape = shapeModeler.makeShape(pca_params) shape = ShapeModeler.normaliseShape(shape) numPointsInShape = len(shape)/2 x_shape = shape[0:numPointsInShape] y_shape = shape[numPointsInShape:] mainPlot.set_data(x_shape, -y_shape) fig.canvas.draw_idle()
def prepareShapesModel(datasetDirectory, num_params): shapes = {} nameFilter = re.compile(regexp) datasets = glob.glob(datasetDirectory + '/*.dat') for dataset in datasets: name = os.path.splitext(os.path.basename(dataset))[0] if nameFilter.match(name): shapeModeler = ShapeModeler(init_filename=dataset, num_principle_components=num_params) shapes[name] = shapeModeler return shapes
def respondToDemonstration(self, shape): """ Algo: 1) takes the shape of the demonstration 2) takes the curent learned shape 3) re-performs PCA taking in account the domonstrated shape, then obtains a new space with new eigen vectors 4) projects demonstrated and learned shapes into this new space and gets their new parameters 5) updates the learned parameters as the algebric middle between demonstrated parameters and curent learned parameters. """ demo_shape = ShapeModeler.normaliseShapeHeight(numpy.array(shape)) # take the shape corresponding to the curent learned parameters in the curent space learned_shape = self.shapeModeler.makeShape(self.params) # add the demo shape to the matrix for PCA and re-compute reference-shape params self.shapeModeler.extendDataMat(demo_shape) ref_params = self.shapeModeler.refParams # re-compute parameters of the learned shape and the demo shape in the new PCA-space params_demo, _ = self.shapeModeler.decomposeShape(demo_shape) self.params, _ = self.shapeModeler.decomposeShape(learned_shape) # learning : diff_params = params_demo - self.params self.params += diff_params/2 #go towards the demonstrated shape #self.params[self.paramsToVary[0]-1] = params_demo[self.paramsToVary[0]-1] #ONLY USE FIRST PARAM #store it as an attempt (this isn't super appropriate but whatever) if (self.doGroupwiseComparison): newParamValue = self.params[ self.paramsToVary[0] - 1, 0] #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM #print('Demo params: '+str(self.params)) bisect.insort(self.params_sorted, newParamValue) self.shapeToParamsMapping.append(self.params) #self.respondToFeedback(len(self.params_sorted)-3) # give feedback of most recent shape so bounds modify return self.shapeModeler.makeShape(self.params), self.params, params_demo
def on_touch_up(self, touch): global userShape touch.ud['line'].points userShape = downsampleShape(userShape,numPoints_shapeModeler,xyxyFormat=True) shapeCentre = ShapeModeler.getShapeCentre(userShape) for i in range(len(wordToLearn)): if(shapeCentre[0] > (self.width/len(wordToLearn))*i): shapeIndex_demoFor = i shapeType = wordManager.shapeAtIndexInCurrentCollection(shapeIndex_demoFor) print('Received demo for letter ' + shapeType) userShape = np.reshape(userShape, (-1, 1)); #explicitly make it 2D array with only one column shape = wordManager.respondToDemonstration(shapeIndex_demoFor, userShape) wordManager.save_all(shapeIndex_demoFor) userShape = [] self.canvas.remove(touch.ud['line']) showShape(shape, shapeIndex_demoFor)
def onUserDrawnShapeReceived(path, shapePreprocessingMethod, positionToShapeMappingMethod): global activeShapeForDemonstration_type #preprocess to turn multiple strokes into one path if(shapePreprocessingMethod == 'longestStroke'): path = processShape_longestStroke(strokes); else: path = processShape_firstStroke(strokes); #identify type of shape which demonstration was for location = ShapeModeler.getShapeCentre(path); if(positionToShapeMappingMethod == 'basedOnColumnOfScreen'): shapeType_demoFor = getShapeCode_basedOnColumnOfScreen(location); elif(positionToShapeMappingMethod == 'basedOnRowOfScreen'): shapeType_demoFor = getShapeCode_basedOnColumnOfScreen(location); elif(positionToShapeMappingMethod == 'basedOnShapeAtPosition'): shapeType_demoFor = getShapeCode_basedOnShapeAtPosition(location); else: shapeType_demoFor = getShapeCode_basedOnClosestShapeToPosition(location); #block the space from robot use try: display_shape_at_location = rospy.ServiceProxy('display_shape_at_location', displayShapeAtLocation); request = displayShapeAtLocationRequest(); request.shape_type_code = shapeType_demoFor; request.location.x = location[0]; request.location.y = location[1]; #todo: allow for blocking different sized shapes response = display_shape_at_location(request); result = response.success; #todo: do something if unsuccessful except rospy.ServiceException, e: rospy.logerr("Service call failed: %s",e);
def __init__(self, settings): self.paramsToVary = settings.paramsToVary #self.numPrincipleComponents = max(self.paramsToVary) self.numPrincipleComponents = NUM_PRINCIPLE_COMPONENTS #assign a ShapeModeler to use print(settings.initDatasetFile) self.shapeModeler = ShapeModeler(init_filename=settings.initDatasetFile, update_filenames=settings.updateDatasetFiles, param_filename=settings.paramFile, num_principle_components=self.numPrincipleComponents) self.bounds = settings.initialBounds for i in range(len(self.paramsToVary)): parameterVariances = self.shapeModeler.getParameterVariances() if (numpy.isnan(settings.initialBounds[i, 0]) or numpy.isnan( settings.initialBounds[i, 1])): #want to set initial bounds as std. dev. multiple boundsFromStdDevMultiples = numpy.array(settings.initialBounds_stdDevMultiples[i, :]) * \ parameterVariances[settings.paramsToVary[i] - 1] if (numpy.isnan(settings.initialBounds[i, 0])): self.bounds[i, 0] = boundsFromStdDevMultiples[0] if (numpy.isnan(settings.initialBounds[i, 1])): self.bounds[i, 1] = boundsFromStdDevMultiples[1] self.doGroupwiseComparison = settings.doGroupwiseComparison self.shape_learning = settings.shape_learning self.minParamDiff = settings.minParamDiff self.initialParamValue = settings.initialParamValue self.params = numpy.zeros((self.numPrincipleComponents, 1)) for i in range(self.numPrincipleComponents): self.params[i][0] = -self.initialParamValue[i] self.initialBounds = deepcopy(self.bounds) self.converged = False self.numIters = 0 self.numItersConverged = 0
def preparePlot(shapeModeler): global sliders, mainPlot, fig fig, ax = plt.subplots() whiteSpace = 0.15 + numParams * 0.05 plt.subplots_adjust(bottom=whiteSpace) plt.axis('equal') #plot of initial shape params = np.zeros((numParams, 1)) shape = shapeModeler.makeShape(params) shape = ShapeModeler.normaliseShape(shape) numPointsInShape = len(shape) / 2 x_shape = shape[0:numPointsInShape] y_shape = shape[numPointsInShape:] mainPlot, = plt.plot(x_shape, -y_shape) plt.axis([-1, 1, -1, 1], autoscale_on=False, aspect='equal') #add sliders to modify parameter values parameterVariances = shapeModeler.getParameterVariances() sliders = [0] * numParams for i in range(numParams): slider = Slider(plt.axes( [0.25, 0.1 + 0.05 * (numParams - i - 1), 0.65, 0.03], axisbg=axcolor), 'Parameter ' + str(i + 1), -5 * parameterVariances[i], 5 * parameterVariances[i], valinit=0) slider.on_changed(update) sliders[i] = slider resetax = plt.axes([0.8, 0.025, 0.1, 0.04]) button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975') button.on_clicked(reset) plt.show()
class ShapeLearner: def __init__(self, settings): self.paramsToVary = settings.paramsToVary #self.numPrincipleComponents = max(self.paramsToVary) self.numPrincipleComponents = NUM_PRINCIPLE_COMPONENTS #assign a ShapeModeler to use print(settings.initDatasetFile) self.shapeModeler = ShapeModeler(init_filename=settings.initDatasetFile, update_filenames=settings.updateDatasetFiles, param_filename=settings.paramFile, num_principle_components=self.numPrincipleComponents) self.bounds = settings.initialBounds for i in range(len(self.paramsToVary)): parameterVariances = self.shapeModeler.getParameterVariances() if (numpy.isnan(settings.initialBounds[i, 0]) or numpy.isnan( settings.initialBounds[i, 1])): #want to set initial bounds as std. dev. multiple boundsFromStdDevMultiples = numpy.array(settings.initialBounds_stdDevMultiples[i, :]) * \ parameterVariances[settings.paramsToVary[i] - 1] if (numpy.isnan(settings.initialBounds[i, 0])): self.bounds[i, 0] = boundsFromStdDevMultiples[0] if (numpy.isnan(settings.initialBounds[i, 1])): self.bounds[i, 1] = boundsFromStdDevMultiples[1] self.doGroupwiseComparison = settings.doGroupwiseComparison self.shape_learning = settings.shape_learning self.minParamDiff = settings.minParamDiff self.initialParamValue = settings.initialParamValue self.params = numpy.zeros((self.numPrincipleComponents, 1)) for i in range(self.numPrincipleComponents): self.params[i][0] = -self.initialParamValue[i] self.initialBounds = deepcopy(self.bounds) self.converged = False self.numIters = 0 self.numItersConverged = 0 ### ----------------------------------------------------- START LEARNING def startLearning(self): #make initial shape if (numpy.isnan(self.initialParamValue[0])): [shape, paramValues] = self.shapeModeler.makeRandomShapeFromUniform(self.params, self.paramsToVary, self.bounds) self.params = paramValues else: shape = self.shapeModeler.makeShape(self.params) self.bestParamValue = self.params[ self.paramsToVary[0] - 1] # USE ONLY FIRST PARAM IN LIST FOR SELF-LEARNING ALGORITHM if (self.doGroupwiseComparison): self.params_sorted = [self.bounds[0, 0], self.bounds[0, 1]] # USE ONLY FIRST PARAM IN LIST FOR SELF-LEARNING ALGORITHM bisect.insort(self.params_sorted, self.bestParamValue) self.shapeToParamsMapping = [self.params] else: self.newParamValue = self.bestParamValue self.params = [self.newParamValue] return shape, self.params ### ---------------------------------------- START LEARNING - TRIANGULAR def startLearningAt(self, startingBounds, startingParamValues): self.bounds = startingBounds #make initial shape [shape, paramValues] = self.shapeModeler.makeRandomShapeFromTriangular(self.params, self.paramsToVary, self.bounds, startingParamValues) self.params = paramValues self.bestParamValue = paramValues[ self.paramsToVary[0] - 1] # USE ONLY FIRST PARAM IN LIST FOR SELF-LEARNING ALGORITHM if (self.doGroupwiseComparison): self.params_sorted = [self.bounds[0, 0], self.bounds[0, 1]] # USE ONLY FIRST PARAM IN LIST FOR SELF-LEARNING ALGORITHM bisect.insort(self.params_sorted, self.bestParamValue) self.shapeToParamsMapping = [self.params] else: self.newParamValue = self.bestParamValue return shape, self.bestParamValue ### ----------------------------------------------- MAKE DIFFERENT SHAPE def makeShapeDifferentTo(self, paramValue): #make new shape to compare with [newShape, newParams] = self.shapeModeler.makeRandomShapeFromTriangular(self.params, self.paramsToVary, self.bounds, [ paramValue]) #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM newParamValue = newParams[self.paramsToVary[0] - 1, 0] #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM #ensure it is significantly different numAttempts = 1 while (abs(newParamValue - paramValue) < self.minParamDiff and numAttempts < maxNumAttempts): [newShape, newParams] = self.shapeModeler.makeRandomShapeFromTriangular(self.params, self.paramsToVary, self.bounds, [ paramValue]) #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM newParamValue = newParams[ self.paramsToVary[0] - 1, 0] #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM numAttempts += 1 if (numAttempts >= maxNumAttempts): #couldn't find a 'different' shape in range print('Oh no!') #this should be prevented by the convergence test below #store it as an attempt if (self.doGroupwiseComparison): bisect.insort(self.params_sorted, newParamValue) self.shapeToParamsMapping.append(newParams) return newShape, newParamValue ### ------------------------------------------------- MAKE SIMILAR SHAPE def makeShapeSimilarTo(self, paramValue): #make new shape, but don't enforce that it is sufficiently different [newShape, newParamValues] = self.shapeModeler.makeRandomShapeFromTriangular(self.params, self.paramsToVary, self.bounds, [ paramValue]) #USE FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM newParamValue = newParamValues[self.paramsToVary[0] - 1, 0] #USE FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM #store it as an attempt if (self.doGroupwiseComparison): bisect.insort(self.params_sorted, newParamValue) self.shapeToParamsMapping.append(newParamValues) return newShape, newParamValue ### ---------------------------------------- GENERATE SIMULATED FEEDBACK def generateSimulatedFeedback(self, shape, newParamValue): #code in place of feedback from user: go towards goal parameter value goalParamValue = numpy.float64(0) #-1.5*parameterVariances[self.paramToVary-1] goalParamsValue = numpy.zeros((self.numPrincipleComponents, 1)) goalParamsValue[self.paramsToVary - 1, 0] = goalParamValue if (self.doGroupwiseComparison): errors = numpy.ndarray.tolist(abs(self.shapeToParamsMapping - goalParamsValue)) bestShape_idx = errors.index(min(errors)) else: errors = [abs(self.bestParamValue - goalParamValue), abs(newParamValue - goalParamValue)] bestShape_idx = errors.index(min(errors)) return bestShape_idx ### ------------------------------------------------ RESPOND TO FEEDBACK def respondToFeedback(self, bestShape): #update bestParamValue based on feedback received if (self.doGroupwiseComparison): params_best = self.shapeToParamsMapping[bestShape] self.bestParamValue = params_best[ self.paramsToVary[0] - 1, 0] #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM bestParamValue_index = bisect.bisect(self.params_sorted, self.bestParamValue) - 1 #indexing seems to start at 1 with bisect newBounds = [self.params_sorted[bestParamValue_index - 1], self.params_sorted[bestParamValue_index + 1]] #restrict bounds if they were caused by other shapes, because it must be sufficiently different to said shape(s) if ((bestParamValue_index - 1) > 0): #not the default min newBounds[0] += self.minParamDiff if ((bestParamValue_index + 1) < (len(self.params_sorted) - 1)): #not the default max newBounds[1] -= self.minParamDiff if (not (newBounds[0] > newBounds[1])): #protect from bounds switching expected order self.bounds[0, :] = newBounds #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM diff_params = params_best - self.params diff = numpy.linalg.norm(diff_params) self.params += diff_params / 2 else: #do pairwise comparison with most recent shape and previous #restrict limits if ( bestShape == 'new' ): #new shape is better worstParamValue = self.bestParamValue bestParamValue = self.newParamValue self.params[self.paramsToVary - 1, 0] = bestParamValue else: #new shape is worse worstParamValue = self.newParamValue bestParamValue = self.bestParamValue self.params[self.paramsToVary - 1, 0] = bestParamValue if ( worstParamValue == min(self.bestParamValue, self.newParamValue) ): #shape with lower value is worse self.bounds[0] = worstParamValue #increase min bound to worst so we don't try any lower else: #shape with higher value is worse self.bounds[1] = worstParamValue #decrease max bound to worst so we don't try any higher ### ------------------------------------------------------------ ITERATE def generateNewShapeGivenFeedback(self, bestShape): #------------------------------------------- respond to feedback self.respondToFeedback(bestShape) #update bounds and bestParamValue #----------------------------------------- check for convergence #continue if there are more shapes to try which are different enough if ((abs(self.bounds[0, 1] - self.bestParamValue) - self.minParamDiff < tol) and (abs( self.bestParamValue - self.bounds[ 0, 0]) - self.minParamDiff) < tol): #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM self.converged = True else: self.converged = False #-------------------------------------------- continue iterating self.numIters += 1 #try again if shape is not good enough if (not self.converged): self.numItersConverged = 0 [newShape, newParamValue] = self.makeShapeDifferentTo(self.bestParamValue) self.newParamValue = newParamValue return self.numItersConverged, newShape, newParamValue else: self.numItersConverged += 1 [newShape, newParamValue] = self.makeShapeSimilarTo(self.bestParamValue) self.newParamValue = newParamValue return self.numItersConverged, newShape, newParamValue def getLearnedParams(self): return self.params def getLearnedShape(self): return self.shapeModeler.makeShape(self.params), self.params def getParameterBounds(self): return self.bounds def setParameterBounds(self, bounds): self.bounds = bounds def respondToDemonstration(self, shape): """ Algo: 1) takes the shape of the demonstration 2) takes the curent learned shape 3) re-performs PCA taking in account the domonstrated shape, then obtains a new space with new eigen vectors 4) projects demonstrated and learned shapes into this new space and gets their new parameters 5) updates the learned parameters as the algebric middle between demonstrated parameters and curent learned parameters. """ demo_shape = ShapeModeler.normaliseShapeHeight(numpy.array(shape)) # take the shape corresponding to the curent learned parameters in the curent space learned_shape = self.shapeModeler.makeShape(self.params) # add the demo shape to the matrix for PCA and re-compute reference-shape params self.shapeModeler.extendDataMat(demo_shape) ref_params = self.shapeModeler.refParams # re-compute parameters of the learned shape and the demo shape in the new PCA-space params_demo, _ = self.shapeModeler.decomposeShape(demo_shape) self.params, _ = self.shapeModeler.decomposeShape(learned_shape) # learning : diff_params = params_demo - self.params self.params += diff_params/2 #go towards the demonstrated shape #self.params[self.paramsToVary[0]-1] = params_demo[self.paramsToVary[0]-1] #ONLY USE FIRST PARAM #store it as an attempt (this isn't super appropriate but whatever) if (self.doGroupwiseComparison): newParamValue = self.params[ self.paramsToVary[0] - 1, 0] #USE ONLY FIRST PARAM FOR SELF-LEARNING ALGORITHM ATM #print('Demo params: '+str(self.params)) bisect.insort(self.params_sorted, newParamValue) self.shapeToParamsMapping.append(self.params) #self.respondToFeedback(len(self.params_sorted)-3) # give feedback of most recent shape so bounds modify return self.shapeModeler.makeShape(self.params), self.params, params_demo def save_all(self): self.shapeModeler.save_all() def save_demo(self): self.shapeModeler.save_demo() def save_params(self): paramValue = [] for i in range(self.numPrincipleComponents): paramValue.append(-self.params[i][0]) self.shapeModeler.save_params(paramValue, self.shape_learning)
def showShape(shape): plt.figure(1) plt.clf() ShapeModeler.normaliseAndShowShape(shape)
def showShape(shape,shapeIndex ): plt.figure(shapeIndex+1) plt.clf() ShapeModeler.normaliseAndShowShape(shape.path)
def find_letter(self, path): x,y = ShapeModeler.getShapeCentre(path) return self.closest_letter(x, y)
def on_touch_up(self, touch): global userShape word = [] total_score =0 rest = userShape scan = downsampleShape(userShape, numPoints_shapeModeler,xyxyFormat=True) shapeCentre = ShapeModeler.getShapeCentre(scan) scan = np.reshape(scan, (-1, 1)); #explicitly make it 2D array with only one column scan = ShapeModeler.normaliseShapeHeight(np.array(scan)) scores = np.array(separator(scan)) scores = scores/np.max(scores) scores = scores*np.abs(scores) scores[scores<0.1]=0 indices = np.array(range(len(scores))) sep = indices[scores>0] #print zip(sep[:-1],sep[1:]) for i in sep: x = scan[i] if len(scan[scan[i:numPoints_shapeModeler]<x])>0: scores[i]=0 if len(scan[scan[:i]>x])>0: scores[i]=0 u = True while u: u = False sep = indices[scores>0] for i,j in zip(sep[:-1],sep[1:]): if j-i<5: u = True if scores[i]>scores[j]: scores[j] = 0 else: scores[i] = 0 plt.clf() ShapeModeler.showShape_score(scan,scores) word = [] sep = indices[scores>0] for i,j in zip(sep[:-1],sep[1:]): shape = scan[i:j+1].T.tolist()[0] + scan[numPoints_shapeModeler+i:numPoints_shapeModeler+j+1].T.tolist()[0] shape = downsampleShape(shape, numPoints_shapeModeler) shape = np.reshape(shape,(-1,1)) shape = ShapeModeler.normaliseShapeHeight(np.array(shape)) best_letter = '?' errors = {} values = [] for letter in abc: space = spaces[letter] error = space.getMinDist(shape) errors[letter] = error values.append(error) best_letter = min(errors, key = errors.get) word.append(best_letter) print 'found ' + str(word) print '######################' print '' userShape = [] self.canvas.remove(touch.ud['line'])
settings_shapeLearners = [] userInputCaptures = [] nb_param = 10 spaces = {} abc = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ] for letter in abc: (shapeType, init_datasetFile, update_datasetFiles, datasetParam) = generateSettings(letter) spaces[letter] = ShapeModeler(init_filename=init_datasetFile, update_filenames=update_datasetFiles, param_filename=datasetParam, num_principle_components=nb_param) def downsampleShape(shape, numDesiredPoints, xyxyFormat=False): numPointsInShape = len(shape) / 2 if (xyxyFormat): #make xyxy format x_shape = shape[0::2] y_shape = shape[1::2] else: x_shape = shape[0:numPointsInShape] y_shape = shape[numPointsInShape:] if isinstance(x_shape, np.ndarray): #convert arrays to lists for interp1d x_shape = (x_shape.T).tolist()[0]
def showShape(shape, shapeIndex): plt.figure(shapeIndex+1, figsize=(3,3)) plt.clf() ShapeModeler.normaliseAndShowShape(shape.path) plt.draw()
def on_touch_up(self, touch): global userShape word = [] total_score = 0 rest = userShape scan = downsampleShape(userShape, numPoints_shapeModeler, xyxyFormat=True) shapeCentre = ShapeModeler.getShapeCentre(scan) scan = np.reshape(scan, (-1, 1)) #explicitly make it 2D array with only one column scan = ShapeModeler.normaliseShapeHeight(np.array(scan)) scores = np.array(separator(scan)) scores = scores / np.max(scores) scores = scores * np.abs(scores) scores[scores < 0.1] = 0 indices = np.array(range(len(scores))) sep = indices[scores > 0] #print zip(sep[:-1],sep[1:]) for i in sep: x = scan[i] if len(scan[scan[i:numPoints_shapeModeler] < x]) > 0: scores[i] = 0 if len(scan[scan[:i] > x]) > 0: scores[i] = 0 u = True while u: u = False sep = indices[scores > 0] for i, j in zip(sep[:-1], sep[1:]): if j - i < 5: u = True if scores[i] > scores[j]: scores[j] = 0 else: scores[i] = 0 plt.clf() ShapeModeler.showShape_score(scan, scores) word = [] sep = indices[scores > 0] for i, j in zip(sep[:-1], sep[1:]): shape = scan[i:j + 1].T.tolist()[0] + scan[numPoints_shapeModeler + i:numPoints_shapeModeler + j + 1].T.tolist()[0] shape = downsampleShape(shape, numPoints_shapeModeler) shape = np.reshape(shape, (-1, 1)) shape = ShapeModeler.normaliseShapeHeight(np.array(shape)) best_letter = '?' errors = {} values = [] for letter in abc: space = spaces[letter] error = space.getMinDist(shape) errors[letter] = error values.append(error) best_letter = min(errors, key=errors.get) word.append(best_letter) print 'found ' + str(word) print '######################' print '' userShape = [] self.canvas.remove(touch.ud['line'])
def showShape(shape ): plt.figure(1) plt.clf() ShapeModeler.normaliseAndShowShape(shape)
def showShape(shape, shapeIndex): plt.figure(shapeIndex + 1) plt.clf() ShapeModeler.normaliseAndShowShape(shape.path)