class OTModuleGeometry(OTBaseModuleGeometry): def __init__(self, name): icon_path = tools.getFileInSameDirectory(__file__, 'icongeo.png') OTBaseModuleGeometry.__init__(self,name, iconFile = icon_path) self._imgWidth = 0.0 self._imgHeight = 0.0 self._startPoint = None self._endPoint = None self._selectedPoly = None self._selectedPoint = None self._video = OTParamVideoInput("Video") self._player = OTParamPlayer("Video") self._remove = OTParamButton("Remove") self._square = OTParamToggle("Square") self._circle = OTParamToggle("Circle") self._export = OTParamButton("Export") self._import = OTParamButton("Import") self._formset = [ '_video',"_player", ("_square", "_circle", " ","_remove"," ", "_export", "_import"), "=", "_polygons" ] self._video.valueUpdated = self.videoSelected self._square.value = self.square_toggle self._circle.value = self.circle_toggle self._remove.value = self.remove_clicked self._export.value = self.export_clicked self._import.value = self.import_clicked self._player._videoWidget.onDrag = self.onDragInVideoWindow self._player._videoWidget.onEndDrag = self.onEndDragInVideoWindow self._player._videoWidget.onClick = self.onClickInVideoWindow self._player._videoWidget.onDoubleClick = self.onDoubleClickInVideoWindow self._player.processFrame = self.processFrame def export_clicked(self): filename = str(QFileDialog.getSaveFileName(self._form, 'Choose a file', '') ) if filename!="": output = open( filename, 'wb') pickle.dump( self._polygons.value , output) output.close() def import_clicked(self): filename = str(QFileDialog.getOpenFileName(self._form, 'Choose a file', '') ) if filename!="": pkl_file = open( filename, 'rb'); data = pickle.load(pkl_file); pkl_file.close() self._polygons.value = data def processFrame(self, frame): rows = self._polygons.value for objIndex, obj in enumerate(rows): try: points = eval(obj[1]) cv2.polylines(frame, [numpy.array(points,numpy.int32)], True, (0,255,0), 1, lineType=cv2.CV_AA) for pointIndex, point in enumerate( points ): if self._selectedPoint == pointIndex and objIndex==self._selectedPoly: cv2.circle(frame, point, 2, (255,0,0), 1) else: cv2.circle(frame, point, 2, (0,255,0), 1) except: pass if self._startPoint and self._endPoint: if self._square.isChecked(): cv2.rectangle(frame, self._startPoint, self._endPoint, (233,44,44), 1 ) elif self._circle.isChecked() and self._endPoint[0]>self._startPoint[0] and self._endPoint[1]>self._startPoint[1]: width = self._endPoint[0]-self._startPoint[0] height = self._endPoint[1]-self._startPoint[1] center = ( self._startPoint[0] + width/2, self._startPoint[1] + height/2 ) cv2.ellipse( frame, center, (width/2,height/2), 0, 0, 360, (233,44,44), 1 ) return frame def selectPoint(self,x, y): rows = self._polygons.value for objIndex, obj in enumerate(rows): try: points = eval(obj[1]) for pointIndex, point in enumerate( points): mouseCoord = ( x, y ) if tools.pointsDistance( mouseCoord, point ) <= 5: self._selectedPoint = pointIndex self._selectedPoly = objIndex return self._selectedPoint = None self._selectedPoly = None except: pass def getIntersectionPoint(self, testPoint, point1, point2, tolerance = 5): vector = ( point2[0]-point1[0], point2[1]-point1[1] ) p0 = point1 if vector[0]!=0: k = float(testPoint[0] - p0[0]) / float(vector[0]) y = float(p0[1]) + k * float(vector[1]) if point2[0]>point1[0]: maxValue = point2[0] minValue = point1[0] else: maxValue = point1[0] minValue = point2[0] if abs(y-testPoint[1])<=tolerance and testPoint[0]<=maxValue and testPoint[0]>=minValue: return testPoint else: return None elif vector[1]!=0: k = float(testPoint[1] - p0[1]) / float(vector[1]) x = float(p0[0]) + k * float(vector[0]) if point2[1]>point1[1]: maxValue = point2[1] minValue = point1[1] else: maxValue = point1[1] minValue = point2[1] if abs(x-testPoint[0])<=tolerance and testPoint[1]<=maxValue and testPoint[1]>=minValue: return testPoint else: return None else: return None def onDoubleClickInVideoWindow(self, event, x, y): mouse = ( int(x*self._imgWidth), int(y*self._imgWidth) ) rows = self._polygons.value for objIndex, obj in enumerate(rows): try: points = eval(obj[1]) n_points = len(points) for pointIndex, point in enumerate( points ): next_point = points[ (pointIndex+1) % n_points ] intersection = self.getIntersectionPoint(mouse, point, next_point ) if intersection != None: self._selectedPoly = objIndex points.insert( pointIndex + 1, intersection ) self._polygons.setValue( 1, self._selectedPoly, points ) self._selectedPoint = pointIndex + 1 return except: pass def onClickInVideoWindow(self, event, x, y): self.selectPoint( int(x * self._imgWidth), int(y * self._imgWidth) ) def onDragInVideoWindow(self, startPoint, endPoint): self._startPoint = ( int(startPoint[0] * self._imgWidth), int(startPoint[1] * self._imgWidth) ) self._endPoint = ( int(endPoint[0] * self._imgWidth), int(endPoint[1] * self._imgWidth) ) if self._selectedPoly!=None and self._selectedPoint!=None: poly = self._polygons.getValue( 1, self._selectedPoly ) try: points = eval(poly) points[self._selectedPoint] = self._endPoint self._polygons.setValue( 1, self._selectedPoly, points ) except: pass if not self._player.is_playing(): self._player.refresh() def onEndDragInVideoWindow(self, startPoint, endPoint): self._startPoint = ( int(startPoint[0] * self._imgWidth), int(startPoint[1] * self._imgWidth) ) self._endPoint = ( int(endPoint[0] * self._imgWidth), int(endPoint[1] * self._imgWidth) ) points = None if self._square.isChecked(): points = createRectanglePoints(self._startPoint, self._endPoint) elif self._circle.isChecked() and self._endPoint[0]>self._startPoint[0] and self._endPoint[1]>self._startPoint[1]: points = createEllipsePoints(self._startPoint, self._endPoint) if points: self._polygons += ["Poly_%d" % self._polygons.count, points] self._startPoint = None self._endPoint = None self._square.uncheck() self._circle.uncheck() def videoSelected(self, value): if value and value!="" and value.hasVideo(): self._player.value = value self._imgWidth = float(value.width) self._imgHeight = float(value.height) else: self._player.value = None def square_toggle(self, checked): if checked: self._circle.uncheck() def circle_toggle(self, checked): if checked: self._square.uncheck() def remove_clicked(self): self._polygons -= -1 #Remove the selected row
class OTModuleAdjustPositions(OTModuleResultsPlugin, OTModulePositions): def __init__(self, name): icon_path = tools.getFileInSameDirectory(__file__, 'icon.jpg') OTModuleResultsPlugin.__init__(self, name, iconFile = icon_path) self._x_col = 4 #Indicate the column with the X coord self._y_col = 5 #Indicate the column with the Y coord self._frame_col = 1 #Indicate the column with the Y coord self._object_col = 6 self._current_row = None self._imgWidth = 0.0 self._imgHeight = 0.0 self._startPoint = None self._endPoint = None self._video = OTParamVideoInput("Video") self._positions = OTParamPositions("Positions") self._showPos = OTParamCheckBox("Show position") self._showTrack = OTParamCheckBox("Show track") self._trackRange = OTParamSlider("Track range", 10, 10, 1000) self._player = OTParamPlayer("Video player") self._progress = OTParamProgress() #Fields used to configure the Position draw function self._show_draw_function = OTParamToggle("Show/Hide draw function") self._draw_function = OTParamTextArea("Draw function", """def draw(frame, row): x, y = int(row[self._x_col]), int(row[self._y_col]) cv2.circle(frame, (x, y), 3, (0,255,0), thickness=2, lineType= cv2.cv.CV_AA)""") self._importFunc = OTParamButton("Import") self._exportFunc = OTParamButton("Export") #Fields used to configure the interpolation self._columns = OTParamCheckBoxList("List of columns to interpolate") self._run_interpolation = OTParamButton("Interpolate") self._run_interpolation_4_all = OTParamButton("Interpolate") #organization of the form self._formset = [ ('_video','_positions'), [ ('_columns', '_run_interpolation', '_run_interpolation_4_all'), "_draw_function", (" ", "_importFunc", "_exportFunc"), "_player", ('_showPos',"_showTrack", "_trackRange") ,"=","_results", "_query"], '_progress' ] self._trackRange.enabled = False self._showPos.value = True #setting up the fields events self._player.processFrame = self.processFrame self._video.valueUpdated = self.newVideoInputChoosen self._positions.valueUpdated = self.newPositionsChoosen self._showTrack.valueUpdated = self.showTrackToggle self._query.selectionChanged = self.tableSelectionChanged self._trackRange.valueUpdated = self.updateTrackRange self._player._videoWidget.onEndDrag = self.onEndDragInVideoWindow self._show_draw_function.value = self.showHideDrawFunction self._importFunc.value = self.importFunction self._exportFunc.value = self.exportFunction self._run_interpolation.value = self.interpolationPositions self._run_interpolation_4_all.value = self.interpolateAllPositions #Hide fields self._draw_function.hide() self._progress.hide() self._importFunc.hide() self._exportFunc.hide() self._columns.hide() self._run_interpolation.hide() self._run_interpolation_4_all.hide() #Configure the popup menu self._query.addPopupMenuOption("-") self._query.addPopupSubMenuOption("Add", {"Interpolation": self.showColumns4Interpolation, "Duplicate row": self.addDuplicatedRow }) self._query.addPopupMenuOption("Remove", self._query.remove) self._query.addPopupMenuOption("-") self._query.addPopupMenuOption("Approximate all positions", self.approximatePositions) self._query.addPopupMenuOption("Interpolate all positions", self.showColumns4InterpolationAll) self._current_row_index = None #Variable used to read the current row when the video is playing def onEndDragInVideoWindow(self, startPoint, endPoint, refresh=True): self._startPoint = ( int(startPoint[0] * self._imgWidth), int(startPoint[1] * self._imgWidth) ) self._endPoint = ( int(endPoint[0] * self._imgWidth), int(endPoint[1] * self._imgWidth) ) current_row = self._query.mouseSelectedRow if current_row!=None: current_index = self._query.mouseSelectedRowIndex current_frame = int(current_row[self._frame_col]) if (self._player.value.getCurrentFrame()) == current_frame: x, y = int(current_row[self._x_col]), int(current_row[self._y_col]) #print "current_row", self._startPoint, x, y if tools.pointsDistance( self._startPoint , (x,y) ) <= 10: self._query.setValueIn( current_index, self._x_col, self._endPoint[0] ) self._query.setValueIn( current_index, self._y_col, self._endPoint[1] ) self._current_row = self._query.valuesInRow(current_index) if refresh: self._query.commit() self._player.refresh() self._query.refresh( current_index ) self._query.select() def exportFunction(self): filename = str(QFileDialog.getSaveFileName(self._form, 'Choose a file', '') ) if filename!="": output = open( filename, 'wb') pickle.dump( self._draw_function.value , output) output.close() def importFunction(self): filename = str(QFileDialog.getOpenFileName(self._form, 'Choose a file', '') ) if filename!="": pkl_file = open( filename, 'rb'); data = pickle.load(pkl_file); pkl_file.close() self._draw_function.value = data func = self._draw_function.value exec func self.drawRow = draw def showHideDrawFunction(self, value): if value: self._player.hide() self._importFunc.show() self._exportFunc.show() self._draw_function.show() else: self._draw_function.hide() self._importFunc.hide() self._exportFunc.hide() self._player.show() func = self._draw_function.value #code = compile(func, '<string>', 'exec') exec func self.drawRow = draw """d = {} exec func.strip() in d print d setattr(self.__class__, 'drawRow', d['drawRow']) """ #self.drawRow = eval( func) def approximatePositions(self): totalCountRows = self._query.count firstRow = self._query.valuesInRow( totalCountRows-1 ) firstPoint = ( int(firstRow[self._x_col]), int(firstRow[self._y_col]) ) lastAngle = None self._progress.show() self._progress.min = 0 self._progress.value = 0 self._progress.max = totalCountRows query = QSqlQuery( self.parentModule.sqldb ) self._query.beginTransaction() for i in range( totalCountRows-2, 0, -1 ): #print i currentRow = self._query.valuesInRow( i ) currentPoint = ( int(currentRow[self._x_col]), int(currentRow[self._y_col]) ) dist = tools.pointsDistance( firstPoint, currentPoint ) vector = ( firstPoint[0]-currentPoint[0], firstPoint[1]-currentPoint[1] ) angle = math.atan2( vector[1], vector[0] ) angleInDegrees = math.degrees( angle ) frame = currentRow[self._frame_col] obj = currentRow[self._object_col] #print "angle:---", angleInDegrees, lastAngle if lastAngle==None: lastAngle=angleInDegrees if dist<=10: #self._query.removeRow( i ) #print "DELETE FROM %s WHERE frame='%s' and object='%s' " % (self._query.table, frame, obj ) query.exec_("DELETE FROM %s WHERE frame='%s' and object='%s' " % (self._query.table, frame, obj ) ) elif( math.fabs(lastAngle-angleInDegrees)>=5 ): #print "angles", angleInDegrees, lastAngle firstPoint = currentPoint lastAngle = angleInDegrees else: #print "DELETE FROM %s WHERE frame='%s' and object='%s' " % (self._query.table, frame, obj ) query.exec_("DELETE FROM %s WHERE frame='%s' and object='%s' " % (self._query.table, frame, obj ) ) #self._query.removeRow( i ) self._progress.value = totalCountRows - i QApplication.processEvents() self._query.commit() self._progress.hide() self._query.refresh(0) def showTrackToggle(self, value): self._trackRange.enabled = value def updateTrackRange(self, value): if isinstance(self._player.value, OTVideoInput): self._player.refresh() ############################################################################ ############ Parent class functions reemplementation ####################### ############################################################################ def selectionChanged(self, selected, deselected): """ Redefinition of the function selectionChanged from OTModuleResultsPlugin """ QTableView.selectionChanged(self._query.form.tableView, selected, deselected) row = self._query.mouseSelectedRow if row != None: self._current_row = row video = self._video.value frame_index = int( row[self._frame_col] ) video.videoInput.setFrame( frame_index-1 ) self._player.updateFrame() ############################################################################ ############ Events ######################################################## ############################################################################ def updateProgressBar(self, index): self._progress.value = index def interpolateAllPositions(self): """ Event called when user click in interpolation button """ self._run_interpolation.hide() self._run_interpolation_4_all.hide() self._columns.hide() self._player.show() totalCountRows = self._query.count n_columns = len(self._query.columns) checked_columns = self._columns.checkedIndexes cols_2_interpolate = map( lambda x: True if x in checked_columns else False, range(n_columns) ) self._progress.show() self._progress.min = 0 self._progress.value = 0 self._progress.max = totalCountRows for i in range( 0, totalCountRows-1 ): self.interpolateBetween2Rows( i, i+1, update = self.updateProgressBar ,cols_2_interpolate = cols_2_interpolate ) self._query.commit() self._progress.value = i self._progress.hide() self._query.orderBy = 1 def interpolationPositions(self): """ Event called when user click in interpolation button """ self._run_interpolation.hide() self._run_interpolation_4_all.hide() self._columns.hide() self._player.show() rowsIndexes = self._query.mouseSelectedRowsIndexes rowsIndexes.sort() if len(rowsIndexes)==2 and rowsIndexes[0]==rowsIndexes[1]-1: #check is the rows are consecutives rows = self._query.mouseSelectedRows diff = float(abs( int(rows[1][0]) - int(rows[0][0]) )) if diff > 1 : print rowsIndexes[0], rowsIndexes[1] self.interpolateBetween2Rows( rowsIndexes[0], rowsIndexes[1], update = self.updateProgressBar ) self._query.commit() self._query.orderBy = 1 self._query.mouseSelectedRowsIndexes = rowsIndexes[0] else: QMessageBox. warning(self._form, 'Warning', "Is not possible to add more frames between the selected ones") else: QMessageBox. warning(self._form, 'Warning', "You should select two consecutive rows") def addDuplicatedRow(self): """ Event called when a user click on the popup menu option """ rows = self._query.mouseSelectedRows rowsIndexes = self._query.mouseSelectedRowsIndexes if len(rows)==1: lastRow = rows[-1] self._query.addRow(lastRow, rowsIndexes[0]) else: QMessageBox. warning(self._control, 'Warning', "You should select one row to duplicate") self._query.orderBy = 1 self._query.mouseSelectedRowsIndexes = rowsIndexes[0] def showColumns4Interpolation(self): """ Event called when a user click on the popup menu option """ self._player.hide() self._draw_function.hide() self._exportFunc.hide() self._importFunc.hide() self._run_interpolation_4_all.hide() self._columns.show() self._run_interpolation.show() def showColumns4InterpolationAll(self): """ Event called when a user click on the popup menu option """ self._player.hide() self._draw_function.hide() self._exportFunc.hide() self._importFunc.hide() self._run_interpolation.hide() self._columns.show() self._run_interpolation_4_all.show() def tableSelectionChanged(self): """ Event called when a user select rows using the popup menu """ self._player.refresh() def newVideoInputChoosen(self, value): """ Event called when a user select rows using the popup menu @param value: Video module @type value: OTModule """ OTParamVideoInput.valueUpdated(self._video,value) if value.videoInput: value.videoInput.setFrame(0) self._player.value = value.videoInput self._imgWidth = float(value.videoInput.width) self._imgHeight = float(value.videoInput.height) self._trackRange.max = value.videoInput.endFrame-value.videoInput.startFrame def newPositionsChoosen(self, value): """ Event called when a new dataset of Positions is choosen @param frame: Frame that would be showed @type frame: Numpy array """ if value: items = value._results.values self._results.clearItems() for key, sql in items: self._results.addItem(key, sql) self._columns.clear() list_of_columns = self._query.columns self._columns.value = map(lambda x: (x, False), list_of_columns) self._x_col = self._query.columnIndex("x") self._y_col = self._query.columnIndex("y") self._frame_col = self._query.columnIndex("frame") def processFrame(self, frame, drawSelectedRows = True): """ This is an event called by the player before he shows the video frame @param frame: Frame that would be showed @type frame: Numpy array """ #Draw the path of the rat if self._showTrack.value: row_index = self._query.mouseSelectedRowIndex if row_index!=None: points = [] for row in range(row_index, row_index + self._trackRange.value): values = self._query.valuesInRow(row) if values!= None: x = int(values[self._x_col]) y = int(values[self._y_col]) points.append( (x,y) ) if len(points)>0: cv2.polylines( frame , [array(points,int32)] , False, (255,255,0), 1, lineType=cv2.cv.CV_AA ) #draw the selected path #When the rows are selected with the popup menu in the Table if drawSelectedRows: selectedRows = self._query.selectedRows if len( selectedRows )>0: track_points = [] for row in selectedRows: values = self._query.valuesInRow(row) x = int(values[self._x_col]) y = int(values[self._y_col]) track_points.append( (x,y) ) cv2.polylines(frame, [array(track_points,int32)], False, (0,255,0), 1) for point in track_points: cv2.circle(frame, point, 3, (0,0,255), thickness=1, lineType= cv2.cv.CV_AA) #Draw the current mouse selected row if self._current_row != None and self._showPos.value: frame = self.drawRow( frame, self._current_row, (0,0,255) ) if self._player.is_playing(): self.drawCurrentPositionWhenIsPlaying(frame) return frame ############################################################################ ############ Functions ##################################################### ############################################################################ def search_4_frame(self, frame2Search, startAtRow = 0): """ This function search for a frame in the List _query @param frame2Search: Frame to search @type frame2Search: Integer @param startAtRow: Start looking in the List row index @type startAtRow: Integer """ if startAtRow<0: startAtRow=0 total_count_rows = self._query.count if total_count_rows==0: # No rows return None elif total_count_rows==1: #If only one row unique_row = self._query.valuesInRow( 0 ) frame = int(unique_row[self._frame_col]) if frame > frame2Search: return 0, None, unique_row, None else: return None, 0, None, unique_row elif startAtRow >= total_count_rows: # In case of start searching in a non existing row last_row = self._query.valuesInRow( total_count_rows-1 ) return total_count_rows-1, None, last_row, None else: #check the next row previous_row = self._query.valuesInRow( startAtRow ) next_row = self._query.valuesInRow( startAtRow + 1 ) if previous_row!=None and next_row!=None: #check the current row previous_frame = int(previous_row[self._frame_col]) next_frame = int(next_row[self._frame_col]) if previous_frame<=frame2Search<next_frame: return startAtRow, startAtRow+1, previous_row, next_row else: #check the next row previous_row = self._query.valuesInRow( startAtRow+1 ) next_row = self._query.valuesInRow( startAtRow+2 ) if previous_row!=None and next_row!=None: previous_frame = int(previous_row[self._frame_col]) next_frame = int(next_row[self._frame_col]) if previous_frame<=frame2Search<next_frame: return startAtRow+1, startAtRow+2, previous_row, next_row #check if the frame to search is bellow the first row and higher than the last frame first_row = self._query.valuesInRow( 0 ) first_frame = int(first_row[self._frame_col]) last_row = self._query.valuesInRow( total_count_rows-1 ) last_frame = int(last_row[self._frame_col]) if first_frame>=frame2Search: return None, 0, None, first_row elif frame2Search>=last_frame: return total_count_rows-1, None, last_row, None else: #Give up!!!! ....Start a binary tree search previous_row_index = 0 next_row_index = (total_count_rows+1)/2 count = 0 # search for the frame calculateSize = True while True: if count > 10000: # for security. We don't want the algorithm to enter in a infinite loop return None if calculateSize: sizeOfList2Search = (next_row_index - previous_row_index) calculateSize = True next_row = self._query.valuesInRow( next_row_index ) next_frame = int( next_row[self._frame_col] ) previous_row = self._query.valuesInRow( previous_row_index ) previous_frame = int( previous_row[self._frame_col] ) if sizeOfList2Search==1 and previous_frame <= frame2Search < next_frame: return previous_row_index, next_row_index, previous_row, next_row elif sizeOfList2Search<1: return None elif previous_frame==frame2Search: return previous_row_index, previous_row_index+1, previous_row, self._query.valuesInRow( previous_row_index+1 ) elif next_frame <= frame2Search and sizeOfList2Search>1: previous_row_index = next_row_index next_row_index += (sizeOfList2Search+1)/2 if next_row_index>=total_count_rows: next_row_index = total_count_rows-1 elif previous_frame < frame2Search < next_frame and sizeOfList2Search>1: next_row_index -= (sizeOfList2Search+1)/2 if next_row_index<0: next_row_index = previous_row_index+1 calculateSize = False else: count += 1 def drawCurrentPositionWhenIsPlaying( self, frame ): current_frame = self._player.value.getCurrentFrame() res = self.search_4_frame( current_frame, self._current_row_index ) if res!=None and self._showPos.value: previous_index, next_index, previous_row, next_row = res row = None if previous_row==None: self._current_row_index = 0 row = next_row x, y = int(row[self._x_col]), int(row[self._y_col]) elif next_row==None: self._current_row_index = previous_index row = previous_row x, y = int(row[self._x_col]), int(row[self._y_col]) else: row = previous_row prev_x, prev_y = float(previous_row[self._x_col]), float(previous_row[self._y_col]) next_x, next_y = float(next_row[self._x_col]), float(next_row[self._y_col]) prev_frame, next_frame = int(previous_row[0]), int(next_row[0]) nSteps = float(next_frame - prev_frame) xStep, yStep = (next_x-prev_x)/nSteps, (next_y-prev_y)/nSteps nSteps2CurrentFrame = float(current_frame-prev_frame) x, y = xStep*nSteps2CurrentFrame, yStep*nSteps2CurrentFrame x, y = int(round( prev_x + x )), int(round( prev_y + y )) #row[self._x_col], row[self._y_col] = x, y #frame = self.drawRow( frame, row, (255,0,0) ) cv2.circle(frame, (x,y), 3, (255,0,0), 2) return frame def drawRow(self, frame, row, color = (0,255,0) ): x, y = int(row[self._x_col]), int(row[self._y_col]) cv2.circle(frame, (x, y), 3, color, thickness=2, lineType= cv2.cv.CV_AA) return frame def interpolateBetween2Rows(self, row1, row2, update = (lambda x: 0), cols_2_interpolate = None ): """ Interpolate values between 2 rows @param row1: First row @type row1: Integer @param row2: First row @type row2: Integer """ if cols_2_interpolate==None: checked_columns = self._columns.checkedIndexes n_columns = len(self._query.columns) cols_2_interpolate = map( lambda x: True if x in checked_columns else False, range(n_columns) ) else: n_columns = len(cols_2_interpolate) previous_row = self._query.valuesInRow( row1 ) next_row = self._query.valuesInRow( row2 ) previous_frame = int( previous_row[self._frame_col] ) next_frame = int( next_row[self._frame_col] ) diff_frames = float( next_frame - previous_frame ) if diff_frames>1: previous, next, diff, step = [], [], [], [] for i in range(n_columns): if cols_2_interpolate[i]: previous.append( float(previous_row[i]) ) next.append( float(next_row[i]) ) diff = float(next[i]) - float(previous[i]) step.append( diff / diff_frames ) else: step.append( None ) previous.append( previous_row[i] ) next.append( next_row[i] ) for j in range(1, int(diff_frames)): values = [] for i in range(n_columns): if cols_2_interpolate[i]: if int(previous[i])==previous[i] and int(next[i])==next[i]: val = int(previous[i]) + int(round( step[i]* float(j) )) else: val = previous[i] + step[i]*float(j) else: val = previous[i] values.append( val ) update( row1 + j ) values.pop(0) self._query.addRow( values, -1,cols= [ 'frame', 'seconds','milliseconds', 'x', 'y', 'object' ]) QApplication.processEvents()