def _drawTootSethOnImage(self, teethSet, img): for i in range(8): start = i * 40 end = start + 40 tooth = Tooth(teethSet.landmarks[start:end]) img = self._drawToothOnImage(tooth, img) return img
def _fitToothAtMultiResolutionLevel(self, toothIndex, downscaledRadiographs): # Current resolution level currentResolutionLevel = self.resolutionLevels - 1 # print("Downscaled radiographs: " + str(downscaledRadiographs.shape)) radiograph = downscaledRadiographs[currentResolutionLevel] # Get initial model rotations initialModelRotation = self.initialRotations[toothIndex] # Get the initial model positions initialModelPosition = self.initialPositions[toothIndex] if initialModelPosition is None: # Automatic model initialization not implemented return None # Get the mean model for the tooth statisticalToothModel = self.completeStatisticalModel.getToothModelByIndex( toothIndex, deepCopy=False) mean = Tooth(statisticalToothModel.getMeanModel()) eigenvectors = statisticalToothModel.getEigenvectors() eigenvalues = statisticalToothModel.getEigenvalues() # Initialize Y, this has to be better Y = deepcopy(mean) Y.rotate(initialModelRotation * (math.pi / 180)) Y.scale(500 / (2**(self.resolutionLevels - 1))) #Y.scale(200) Y.translate(initialModelPosition) # print("Initialized Y: " + str(Y.getLandmarks())) # Init algorithm b = 0 X = mean while currentResolutionLevel >= 0: X, Y = self._fitSingleToothModel( toothIndex, currentResolutionLevel, radiograph, X, Y, b, eigenvalues, eigenvectors, mean, self.filter_settings[currentResolutionLevel]) # print("Upscaling") # print("Changing resolution level") # print("X = " + str(X.getLandmarks())) # print("Y = " + str(Y.getLandmarks())) currentResolutionLevel -= 1 if currentResolutionLevel >= 0: Y.scale(2) radiograph = downscaledRadiographs[currentResolutionLevel] return X, Y
def loadRadiograph(self, radiographID, hasLandmarks=False): self.radiographID = radiographID self.imgPath = './data/Radiographs/%02d.tif' % (self.radiographID + 1) self.image = cv2.cvtColor(cv2.imread(self.imgPath), cv2.COLOR_BGR2GRAY) if hasLandmarks: for i in range(self.nb_teeth): landmark = self.loadLandmark('./data/Landmarks/original/' + 'landmarks%d-%d.txt' % (radiographID + 1, i + 1)) self.teeth.append(Tooth(landmark)) self.teethSet = TeethSet(self.teeth)
def _show_training_result(self): mean_tooth = Tooth(to_landmarks_format(self.pca.mean)) test_tooth = self.data_manager.get_tooth(0, 0, True) test_tooth.align(mean_tooth) tooth_data = test_tooth.landmarks.flatten() projection = self.pca.project(tooth_data) reconstructed_data = self.pca.reconstruct(projection) shapes = [self.pca.mean, tooth_data, reconstructed_data] colors = [[255, 0, 0], [0, 255, 255], [255, 255, 0]] self.scene.clear() for i, shape in enumerate(shapes): tooth = Tooth(to_landmarks_format(shape)) r, g, b = colors[i] tooth.outline_pen = QPen(QColor.fromRgb(r, g, b)) tooth.outline_pen.setWidthF(0.02) tooth.draw(self.scene, True, False, False) self._focus_view() self.compCountLabel.setText(str(len(self.pca.eigen_values)))
def create(data_manager, components_limit=0): ''' Creates statistical model by aligning models and performing PCA :param data_manager: data manager providing training data :param components_limit: Limit how much PCA components should be found (0 == all) :return: resulting PCA ''' teeth = data_manager.get_all_teeth(True) mean_shape = deepcopy(teeth[0]) assert isinstance(mean_shape, Tooth) mean_shape.move_to_origin() mean_shape.normalize_shape() error = float("inf") while error > 0.05: meanAcum = np.zeros(mean_shape.landmarks.shape) for i in range(0, len(teeth)): teeth[i].align(mean_shape) meanAcum += teeth[i].landmarks new_mean_shape = Tooth(meanAcum / len(teeth)) new_mean_shape.align(mean_shape) error = new_mean_shape.sum_of_squared_distances(mean_shape) mean_shape = new_mean_shape # Realign all teeth with final mean shape for i in range(0, len(teeth)): teeth[i].align(mean_shape) data = np.zeros((len(teeth), teeth[0].landmarks.size)) for i, tooth in enumerate(teeth): data[i, :] = tooth.landmarks.flatten() pca = PCA() pca.train(deepcopy(data), components_limit) return pca
def drawToothModelOnFrame(self, parent, radiograph_index, meanModels, model_index, modelLocations, rotations): img = self.dataHandler.getRadiographs( deepCopy=True)[radiograph_index].getImage() img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) for i in range(model_index + 1): model = deepcopy(meanModels[i]) model = Tooth(model) rotation = rotations[i] theta = rotation * (math.pi / 180) model.rotate(theta) model.scale(200) model.translate(modelLocations[i]) img = self._drawToothOnImage(model, img) return RadiographFrame(parent, img),
def make_step(self, phase=None): """ Performs one step of the active shape model search algorithm, which updates landmarks, projects obtained model on the PCA, limits returned eigenvalues and reconstructs the shape again. Current propoerties of this ASM instance are updated accordingly. :param phase: If None, whole algorithm is performed. If 0, only landmarks will be updated. If 1, everything except landmark updates will be perfomed. """ if phase is None or phase == 0: # 1. Sample along normals and find best new position for points by comparing with model resolution_level = self.multi_resolution_framework.get_level(self.current_level) new_tooth = resolution_level.update_tooth_landmarks(self.current_tooth) else: new_tooth = deepcopy(self.current_tooth) if phase is None or phase == 1: # 2. Find new translation, scale, rotation and eigen values translation, scale, rotation = new_tooth.align(self.mean_tooth) b = self.pca.project(new_tooth.landmarks.flatten()) # 3. Limit the eigen values to allowed range max_deviations = self.pca.get_allowed_deviation() for i in range(0, b.shape[0]): b[i] = min(max(b[i], -max_deviations[i]), max_deviations[i]) # 3b. Limit pose values scale = min(max(scale, 5), 80 / (2 ** self.current_level)) # 4. Reconstruct modified shape new_shape = self.pca.reconstruct(b) new_tooth = Tooth(to_landmarks_format(new_shape)) new_tooth.transform(translation, scale, rotation) self.current_params = b self.current_tooth = new_tooth
def createMeanModelFrame(self, parent, meanModel, col, row): height = 360 width = 320 img = np.zeros((height, width, 3), np.uint8) meanTooth = Tooth(deepcopy(meanModel)) meanTooth.scale(height) meanTooth.translate([width / 2, height / 2]) img = self._drawToothOnImage(meanTooth, img) frame = MeanModelFrame(parent, img, row, col) return frame
def step(self, Y, X, eigenvectors, mean): # Fit Y to X Y_new = self.procrustes.allignDataToModel(Y, X) # Project Y into X space and get new b b = self.pca.project(Y_new.getLandmarks().flatten(), eigenvectors, mean.getLandmarks().flatten()) # print("b = " + str(b)) # Generate new model points X X_new = self.pca.reconstruct(b, eigenvectors, mean.getLandmarks().flatten()) X_new = X_new.reshape((X_new.shape[0] // 2, 2)) return Tooth(X_new), b
def _fitSingleToothModel(self, toothIndex, currentResolutionLevel, radiograph, X, Y, b, eigenvalues, eigenvectors, mean, filter_settings): scale = 500 / ((2 * currentResolutionLevel) + 1) Y_copy = deepcopy(Y) i = 0 while i < 100: X, b_new = self._modelFittingStep(Y, X, eigenvalues, eigenvectors, mean, scale) # print("X Step: " + str(X.getLandmarks())) # Calculate new Y from the current X # I might need to first allign model X to Y, as X could still be at the origin and with no scale and rotation temp = self.procrustes.allignModelToData(deepcopy(Y_copy), deepcopy(X))[1] # print("Temp step: " + str(temp.getLandmarks())) Y, p = self._getNewYEstimateAtCurrentResolutionLevel( temp, radiograph, toothIndex, currentResolutionLevel, filter_settings) Y = Tooth(Y) Y_copy = deepcopy(Y) # if ((np.isclose(b, b_new).all() and i>3) or (i>=(12/(currentResolutionLevel+1)) and currentResolutionLevel > 0)): # print("Breaking after " + str(i) + " iterations") # break # else: # b = b_new # i += 1 if (p >= 0.9 and i > 2) or i >= 5: print("Breaking after " + str(i) + " iterations") break else: b = b_new i += 1 return X, Y
def _modelFittingStep(self, Y, X, eigenvalues, eigenvectors, mean, scale): # Fit Y to X Y_new = self.procrustes.allignDataToModel(Y, X) # Project Y into X space and get new b b = self.pca.project(Y_new.getLandmarks().flatten(), eigenvectors, mean.getLandmarks().flatten()) # print("b = " + str(b)) # Enforce constraint |b_i| < 3*lambda_i for i in range(len(b)): if abs(b[i]) > 2 * eigenvalues[i] * scale: b[i] = 2 * eigenvalues[i] * scale # print("eigenvalue: " + str(eigenvalues[i])) # Generate new model points X X_new = self.pca.reconstruct(b, eigenvectors, mean.getLandmarks().flatten()) X_new = X_new.reshape((X_new.shape[0] // 2, 2)) return Tooth(X_new), b
def fitModel(self, target_tooth, model): self.procrustes = Procrustes() self.pca = PCA() eigenvectors = model.getEigenvectors() Y = target_tooth mean = Tooth(model.getMeanModel()) # Init b = 0 X = mean i = 0 while i < 20: i += 1 X, b_new = self.step(Y, X, eigenvectors, mean) if np.allclose(b, b_new): break else: b = b_new return X
def createMeanModelPresentationImages(self, statisticalModel): toothModels = statisticalModel.getAllToothModels(deepCopy=True) pca = PCA() for i in range(8): height = 3840 width = 2160 img = np.zeros((height, width, 3), np.uint8) meanModel = toothModels[i].getMeanModel(deepCopy=True) flatModel = meanModel.flatten() eigenvalues = toothModels[i].getEigenvalues(deepCopy=True) eigenvectors = toothModels[i].getEigenvectors(deepCopy=True) meanTooth = Tooth(deepcopy(meanModel)) meanTooth.scale(height) meanTooth.translate([width / 2, height / 2]) for j in range(len(eigenvalues)): img_2 = deepcopy(img) maxChangeVector = np.zeros(np.array(eigenvalues).shape) maxChangeVector[j] = 100 * eigenvalues[j] * (5 * j + 1) maxChange = pca.reconstruct(maxChangeVector, eigenvectors, deepcopy(flatModel)) maxChange = maxChange.reshape((maxChange.shape[0] // 2, 2)) maxChangeTooth = Tooth(maxChange) maxChangeTooth.scale(height) maxChangeTooth.translate([width / 2, height / 2]) minChangeVector = np.zeros(np.array(eigenvalues).shape) minChangeVector[j] = -100 * (eigenvalues[j]) * (5 * j + 1) minChange = pca.reconstruct(minChangeVector, eigenvectors, deepcopy(flatModel)) minChange = minChange.reshape((minChange.shape[0] // 2, 2)) minChangeTooth = Tooth(minChange) minChangeTooth.scale(height) minChangeTooth.translate([width / 2, height / 2]) # img_2 = self._drawToothContourOnImage(meanTooth, img_2, lineColor=(255,255,255)) img_2 = self._drawToothContourOnImage(maxChangeTooth, img_2, lineColor=(255, 255, 255)) img_2 = self._drawToothContourOnImage(minChangeTooth, img_2, lineColor=(255, 255, 255)) height = img_2.shape[0] width = img_2.shape[1] img_2 = cv2.resize(img_2, (int(width * 0.1), int(height * 0.1)), interpolation=cv2.INTER_AREA) # img_2 = Filter.process_image(img_2) filename = "Results/mean_model_modes_adjusted/tooth_{0}_mode_{1}.jpg".format( i, j) cv2.imwrite(filename, img_2) cv2.imshow("Mean Model", img_2)