예제 #1
0
    def __init__(self, pdmodel, glmodel_pyramid):
        self.pdmodel = pdmodel
        self.glmodel_pyramid = glmodel_pyramid

        # initialise examining/fitting/aligning classes
        self.fitter = Fitter(pdmodel)
        self.examiner = Examiner(glmodel_pyramid)
        self.aligner = Aligner()
예제 #2
0
class Fitter(object):
    def __init__(self, pdmodel):
        self.pdmodel = pdmodel
        self.aligner = Aligner()
        self.start_pose = ()

    def fit(self, prev_shape, new_shape, pyramid_level=0, n=None):
        '''
        Algorithm that finds the best shape parameters that match identified
        image points.

        In: PointDistributionModel instance pdm,
            array of new image points (x1, x2, ..., xN, y1, y2,..., yN)
        Out: the pose params (Tx, Ty, s, theta) and shape parameter (c) to
            fit the model to the image
        '''
        if not isinstance(new_shape, Shape):
            new_shape = Shape(new_shape)
        if not isinstance(prev_shape, Shape):
            prev_shape = Shape(prev_shape)
        if not self.start_pose:
            raise ValueError('No inital pose parameters found.')

        # find pose parameters to align with new image points
        Tx, Ty, s, theta = self.start_pose
        dx, dy, ds, dTheta = self.aligner.get_pose_parameters(prev_shape, new_shape)
        changed_pose = (Tx + dx, Ty + dy, s*(1+ds), theta+dTheta)

        # align image with model
        y = self.aligner.invert_transform(new_shape, changed_pose)

        # SVD on scaled eigenvectors of the model
        u, w, v = np.linalg.svd(self.pdmodel.scaled_eigenvectors, full_matrices=False)
        W = np.zeros_like(w)

        # define weight vector n
        if n is None:
            last_eigenvalue = self.pdmodel.eigenvalues[-1]
            n = last_eigenvalue**2 if last_eigenvalue**2 >= 0 else 0

        # calculate the shape vector
        W = np.diag(w/((w**2) + n))
        c = (v.T).dot(W).dot(u.T).dot(y.vector)

        return changed_pose, c
예제 #3
0
class ActiveShapeModel(object):
    '''
    Algorithm examines a region close to the initial position. For each
    point X_i in this region, find the shape/pose parameters of the
    deformable model that fits the examined region (keeping the shape
    parameter within a 3*sqrt(eigval) bound).
    Repeat until convergence.

    in: PointDistributionModel pdmodel
        list of gray-level models per resolution level
    '''
    def __init__(self, pdmodel, glmodel_pyramid):
        self.pdmodel = pdmodel
        self.glmodel_pyramid = glmodel_pyramid

        # initialise examining/fitting/aligning classes
        self.fitter = Fitter(pdmodel)
        self.examiner = Examiner(glmodel_pyramid)
        self.aligner = Aligner()

    # def __init__(self, pdmodel):
    #     self.pdmodel = pdmodel

    #     # initialise examining/fitting/aligning classes
    #     self.fitter = Fitter(pdmodel)
    #     self.aligner = Aligner()

    def multiresolution_search(self,
                               image,
                               region,
                               t=0,
                               max_level=0,
                               max_iter=5,
                               n=None):
        '''
        Perform Multi-resolution Search ASM algorithm.

        in: np array of training image
            np array region; array of coordinates that gives a rough
                estimation of the target in form (x1, ..., xN, y1, ..., yN)
            int t; amount of pixels to be examined on each side of the
                normal of each point during an iteration (t>k)
            int max_levels; max amount of levels to be searched
            int max_iter; amount to stop iterations at each level
            int n; fitting parameter
        out: Shape region; approximation of the target
        '''
        if not isinstance(region, Shape):

            region = Shape(region)

        # create Gaussian pyramid of input image
        image_pyramid = gaussian_pyramid(image,
                                         levels=len(self.glmodel_pyramid))

        # allow examiner to render the largest image (for testing)
        self.examiner.bigImage = image_pyramid[0]

        level = max_level
        max_level = True

        while level >= 0:
            # get image at level resolution
            image = image_pyramid[level]
            # search in the image
            region = self.search(image,
                                 region,
                                 t=t,
                                 level=level,
                                 max_level=max_level,
                                 max_iter=max_iter,
                                 n=n)
            # descend the pyramid
            level -= 1
            max_level = False

        return region

    def search(self,
               image,
               region,
               t=0,
               level=0,
               max_level=False,
               max_iter=5,
               n=None):
        '''
        Perform the Active Shape Model algorithm in input region.

        in: array image; input image
            array region; array of coordinates that gives a rough estimation
                of the target in form (x1, ..., xN, y1, ..., yN)
            int t; amount of pixels to be examined on each side of the normal
                of each point during an iteration (t>k)
            int level; level in the gaussian pyramid
            int max_iter; amount to stop iterations at each level
            int n; fitting parameter
        out: array points; approximation of the target
        '''

        if max_level:
            # get initial parameters
            pose_para = self.aligner.get_pose_parameters(
                self.pdmodel.mean, region)
            # set initial fitting pose parameters
            self.fitter.start_pose = pose_para
            # align model mean with region
            points = self.aligner.transform(self.pdmodel.mean, pose_para)

        else:
            points = region

        # set examiner image
        self.examiner.set_image(image)

        # perform algorithm
        i = 0
        movement = np.zeros_like(points.length)
        while np.sum(movement) / points.length <= 0.5:
            # examine t pixels on the normals of all points in the model
            # plot.render_shape_to_image(np.uint8(image), points)
            adjustments, movement = self.examiner.examine(points,
                                                          t=t,
                                                          pyramid_level=level)

            # find the best parameters to fit the model to the examined points
            pose_para, c = self.fitter.fit(points,
                                           adjustments,
                                           pyramid_level=level,
                                           n=n)
            # add constraints to the shape parameter
            c = self.constrain(c)
            # transform the model according to the new parameters
            points = self.transform(pose_para, c)

            plt.imshow(image)
            plt.plot(points.x, points.y, 'r.')
            plt.show()

            print('**** LEVEL ---', str(level))
            print('**** ITER ---', str(i))
            print('(constr shape param)', c[:4])
            print('(pose params)', pose_para)

            # keep iteration count
            i += 1
            if i == max_iter:
                break

        return points

    def transform(self, pose_para, b):
        '''
        Transform the model to the image by inserting the most suitable
        pose and shape parameters
        '''
        mode = self.pdmodel.deform(b)
        return self.aligner.transform(mode, pose_para)

    def constrain(self, vector):
        '''
        Add constraints to shape parameter proportional to the eigenvalues
        of the point distribution model. According to Cootes et al., all
        elements of the vector should agree to the following constraint:
          |v_i| < 3*sqrt(eigenval_i)
        '''
        uplimit = 3 * np.sqrt(self.pdmodel.eigenvalues)
        lowlimit = -1 * uplimit
        vector[vector > uplimit] = uplimit[np.where(vector > uplimit)]
        vector[vector < lowlimit] = lowlimit[np.where(vector < lowlimit)]
        return vector
예제 #4
0
            gaussian_pyramid(self.images[i], levels=levels)
            for i in range(self.images.shape[0])
        ])

        # create list of gray-level models
        glmodels = []
        for l in range(levels):
            glmodels.append(
                self.graylevelmodel(multi_res[:, l],
                                    k=k,
                                    reduction_factor=2**l))
            print('---Created gray-level model of level ' + str(l))
        return glmodels


aligner = Aligner()

loader = []
training_set = []
test_set = []
trainlandmarks = []
asm = []
pca = []


def Train():
    global loader, training_set, test_set, trainlandmarks, pca
    # ------------- LOAD DATA -------------- #
    loader = DataLoader()
    training_set, test_set = loader.leave_one_out(test_index=0)
예제 #5
0
def run(imageslice, centroid):
    '''
    Main method of the package.
    '''

    # ------------- LOAD DATA -------------- #
    loader = DataLoader()
    training_set, test_set = loader.leave_one_out(test_index=1)

    # --------------- TRAINING ---------------- #
    trainlandmarks = training_set[1]

    # build and train an Active Shape Model
    asm = ASMTraining(training_set, k=3, levels=3)
    pca = asm.activeshape.pdmodel

    t = 0
    for i in range(len(pca.eigenvalues)):
        if sum(pca.eigenvalues[:i]) / sum(pca.eigenvalues) < 0.99:
            t = t + 1
        else:
            break

    print("Constructed model with {0} modes of variation".format(t))

    # --------------- TESTING ----------------- #
    aligner = Aligner()
    testimage, testlandmarks = test_set
    test = Shape(testlandmarks)
    # remove some noise from the test image
    testimage = remove_noise(testimage)
    plt.imshow(testimage)
    plt.plot(test.x, test.y, 'r.')
    plt.show()

    plt.imshow(imagestest)
    plt.plot(test.x, test.y, "r.")

    pose_para = aligner.get_pose_parameters(pca.mean, test)
    lst = list(pose_para)
    lst[0] = 0
    lst[1] = 0
    lst[2] = pose_para[2]
    lst[3] = 0
    t = tuple(lst)

    points = aligner.transform(pca.mean, t)

    meanShapeCentroid = (np.sum(points.x) / 30, np.sum(points.y) / 30)
    # centroid= tran.set_clicked_center(np.uint8(testimage))
    matches1 = tran.initalizeShape(centroid, meanShapeCentroid,
                                   points.matrix.T)
    if not isinstance(matches1, Shape):
        matches1 = Shape(matches1.T)

    plt.imshow(imagestest)
    plt.plot(matches1.x, matches1.y, '.')
    plt.show()

    new_fit = asm.activeshape.multiresolution_search(imagestest,
                                                     matches1,
                                                     t=10,
                                                     max_level=0,
                                                     max_iter=20,
                                                     n=0.1)
    # Find the target that the new fit represents in order
    # to compute the error. This is done by taking the smallest
    # MSE of all targets.
    mse = mean_squared_error(testlandmarks, new_fit)
    # implement maximally tolerable error
    if int(mse) < MSE_THRESHOLD:
        print('MSE:', mse)
        # plot.render_shape_to_image(np.uint8(testimage), trainlandmarks[best_fit_index], color=(0, 0, 0))
    else:
        print('Bad fit. Needs to restart.')
예제 #6
0
 def __init__(self, pdmodel):
     self.pdmodel = pdmodel
     self.aligner = Aligner()
     self.start_pose = ()