Exemple #1
0
class OTModuleClusterObjectsPositions(OTModuleResultsPlugin,
                                      OTModulePositions):
    def __init__(self, name):
        icon_path = tools.getFileInSameDirectory(__file__, 'icon.jpg')
        OTModuleResultsPlugin.__init__(self, name, iconFile=icon_path)

        self._positions = OTParamPositions("Positions")
        self._video = OTParamVideoInput("Video")
        self._player = OTParamPlayer("Video player")
        self._nobjects = OTParamSlider("Number of objects to track", 1, 1, 10)
        self._run = OTParamButton("Run")
        self._apply = OTParamButton("Apply changes")
        self._progress = OTParamProgress()

        #self._query.readOnly = True
        self._run.value = self.run
        self._apply.value = self.apply
        self._video.valueUpdated = self.newVideoInputChoosen
        self._player.processFrame = self.processFrame
        self._query.form.tableView.keyPressEvent = self.keyPressEvent

        self._current_row = None

        self._formset = [('_video', "_positions", '_nobjects', '_run'),
                         '_player', '=', ("_results", '_apply'), "_query",
                         "_progress"]

        self._progress.hide()

    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

    def apply(self):
        updatequery = QtSql.QSqlQuery(self.parentModule.sqldb)
        selectquery = QtSql.QSqlQuery(self.parentModule.sqldb)
        query = "SELECT a.object, b.id FROM %s a inner join %s b on a.frame=b.frame and a.new_object=b.object WHERE a.new_object<>'' " % (
            self._query.table, self._query.table)
        selectquery.exec_(query)
        while (selectquery.next()):
            row = selectquery.record()
            obj = int(row.value("object").toString())
            rowid = int(row.value("id").toString())
            query = "UPDATE %s SET object=%s WHERE id=%s " % (
                self._query.table, obj, rowid)
            updatequery.exec_(query)

        query = "UPDATE %s SET object=new_object WHERE new_object<>'' " % self._query.table
        updatequery.exec_(query)
        query = "UPDATE %s SET new_object='' " % self._query.table
        updatequery.exec_(query)
        updatequery.finish()
        self._query.orderBy = 1

    def keyPressEvent(self, event):
        #print event.key()
        if event.key() in (16777235, 16777237, 16777233, 16777232, 16777238,
                           16777239, 16777248):
            QTableView.keyPressEvent(self._query.form.tableView, event)
        else:
            key = event.text()
            if event.key() == 16777219 or event.key() == 16777223: key = ""
            if key == '' or key in self._results.keys:
                for row in self._query.mouseSelectedRowsIndexes:
                    self._query.setValueIn(row, 13, key)
                self._query.commit()

    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[1]) - 1
            video.videoInput.setFrame(frame_index)
            self._player.updateFrame()

    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 current mouse selected row
        if self._current_row != None:
            x = int(self._current_row[4])
            y = int(self._current_row[5])
            velocity = eval(str(self._current_row[6]))
            accelaration = eval(str(self._current_row[7]))
            blob = array([eval(str(self._current_row[8]))])

            cv2.circle(frame, (x, y), 6, (0, 0, 255), -1)
            cv2.polylines(frame, blob, True, (0, 255, 0), 1)

            xx = int(math.ceil(x + velocity[0] + 0.5 * accelaration[0]))
            yy = int(math.ceil(y + velocity[1] + 0.5 * accelaration[1]))
            cv2.line(frame, (x, y), (xx, yy), (255, 0, 0), 2)

        return frame

    def __smallestDistance(self, point, positions):
        smallest_dist = 1000000
        index = -1
        for i, values in enumerate(positions):
            frame, x, y = int(values[1]), int(values[4]), int(values[5])
            dist = tools.pointsDistance(point, (x, y))
            if dist <= smallest_dist:
                smallest_dist = dist
                index = i
        return index

    def __guessPositions(self, objs_window, nobjects=2):
        origin = [None for x in range(nobjects)]

        for frameIndex, frame in enumerate(objs_window.get()):
            if frameIndex == 0: continue

            final_selection = list(origin)
            scores = []

            for objIndex, obj in enumerate(frame):
                for last_obj in objs_window.get(frameIndex - 1):
                    classification = last_obj.scorePosition(obj._position)
                    scores.append([classification, last_obj, obj])
            scores = sorted(scores, key=lambda x: x[0], reverse=True)

            used = []
            for score_index in range(len(scores)):
                classification, last_object, new_obj = scores[score_index][
                    0], scores[score_index][1], scores[score_index][2]
                #if classification>0.005 and final_selection[last_object._label]==None:
                if final_selection[
                        last_object._label] == None and new_obj not in used:
                    new_obj.calcEnergyProperties(last_object)
                    new_obj._label = last_object._label
                    final_selection[last_object._label] = new_obj
                    used.append(new_obj)

            for i, obj in enumerate(final_selection):
                if obj == None:
                    final_selection[i] = objs_window.get(frameIndex -
                                                         1)[i].genNextFrame()

            objs_window.set(frameIndex, final_selection)

        self._firstTime = False
        return objs_window

    def __getFirstValues(self, query, nvalues):
        sqlquery = QtSql.QSqlQuery(self.parentModule.sqldb)
        sqlquery.exec_(query)
        results = []
        for index in range(nvalues):
            sqlquery.next()
            row = sqlquery.record()

            rowid = int(row.value("id").toString())
            frame = int(row.value("frame").toString())
            seconds = float(row.value("seconds").toString())
            milliseconds = float(row.value("milliseconds").toString())
            x = int(row.value("x").toString())
            y = int(row.value("y").toString())
            obj = str(row.value("polygon").toString())
            r = str(row.value("r").toString())
            g = str(row.value("g").toString())
            b = str(row.value("b").toString())

            values = [rowid, frame, seconds, milliseconds, x, y, obj, r, g, b]
            results.append(values)
        return results

    def __row2List(self, row):
        rowid = int(row.value("id").toString())
        frame = int(row.value("frame").toString())
        seconds = float(row.value("seconds").toString())
        milliseconds = float(row.value("milliseconds").toString())
        x = int(row.value("x").toString())
        y = int(row.value("y").toString())
        obj = str(row.value("polygon").toString())
        r = str(row.value("r").toString())
        g = str(row.value("g").toString())
        b = str(row.value("b").toString())
        return [rowid, frame, seconds, milliseconds, x, y, obj, r, g, b]

    def run(self):

        totalResults = self._positions.value.countAllResults()
        self._progress.min = 0
        self._progress.value = 0
        self._progress.max = totalResults
        self._progress.show()
        QApplication.processEvents()

        sqlquery = QtSql.QSqlQuery(self.parentModule.sqldb)
        insertquery = QtSql.QSqlQuery(self.parentModule.sqldb)

        insertquery.exec_("PRAGMA cache_size = 65536")
        insertquery.exec_("PRAGMA temp_store = MEMORY")
        insertquery.exec_("PRAGMA journal_mode = OFF")
        insertquery.exec_("PRAGMA synchronous = OFF")

        tablename = "%s_output" % (self.name.replace(" ",
                                                     "").lstrip('0123456789.'))
        insertquery.exec_("DROP TABLE IF EXISTS %s" % tablename)
        insertquery.exec_(
            "CREATE TABLE if not exists %s(id INTEGER PRIMARY KEY AUTOINCREMENT, frame BIGINT, seconds DOUBLE, milliseconds BIGINT, x INTEGER, y INTEGER, velocity TEXT, accelaration TEXT, polygon TEXT, r INTEGER, g INTEGER, b INTEGER, object INTEGER, new_object INTEGER)"
            % tablename)

        count = 0

        for query in self._positions.value.getAllQueries():
            last_frame, frame_values = -1, []
            sqlquery.exec_(query)

            valuesWindow = tools.RingBuffer(20)

            while (sqlquery.next()):
                row = sqlquery.record()
                values = self.__row2List(row)
                frame = values[1]

                if frame != last_frame and last_frame != -1:

                    #first frame give names to objects
                    if valuesWindow.count() == 0:
                        valuesWindow.append([
                            EnergeticObject(vals, label=i)
                            for i, vals in enumerate(frame_values)
                        ])
                    else:
                        valuesWindow.append(
                            [EnergeticObject(vals) for vals in frame_values])
                    #valuesWindow.printValues()

                    valuesWindow = self.__guessPositions(valuesWindow)

                    if valuesWindow.count() == 20:
                        for frameObjects in valuesWindow.get():
                            for obj in frameObjects:
                                if obj._saved != True:
                                    query = "INSERT INTO %s(frame, seconds, milliseconds, x, y, velocity, accelaration, polygon, r, g, b, object) VALUES (%s,%f,%f,%s,%s,'%s', '%s','%s', %s, %s, %s, %s)" % (
                                        tablename, obj._frame,
                                        obj._milliseconds, obj._seconds,
                                        obj._position[0], obj._position[1],
                                        obj._velocity, obj._accelaration,
                                        obj._blob, obj._r, obj._g, obj._b,
                                        obj._label)
                                    insertquery.exec_(query)
                                    obj._saved = True
                    frame_values = [values]
                else:
                    frame_values.append(values)

                last_frame = frame

                count += 1
                self._progress.value = count
                QApplication.processEvents()

            for frameObjects in valuesWindow.get():
                for obj in frameObjects:
                    if obj._saved != True:
                        query = "INSERT INTO %s(frame, seconds, milliseconds, x, y, velocity, accelaration, polygon, r, g, b, object) VALUES (%s,%f,%f,%s,%s,'%s', '%s','%s', %s, %s, %s, %s)" % (
                            tablename, obj._frame, obj._milliseconds,
                            obj._seconds, obj._position[0], obj._position[1],
                            obj._velocity, obj._accelaration, obj._blob,
                            obj._r, obj._g, obj._b, obj._label)
                        insertquery.exec_(query)

        insertquery.exec_("CREATE INDEX Idx3 ON %s(object, new_object);" %
                          tablename)
        insertquery.finish()
        self._progress.value = totalResults
        QApplication.processEvents()
        self.parentModule.sqldb.commit()
        self._progress.hide()

        self._results.clearItems()

        for label in range(self._nobjects.value):
            self._results.addItem(
                "%s" % label,
                "SELECT id, frame, seconds, milliseconds, x, y, velocity, accelaration, object, r, g, b, object, new_object FROM %s WHERE object like %d"
                % (tablename, label))

    def getArenaIntersection(self, x, y, arenasDict):
        for name, arena in arenasDict:
            contour = array([eval(arena)], int32)
            point = (x, y)
            res = cv2.pointPolygonTest(contour, point, False)
            if res >= 0:
                return name
        return "None"
Exemple #2
0
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()