Exemple #1
0
class Tracker:
    LIG_THR_EVERY_FRAMES = 15

    def __init__(self, initialPosition, initialWidth, initialHeight, frame,
                 parametersNew):

        #########################################

        #########################################
        self.initFrame = frame
        self.initPos = initialPosition
        self.initW = initialWidth
        self.initH = initialHeight
        self.KM = KalmanFilter()
        self.MF = MaskingFilter()
        self.KM.setStatePost(
            np.array([initialPosition[0], initialPosition[1], 0.,
                      0.]).reshape(4, 1))
        self.selectionWidth = initialWidth
        self.selectionHeight = initialHeight

        self.prevFrameGray = None
        self.frameCounter = 0  #Shape = {tuple}: (x, 1, 2)
        #Por ejemplo: [[[x1 y1]]\n\n [[x2 y2]]\n\n [[x3 y3]]]
        #es decir una matriz de x filas y 1 columna, donde cada elemento
        #de la unica columna es una coordenada [x y].
        if self.MF.mask is not self.MF.maskingType["FILTER_OFF"]:
            self.MF.calculateNewMask(
                frame, frame[int(initialPosition[1] -
                                 initialHeight / 2):int(initialPosition[1] +
                                                        initialHeight / 2),
                             int(initialPosition[0] -
                                 initialWidth / 2):int(initialPosition[0] +
                                                       initialWidth / 2)])
            frame = self.MF.filterFrame(frame)

        self.prevFrameGray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

        self.SC = Searcher(self.initFrame, initialHeight, initialWidth,
                           initialPosition[0], initialPosition[1],
                           cv.cvtColor(frame, cv.COLOR_BGR2GRAY))
        self.SC.features, self.SC.trackingError = self.SC.ST.recalculateFeatures(
            self.prevFrameGray[int(initialPosition[1] -
                                   initialHeight / 2):int(initialPosition[1] +
                                                          initialHeight / 2),
                               int(initialPosition[0] -
                                   initialWidth / 2):int(initialPosition[0] +
                                                         initialWidth / 2)])
        self.SC.features = self.SC.featureTranslate(
            initialPosition[0] - initialWidth / 2,
            initialPosition[1] - initialHeight / 2, self.SC.features)
        self.SC.LK.prevFeatures = self.SC.features

        #OPTIMIZACIÓN
        self.bins_var = 1
        self.kernel_blur_var = 1
        self.mask_blur_var = 1
        self.low_pth_var = 200

    def getTrackingError(self):
        return self.SC.trackingError

    def setFilter(self, filterType):
        if filterType in self.MF.maskingType.keys():
            self.MF.mask = self.MF.maskingType[filterType]
        else:
            print("Wrong filter type")

    def featureTranslate(self, x, y, features):
        if features is None:
            return None
        for i in range(features.shape[0]):
            features[i][0][0] += x
            features[i][0][1] += y
        return features

    def update(self, frame):

        self.frameCounter += 1
        self.KM.predict()
        realframe = frame
        if self.MF.mask is self.MF.maskingType["FILTER_LAB"]:

            if self.frameCounter != 0 and self.frameCounter % self.MF.CIELabRecalculationNumber == 0 and self.MF.labPeriodicRecalculations is True and self.SC.trackingError is False:
                vx, vy = self.getEstimatedVelocity()
                if np.abs(vx) < 5 and np.abs(vy) < 5:
                    medx, medy = np.median(
                        self.SC.features[:, 0,
                                         0]), np.median(self.SC.features[:, 0,
                                                                         1])
                    std = np.sqrt((np.std(self.SC.features[:, 0, 0]))**2 +
                                  (np.std(self.SC.features[:, 0, 1]))**2)
                    # calculate mean and std of features
                    mask = (self.SC.features[:, 0, 0] <
                            medx + self.SC.stdMultiplier * std + 0.1) & (
                                self.SC.features[:, 0, 0] >
                                medx - self.SC.stdMultiplier * std - 0.1) & (
                                    self.SC.features[:, 0, 1] <
                                    medy + self.SC.stdMultiplier * std +
                                    0.1) & (self.SC.features[:, 0, 1] > medy -
                                            self.SC.stdMultiplier * std - 0.1)
                    self.SC.features = self.SC.features[mask]
                    # remove outliers.
                    medx, medy = np.median(
                        self.SC.features[:, 0,
                                         0]), np.median(self.SC.features[:, 0,
                                                                         1])
                    if (~np.isnan(medx)) and (~np.isnan(medy)):
                        self.MF.calculateNewMask(
                            frame,
                            frame[int(medy - self.selectionHeight /
                                      2):int(medy + self.selectionHeight / 2),
                                  int(medx - self.selectionWidth /
                                      2):int(medx + self.selectionWidth / 2)])

            frame = self.MF.filterFrame(frame)
        elif self.MF.mask is self.MF.maskingType["FILTER_CSHIFT"]:
            frame = self.MF.filterFrame(frame)
            #TINCHO

        #Tacking error?
        if self.SC.trackingError is True:
            if self.SC.missAlgorithm == self.SC.missAlgorithmD["ST"]:
                x, y = self.SC.searchMissing(self.KM.statePost[0][0],
                                             self.KM.statePost[1][0], frame,
                                             frame)
            elif self.SC.missAlgorithm == self.SC.missAlgorithmD["CORR"]:
                x, y = self.SC.searchMissing(self.KM.statePost[0][0],
                                             self.KM.statePost[1][0],
                                             realframe, frame)
            if self.SC.trackingError is False:
                self.KM.correct(x, y)
        else:
            x, y = self.SC.search(self.frameCounter, realframe, frame)
            if self.SC.trackingError is False:
                self.KM.correct(x, y)

    def changeSettings(self, parametersNew):

        self.KM.dt = parametersNew[0]  #kalman_ptm
        self.KM.PROCESS_COV = parametersNew[1]  #kalman_pc
        self.KM.MEAS_NOISE_COV = parametersNew[2]  #kalman_mc

        self.SC.LK.lkMaxLevel = int(parametersNew[3])  #lk_mr

        if parametersNew[4] is False:  #Color Filter OnOff
            self.MF.mask = self.MF.maskingType["FILTER_OFF"]

        self.MF.LSemiAmp = parametersNew[5]  #colorFilter_LihtThr
        self.MF.aSemiAmp = parametersNew[6]  #colorFilter_a
        self.MF.bSemiAmp = parametersNew[7]  #colorFilter_b

        if parametersNew[20] == True and parametersNew[19] == False:
            self.SC.missAlgorithm = self.SC.missAlgorithmD["ST"]
        elif parametersNew[20] == False and parametersNew[19] == True:
            self.SC.missAlgorithm = self.SC.missAlgorithmD["CORR"]
        if parametersNew[22] == True and parametersNew[21] == False:
            self.SC.recalcAlgorithm = self.SC.recalcAlgorithmD["ST"]
        elif parametersNew[22] == False and parametersNew[21] == True:
            self.SC.recalcAlgorithm = self.SC.recalcAlgorithmD["CORR"]
        self.SC.MASKCONDITION = parametersNew[23]

        #= parametersNew[8]     #Light R OnOff
        #= parametersNew[9]    #ligtRec_x)
        #= parametersNew[10]   #ligtRec_maxT

        #= parametersNew[11]    #Cam shift On/Off

        self.SC.ST.maxcorners = int(parametersNew[13])  #shit_MaxFeat
        self.SC.ST.qLevel = parametersNew[14]  #shit_FeatQual
        self.SC.ST.minDist = parametersNew[15]  #shit_MinFeat

        #= parametersNew[16]                #ShiTomasiOn/ Off
        self.SC.ST.frameRecalculationNumber = parametersNew[16]  #shit_SPix

        #self.MF.mask = self.MF.maskingType[parametersNew[??]] #MENSAJE PARA TOMI: tiene que ser un string parametersNew[??] fijate en la clase

        self.MF.hist_filter.set_bins(parametersNew[9])
        self.MF.hist_filter.set_mask_blur(parametersNew[10])
        self.MF.hist_filter.set_kernel_blur(parametersNew[11])
        self.MF.hist_filter.set_low_pth(parametersNew[12])

        self.MF.ksize = parametersNew[24]
        if int(self.MF.ksize) % 2 == 0:
            self.MF.ksize = int(self.MF.ksize) + 1
        else:
            self.MF.ksize = int(self.MF.ksize)

        self.MF.updateMaskFromSettings()
        self.KM.updateParams()

    def updateKalman(self, kalman_ptm, kalman_pc, kalman_mc):
        self.KM.dt = kalman_ptm
        self.KM.PROCESS_COV = kalman_pc
        self.KM.MEAS_NOISE_COV = kalman_mc
        self.KM.updateParams()

    def updateLK(self, lk_mr):
        self.SC.LK.lkMaxLevel = lk_mr

    def updateColorFilter(self, CFPropOnOff, LihtThr, a, b, maskBlur_lab):
        if CFPropOnOff is False:  # Color Filter OnOff
            self.MF.mask = self.MF.maskingType["FILTER_OFF"]

        self.MF.LSemiAmp = LihtThr
        self.MF.aSemiAmp = a
        self.MF.bSemiAmp = b

        self.MF.ksize = maskBlur_lab
        if int(self.MF.ksize) % 2 == 0:
            self.MF.ksize = int(self.MF.ksize) + 1
        else:
            self.MF.ksize = int(self.MF.ksize)

        self.MF.updateMaskFromSettings()

    def updateCamShift(self, CFCamShiftOnOff, bins, mb, sb, lbpt):
        self.MF.hist_filter.set_bins(bins)
        self.MF.hist_filter.set_mask_blur(mb)
        self.MF.hist_filter.set_kernel_blur(sb)
        self.MF.hist_filter.set_low_pth(lbpt)

        self.MF.updateMaskFromSettings()

    def updateShiT(self, MaxFeat, FeatQual, MinFeat, Rec, ShiTPropOnOff, SPix):
        self.SC.ST.maxcorners = int(MaxFeat)
        self.SC.ST.qLevel = FeatQual
        self.SC.ST.minDist = MinFeat
        self.SC.ST.frameRecalculationNumber = Rec

    def updateMissinSearch(self, missCorr, missST, recCor, recST):
        if missST == True and missCorr == False:
            self.SC.missAlgorithm = self.SC.missAlgorithmD["ST"]
            self.SC.searchHeight = self.initH
            self.SC.searchWidth = self.initW
        elif missST == False and missCorr == True:
            self.SC.missAlgorithm = self.SC.missAlgorithmD["CORR"]
            self.SC.searchHeight = self.initH
            self.SC.searchWidth = self.initW
        if recST == True and recCor == False:
            self.SC.recalcAlgorithm = self.SC.recalcAlgorithmD["ST"]
        elif recST == False and recCor == True:
            self.SC.recalcAlgorithm = self.SC.recalcAlgorithmD["CORR"]

    def updateMaskCond(self, maskCondition):
        self.SC.MASKCONDITION = maskCondition

    def updateBGR(self, color):
        self.MF.calculateNewMask(None, None, True, color)
        self.MF.updateMaskFromSettings()

    def getFilteredFrame(self):
        return self.MF.filteredFrame

    def getCorrFrame(self):
        return self.SC.corr_out

    def getEstimatedPosition(self):
        return self.KM.statePost[0][0], self.KM.statePost[1][0]

    def getEstimatedVelocity(self):
        return self.KM.statePost[2][0], self.KM.statePost[3][0]

    def getTrajectory(self):
        return self.KM.trajectory

    def costChangeParamsLAB(self, x):
        self.MF.LSemiAmp = x[0]
        self.MF.aSemiAmp = x[1]
        self.MF.bSemiAmp = x[2]
        self.MF.updateMaskFromSettings()
        testFrame = self.MF.filterFrame(self.initFrame)

        countTotal = np.count_nonzero(testFrame)
        countInside = np.count_nonzero(testFrame[
            int(self.initPos[1] -
                self.selectionHeight / 2):int(self.initPos[1] +
                                              self.selectionHeight / 2),
            int(self.initPos[0] -
                self.selectionWidth / 2):int(self.initPos[0] +
                                             self.selectionWidth / 2)])

        countOutside = countTotal - countInside
        # print(countOutside-countInside)
        # return countOutside*(1/5) - countInside*(4/5)
        return countOutside - countInside

    def calculate_optimal_params(self):
        if self.MF.mask is self.MF.maskingType["FILTER_LAB"]:
            self.optimize()
            params = {
                "l": self.MF.LSemiAmp,
                "a": self.MF.aSemiAmp,
                "b": self.MF.bSemiAmp,
                "blur": self.MF.ksize
            }
            return params
        elif self.MF.mask is self.MF.maskingType["FILTER_CSHIFT"]:
            for i in range(3):
                self.optimize()
            params = {
                "bins": self.MF.hist_filter.bins_opti,
                "mask_blur": self.MF.hist_filter.mask_blur_size_opti,
                "kernel_blur": self.MF.hist_filter.kernel_blur_size_opti,
                "low_pth": self.MF.hist_filter.low_pth_opti
            }
            return params

    def calculate_cost(self):
        test_frame = self.MF.filterFrame(self.initFrame)
        count_total = np.count_nonzero(test_frame)
        count_inside = np.count_nonzero(test_frame[
            int(self.initPos[1] -
                self.selectionHeight / 2):int(self.initPos[1] +
                                              self.selectionHeight / 2),
            int(self.initPos[0] -
                self.selectionWidth / 2):int(self.initPos[0] +
                                             self.selectionWidth / 2)])
        count_outside = count_total - count_inside
        return count_outside - count_inside
        # return count_outside**4 - count_inside**3 #PREFERIMOS QUE ESTE VACIO AFUERA

    def optimize(self):

        if self.MF.mask is self.MF.maskingType["FILTER_LAB"]:

            for j in range(3):
                best_L = [self.MF.LSemiAmp]
                best_cost = self.calculate_cost()

                for i in range(10, 150):
                    self.MF.LSemiAmp = i
                    self.MF.updateMaskFromSettings()
                    cost = self.calculate_cost()
                    if cost < best_cost:
                        best_L.append(i)
                        best_cost = cost

                self.MF.LSemiAmp = best_L[-1]
                self.MF.updateMaskFromSettings()

                best_mask_blur = [self.MF.ksize]
                # best_cost = 0
                for i in [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]:
                    self.MF.ksize = i
                    cost = self.calculate_cost()
                    if cost < best_cost:
                        best_mask_blur.append(i)
                        best_cost = cost
                self.MF.ksize = best_mask_blur[-1]

                best_a = [self.MF.aSemiAmp]
                for i in range(5, 100):
                    self.MF.aSemiAmp = i
                    self.MF.updateMaskFromSettings()
                    cost = self.calculate_cost()
                    if cost < best_cost:
                        best_a.append(i)
                        best_cost = cost
                self.MF.aSemiAmp = best_a[-1]
                self.MF.updateMaskFromSettings()

                best_b = [self.MF.bSemiAmp]
                for i in range(5, 100):
                    self.MF.bSemiAmp = i
                    self.MF.updateMaskFromSettings()
                    cost = self.calculate_cost()
                    if cost < best_cost:
                        best_b.append(i)
                        best_cost = cost
                self.MF.bSemiAmp = best_b[-1]
                self.MF.updateMaskFromSettings()

                self.MF.LSemiAmp = best_L[-1]
                self.MF.aSemiAmp = best_a[-1]
                self.MF.bSemiAmp = best_b[-1]
                self.MF.ksize = best_mask_blur[-1]

                self.MF.updateMaskFromSettings()

                x_bounds = [(0, 150), (0, 150), (0, 150)]
                x0 = np.array(
                    [self.MF.LSemiAmp, self.MF.aSemiAmp, self.MF.bSemiAmp])
                # res = optimize.least_squares(self.costChangeParamsLAB,x0=x0,bounds=[(0,0,0),(150,150,150)],ftol=1000)
                #res = optimize.minimize(self.costChangeParamsLAB, x0=x0, bounds=x_bounds,method="Powell")
                res = optimize.minimize(self.costChangeParamsLAB,
                                        x0=x0,
                                        method="Powell")
            self.MF.LSemiAmp = res.x[0]
            self.MF.aSemiAmp = res.x[1]
            self.MF.bSemiAmp = res.x[2]
            self.MF.updateMaskFromSettings()

        else:
            best_bin = [self.MF.hist_filter.bins]
            best_cost = self.calculate_cost()

            for i in range(1, 200):
                self.MF.hist_filter.set_bins(i)
                self.MF.updateMaskFromSettings()
                cost = self.calculate_cost()
                if cost < best_cost:
                    best_bin.append(i)
                    best_cost = cost

            self.MF.hist_filter.set_bins(best_bin[-1])
            self.MF.updateMaskFromSettings()

            best_mask_blur = [self.MF.hist_filter.mask_blur_size]
            # best_cost = 0
            for i in [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]:
                self.MF.hist_filter.set_mask_blur(i)
                cost = self.calculate_cost()
                if cost < best_cost:
                    best_mask_blur.append(i)
                    best_cost = cost
            self.MF.hist_filter.set_mask_blur(best_mask_blur[-1])

            best_kernel_blur = [self.MF.hist_filter.kernel_blur_size]
            for i in [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]:
                self.MF.hist_filter.set_kernel_blur(i)
                self.MF.updateMaskFromSettings()
                cost = self.calculate_cost()
                if cost < best_cost:
                    best_kernel_blur.append(i)
                    best_cost = cost
            self.MF.hist_filter.set_kernel_blur(best_kernel_blur[-1])
            self.MF.updateMaskFromSettings()

            best_low_pth = [self.MF.hist_filter.low_pth]

            self.MF.hist_filter.set_bins(best_bin[-1])
            self.MF.hist_filter.set_mask_blur(best_mask_blur[-1])
            self.MF.hist_filter.set_kernel_blur(best_kernel_blur[-1])
            self.MF.hist_filter.set_low_pth(best_low_pth[-1])

            self.MF.hist_filter.bins_opti = best_bin[-1]
            self.MF.hist_filter.mask_blur_size_opti = best_mask_blur[-1]
            self.MF.hist_filter.kernel_blur_size_opti = best_kernel_blur[-1]
            self.MF.hist_filter.low_pth_opti = best_low_pth[-1]

            # self.MF.hist_filter.set_low_pth(best_low_pth[-1])
            self.MF.updateMaskFromSettings()

    def colorKernelChange(self, bgr):
        b = bgr[0]
        g = bgr[1]
        r = bgr[2]

    def showSearchArea(self):
        if self.SC.missAlgorithm == self.SC.missAlgorithmD["ST"]:
            return True
        else:
            return False