Exemplo n.º 1
0
class MainApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.title("CV Project")

        self.dataHandler = DataHandler(scale_radiographs_by=0.4)
        self.frameFactory = FrameFactory(self.dataHandler)
        self.statisticalModelTrainer = StatisticalModelTrainer()
        self.procrustes = Procrustes()

        self.radiographFrameContainer = RadiographFrameContainer(
            self, self.frameFactory)
        self.procrustesTeethSetImageContainer = None
        self.modelFittingContainer = None

        self.buttonContainer = ButtonContainer(self)
        self.buttonContainer.createImageNavigationButtons(
            self.radiographFrameContainer)
        self.buttonContainer.createFunctionButtons(self)

        self.manualModelPlacementContainer = None

        self.alignedTeeth = list()
        self.meanModels = list()
        self.k_pixels = [13, 7, 2, 2, 1]
        self.m_pixels = [25, 15, 4, 3, 2]
        self.resolutionLevels = 2
        self.filter_settings = [(3, 3, 6), (3, 3, 6), (3, 3, 6), (1, 2, 6),
                                (1, 2, 3)]

        #self.filterTest()
        #self.createMeanModelImages = True

    def filterTest(self):
        radiograph = self.dataHandler.getRadiographs(deepCopy=True)[0]
        blurred_img = Filter.process_image(deepcopy(radiograph.getImage()),
                                           median_kernel=3,
                                           bilateral_kernel=10)
        cv2.imshow("BlurredImage", blurred_img)
        clahe = cv2.equalizeHist(blurred_img)
        cv2.imshow("Clahe", clahe)
        img_1 = Filter.laplacian(blurred_img)
        cv2.imshow("Img1", img_1)

        # radiograph.downScale()
        # blurred_img = Filter.process_image(deepcopy(radiograph.getImage()), median_kernel=3, bilateral_kernel=10)
        # img_2 = Filter.laplacian(deepcopy(blurred_img))
        # height = img_1.shape[0]
        # width = img_1.shape[1]
        # img_2 = cv2.resize(img_1, (int(width*0.5), int(height*0.5)))
        # cv2.imshow("Img2", img_2)

        # radiograph.downScale()
        # blurred_img = Filter.process_image(deepcopy(radiograph.getImage()), median_kernel=3, bilateral_kernel=10)
        # img_3 = Filter.laplacian(deepcopy(blurred_img))
        # height = img_2.shape[0]
        # width = img_2.shape[1]
        # img_3 = cv2.resize(img_2, (int(width*0.5), int(height*0.5)))
        # cv2.imshow("Img3", img_3)

        # radiograph.downScale()
        # blurred_img = Filter.process_image(deepcopy(radiograph.getImage()), median_kernel=3, bilateral_kernel=10)
        # img_4 = cv2.Canny(deepcopy(blurred_img), 15, 15)
        # cv2.imshow("Img4", img_4)

        # radiograph.downScale()
        # blurred_img = Filter.process_image(deepcopy(radiograph.getImage()), median_kernel=3, bilateral_kernel=10)
        # img_5 = cv2.Canny(deepcopy(blurred_img), 15, 15)
        # cv2.imshow("Img5", img_5)

    def trainCompleteStatisticalModel(self):
        self.statisticalModel = self.statisticalModelTrainer.trainCompleteStatisticalModel(
            self.k_pixels,
            self.resolutionLevels,
            self.filter_settings,
            leaveOneOut=0)

        # for i in range(8):
        #     maxEig = self.statisticalModel.getToothModelByIndex(i).getEigenvalues()[0]
        #     print("Tooth " + str(i) + " biggest eigenvalue: " + str(maxEig*10000))

        # if(self.createMeanModelImages):
        #     self.frameFactory.createMeanModelPresentationImages(self.statisticalModel)

    def performManualModelPositionInit(self):
        self.manualModelPlacementContainer = ManualModelPlacementContainer(
            self, self.frameFactory,
            self.statisticalModel.getAllToothModels(deepCopy=True))
        self.buttonContainer.createImageNavigationButtons(
            self.manualModelPlacementContainer)

    def acceptModelPosition(self):
        self.manualModelPlacementContainer.nextMeanModel()

    def changeToothRotation(self, var):
        if self.manualModelPlacementContainer is not None:
            self.manualModelPlacementContainer.manualRotation(var)

    def performAutoModelPositionInit(self):
        return None

    def performModelFitting(self):

        if self.manualModelPlacementContainer is not None:
            initialModelPositions = self.manualModelPlacementContainer.getChosenModelPositions(
            )
            initialModelRotations = self.manualModelPlacementContainer.getChosenModelRotations(
            )
            initialModelPositions *= 2.5

        self.multiResActiveShapeModel = MultiResolutionActiveShapeModel(
            self.statisticalModel,
            resolutionLevels=self.resolutionLevels,
            m_pixels=self.m_pixels,
            k_pixels=self.k_pixels,
            filter_settings=self.filter_settings,
            initialPositions=initialModelPositions,
            initialRotations=initialModelRotations)
        radiograph = DataHandler().getRadiographs(deepCopy=True)[
            self.manualModelPlacementContainer.getChosenRadiograph()]

        # Fit the first tooth to the radiograph
        fittedModels_Y = self.multiResActiveShapeModel.fitCompleteModel(
            radiograph)

        self.fittedModels = list()

        # allign fitted model to be drawn
        for model in fittedModels_Y:
            [X, Y] = model
            temp = self.procrustes.allignModelToData(Y, X)[1]
            self.fittedModels.append(temp)

        self.fittedModels = np.array(self.fittedModels)

        print("fittedModels" + str(np.array(self.fittedModels).shape))
        radiograph.scaleImage(0.4)

        self.frameFactory.createFittingErrorPresentationImages(
            self.fittedModels, radiograph)

        self.modelFittingContainer = ModelFittingContainer(
            self, self.frameFactory, [self.fittedModels], radiograph)
        self.buttonContainer.createImageNavigationButtons(
            self.modelFittingContainer)
class MultiResolutionTrainer:

    def __init__(self):
        self.completeDataHandler = DataHandler()
        self.grayLevelToothModels = None

    def trainGrayLevelMultiResolutionModel(self, k_pixels, resolutionLevels, filter_settings):
        singleResolutionModels = list()
        for i in range(resolutionLevels):
            start_time = time.time()
            singleResModel = self.trainGrayLevelSingleResolutionModel(k_pixels[i], i, filter_settings[i])
            singleResolutionModels.append(singleResModel)
            print("--- %s seconds ---" % (time.time() - start_time))
        singleResolutionModels = np.array(singleResolutionModels)
        print(str(len(singleResolutionModels)) + " single resolution models created")
        return StatisticalGrayLevelMultiResModel(singleResolutionModels, resolutionLevels)

    def trainGrayLevelSingleResolutionModel(self, k_pixels, resolutionLevel, filter_settings):
        """
        Learns the statistical gray-level models for all point on all teeth for a single resolution level 
        """
        g_all = self.trainGrayLevelModelForAllPointsAllExamples(k_pixels, resolutionLevel, filter_settings)
        print("g_all: " + str(g_all.shape))
        grayLevelToothModels = self.trainGrayLevelToothModels(g_all, k_pixels, resolutionLevel)

        print(str(len(grayLevelToothModels)) + " Gray level tooth models created during training")

        return StatisticalGrayLevelSingleResModel(grayLevelToothModels, resolutionLevel)

    def trainGrayLevelToothModels(self, g_all, k_pixels, resolutionLevel):
        grayLevelToothModels = list()
        for i in range(8):
            grayLevelPointModels = list()
            for j in range(40):
                g_point = list()
                for k in range(14):
                    g_point.append(g_all[k][i][j])
                g_point = np.array(g_point)
                g_point_mean = np.mean(g_point, axis=0)
                g_point_cov = np.cov(g_point.T)
                grayLevelPointModels.append(StatisticalGrayLevelPointModel(g_point_mean, g_point_cov, k_pixels, i, j))
            grayLevelPointModels = np.array(grayLevelPointModels)
            statisticalGrayLevelToothModel = StatisticalGrayLevelToothModel(grayLevelPointModels, i, resolutionLevel)
            grayLevelToothModels.append(statisticalGrayLevelToothModel)

        return np.array(grayLevelToothModels)
                    
    def trainGrayLevelModelForAllPointsAllExamples(self, k, resolutionLevel, filter_settings):
        """
        calcualtes the gray-level vectors for all point of all teeth in all provided examples.
        """
        radiographs = self.completeDataHandler.getRadiographs(deepCopy=True)

        g_all = list()
        for radiograph in radiographs:
            
            # Scale image to current resolution level
            for i in range(resolutionLevel):
                radiograph.downScale()

            # Pre process image
            img = Filter.process_image(deepcopy(radiograph.getImage(deepCopy=True)), filter_settings[0], filter_settings[1], filter_settings[2])
            derivate_img = Filter.laplacian(img)
            # derivate_img = Filter.histogramEql(Filter.process_image(deepcopy(img), filter_settings[0], filter_settings[1], filter_settings[2]))
            # derivate_img = Filter.process_image(deepcopy(derivate_img), median_kernel=3, bilateral_kernel=5)
            
            g_ex = self.trainGrayLevelModelForAllPointsOneExample(img, derivate_img, radiograph, k)
            g_all.append(g_ex)
        
        return np.array(g_all)

    def trainGrayLevelModelForAllPointsOneExample(self, img, derivate_img, radiograph, k):
        """
        Calculate the grey-level vectors for all points of all teeth in one example.
        """
        g_ex = list()
        teeth = radiograph.getTeeth()
        for tooth in teeth:
            points = tooth.getLandmarks()
            g_p = list()
            for i in range(len(points)):
                current_point = points[i]
                
                if i == 0:
                    previous_point = points[len(points)-1]
                else:
                    previous_point = points[i-1]
                
                if i == len(points)-1:
                    next_point = points[0]
                else: 
                    next_point = points[i+1]
                
                g_p.append(self.trainGrayLevelModelForOnePointOneExample(img, derivate_img, current_point, previous_point, next_point, k))
            g_ex.append(np.array(g_p))
        
        return np.array(g_ex)

    def trainGrayLevelModelForOnePointOneExample(self, img, derivate_img, current_point, previous_point, next_point, k):
        """
        calculates the grey-level vector of the pixels on the normal in the given point in the given example.
        """
        sample,_,_ = Utils.getSampleFromImage(img, derivate_img, current_point, previous_point, next_point, k)
        return sample
class StatisticalModelTrainer:
    def __init__(self):
        self.completeDataHandler = DataHandler()
        self.procrustes = Procrustes()
        self.pca = PCA()
        self.modelFitter = ModelFitter()
        self.multiResTrainer = MultiResolutionTrainer()

    def trainCompleteStatisticalModel(self,
                                      k_pixels,
                                      resolutionLevels,
                                      filter_settings,
                                      doLeaveOneOutTrainingSetTest=False,
                                      leaveOneOut=None):
        """
        Performs leave-one-out validation of the training set, then 
        trains a statistical model from the entire training set.
        """
        if doLeaveOneOutTrainingSetTest:
            self.doLeaveOneOutTrainingSetValidation()

        if leaveOneOut is not None:
            self.completeDataHandler = DataHandler(leave_one_out=leaveOneOut)

        statisticalToothModels = self.trainModelFromCompleteTrainingSet()

        grayLevelMultiResModel = self.multiResTrainer.trainGrayLevelMultiResolutionModel(
            k_pixels, resolutionLevels, filter_settings)

        completeModel = CompleteStatisticalModel(statisticalToothModels,
                                                 grayLevelMultiResModel)

        print("Statistical model trained!")

        return completeModel

    def trainModel(self, dataHandler):
        """
        Trains a statistical model from the examples provided in the given dataHandler.
        """
        alignedTrainingExamples = self.allignTrainingExamples(dataHandler)
        return self.perfromPCA(alignedTrainingExamples)

    def allignTrainingExamples(self, dataHandler):
        """
        Alligns all training examples, grouped by the same tooth, using procrustes analysis.
        """
        alignedTrainingExamples = list()
        for i in range(8):
            temp = dataHandler.getAllTeethAtIndex(i, deepCopy=True)
            alignedTrainingExamples.append(
                self.procrustes.performProcrustesAlignment(temp))
        return alignedTrainingExamples

    def perfromPCA(self, alignedTrainingExamples):
        """
        Performs PCA on the given training set, and returns the obtained statistical models.
        """
        meanModels = list()
        for i in range(8):
            [mean, eigenvalues, eigenvectors
             ] = self.pca.do_pca_and_build_model(alignedTrainingExamples[i])
            statisticalToothModel = StatisticalToothModel(
                mean, eigenvalues, eigenvectors)
            meanModels.append(statisticalToothModel)
        meanModels = np.array(meanModels)
        return meanModels

    def trainModelFromCompleteTrainingSet(self):
        """
        Trains a statistical model from the complete training set.
        """
        statisticalModel = self.trainModel(self.completeDataHandler)
        return statisticalModel

    def doLeaveOneOutTrainingSetValidation(self):
        """
        Performs a leave-one-out validation of the training set. 
        If for any subset of the training set the error on the left out example
        is too big, the training set is considered insuficient.
        """
        # Number of training examples
        n = len(self.completeDataHandler.getRadiographs(deepCopy=True))

        for i in range(n):
            dataHandler = DataHandler(leave_one_out=i)
            statisticalModel = self.trainModel(dataHandler)
            print("Left out radiograph: " + str(i))
            self.testTrainedModelOnLeftOutExample(dataHandler,
                                                  statisticalModel)

    def testTrainedModelOnLeftOutExample(self, dataHandler, statisticalModel):
        """
        Test the learned model by fitting it to the train examples as well as to the
        left out exampele and compares the mean error on the training examples to the 
        error on the left out example.
        """

        training_radiographs = dataHandler.getRadiographs(deepCopy=True)
        leftOut_radiograph = dataHandler.getLeftOutRadiograph(deepCopy=True)

        total_error = 0
        for radiograph in training_radiographs:
            error = self.fitModelToAnnotatedExampleAndMeasureError(
                radiograph, statisticalModel)
            total_error += error
        errorOnTrainingExamples = total_error / len(training_radiographs)

        errorOnLeftOutExample = self.fitModelToAnnotatedExampleAndMeasureError(
            leftOut_radiograph, statisticalModel)

        errorComparison = errorOnLeftOutExample / errorOnTrainingExamples

        if errorComparison > 3:
            print("Relative error on left out example = " +
                  str(errorOnLeftOutExample))
            print(
                "Error on test image is relativelly big (>3 times the mean error on the train images), "
                + "the training set might not be good enough")

    def fitModelToAnnotatedExampleAndMeasureError(self, radiograph,
                                                  statisticalModel):
        """
        Fits a model to an annotated example and measures the error.
        """
        teeth = radiograph.getTeeth(deepCopy=True)
        total_error = 0
        for i in range(8):
            tooth = deepcopy(teeth[i])
            model = statisticalModel[i]

            # Fit the model to the radiograph
            fitted_model = self.modelFitter.fitModel(deepcopy(tooth), model)

            # align fitted model to examples
            alignedModel = self.procrustes.allignModelToData(
                deepcopy(tooth), fitted_model)[1]

            # Error is the measured as the norm of the difference of the two matrices
            error = (tooth.getLandmarks() - alignedModel.getLandmarks()
                     ) / alignedModel.getLandmarks()
            error = np.linalg.norm(error)
            total_error += error

        return total_error