コード例 #1
0
def save_thick_fibers(read_path, save_path, thickness, write_images=True):
    """
    Takes the images in the read path together with the ground truth labels. Produces and saves
    new images with thicker ground truth label saved in the save path.
    :param read_path: The path were the original ground truths are
    :param save_path: The path were the new thicker ground truths will be saved
    :param thickness: The thickness for the new ground truth images
    :param load_type: The type of the original images saved
    :param write_images: This flag determines if the original images will be also copied into the path (the input data)
    :return: None
    """

    # Get the image names in the read path
    names = name_list(read_path)
    if not (exists(save_path)):
        makedirs(
            save_path)  # Creates the folder if the save path doesn't exist

    # For each of the images produce a new image with the thicker ground truth
    for name in names:
        print('Converting image %s...\n' % name)
        _, label = load_image_label(read_path, name)
        thick_label = create_thick_fibers(label, thickness)
        cv2.imwrite(
            join(
                save_path,
                name.replace(get_file_extension(name),
                             '_FIB' + get_file_extension(name))), thick_label)
        if write_images:
            copyfile(join(read_path, name), join(save_path, name))
コード例 #2
0
    def convolutional_selection(self,save_path, size, img, label, name):
        # Obtain the left top corner for the hard example window
        chip_names = []
        # Convolve the label to find the relevant spots
        __, label = cv2.threshold(label, 127, 255, cv2.THRESH_BINARY_INV)
        convolved1 = convolve2d(label[:,:,0], self.gaussian_kernel((np.min(self.size))), mode='valid')
        convolved2 = convolve2d(label[:,:,1], self.gaussian_kernel((np.min(self.size))), mode='valid')
        __, label = cv2.threshold(label, 127, 255, cv2.THRESH_BINARY_INV)
        while np.sum(convolved1) != 0:
            index1, index2 = np.unravel_index(convolved1.argmax(), convolved1.shape)
            chip_image = img[index1:(index1 + size[0]),
                         index2:(index2 + size[1])]  # Get the hard example window
            chip_label = label[index1:(index1 + size[0]),
                         index2:(index2 + size[1]),0]  # Get the hard example label window
            chip_label2 = label[index1:(index1 + size[0]),
                         index2:(index2 + size[1]),1]  # Get the hard example label window
            # Remove a certain search area for the convolution
            index1_rmv_conv_start = max([index1 - int(size[0] / 4) + 1, 0])
            index2_rmv_conv_start = max([index2 - int(size[1] / 4) + 1, 0])
            index1_rmv_conv_end = min([index1_rmv_conv_start + (size[0] - 2), img.shape[0]])
            index2_rmv_conv_end = min([index2_rmv_conv_start + (size[1] - 2), img.shape[1]])
            convolved1[index1_rmv_conv_start:index1_rmv_conv_end, index2_rmv_conv_start:index2_rmv_conv_end] = 0
            convolved2[index1_rmv_conv_start:index1_rmv_conv_end, index2_rmv_conv_start:index2_rmv_conv_end] = 0
            save_name = name.replace(get_file_extension(name),
                                     '_H_' + str(index1) + '_' + str(index2) + get_file_extension(name))
            cv2.imwrite(join(save_path, save_name), chip_image)
            cv2.imwrite(join(save_path,
                             save_name.replace(get_file_extension(save_name), '_FIB' + get_file_extension(save_name))),
                        chip_label)
            cv2.imwrite(join(save_path,
                             save_name.replace(get_file_extension(save_name), '_FIB2' + get_file_extension(save_name))),
                        chip_label2)

        # while np.sum(convolved2) != 0:
        #     index1, index2 = np.unravel_index(convolved2.argmax(), convolved2.shape)
        #     chip_image = img[index1:(index1 + size[0]),
        #                  index2:(index2 + size[1])]  # Get the hard example window
        #     chip_label = label[index1:(index1 + size[0]),
        #                  index2:(index2 + size[1]),0]  # Get the hard example label window
        #     chip_label2 = label[index1:(index1 + size[0]),
        #                  index2:(index2 + size[1]),1]  # Get the hard example label window
        #     # Remove a certain search area for the convolution
        #     index1_rmv_conv_start = max([index1 - int(size[0] / 4) + 1, 0])
        #     index2_rmv_conv_start = max([index2 - int(size[1] / 4) + 1, 0])
        #     index1_rmv_conv_end = min([index1_rmv_conv_start + (size[0] - 2), img.shape[0]])
        #     index2_rmv_conv_end = min([index2_rmv_conv_start + (size[1] - 2), img.shape[1]])
        #     convolved1[index1_rmv_conv_start:index1_rmv_conv_end, index2_rmv_conv_start:index2_rmv_conv_end] = 0
        #     convolved2[index1_rmv_conv_start:index1_rmv_conv_end, index2_rmv_conv_start:index2_rmv_conv_end] = 0
        #     save_name = name.replace(get_file_extension(name),
        #                              '_H_' + str(index1) + '_' + str(index2) + get_file_extension(name))
        #     cv2.imwrite(join(save_path, save_name), chip_image)
        #     cv2.imwrite(join(save_path,
        #                      save_name.replace(get_file_extension(save_name), '_FIB' + get_file_extension(save_name))),
        #                 chip_label)
        #     cv2.imwrite(join(save_path,
        #                      save_name.replace(get_file_extension(save_name), '_FIB2' + get_file_extension(save_name))),
        #                 chip_label2)

        return chip_names
コード例 #3
0
 def produce_prediction_files(self, name, model, threshold,
                              threshold_folder):
     """
     This function takes an image with certain name and makes a prediction with the specified model. The prediction
     is then thresholded to obtain a boolean mask which is used to produce prediction files which are then stored in
     the threshold folder
     :param name: Name of the input image
     :param model: Model used to produce the prediction
     :param threshold: Threshold to produce the boolean mask from the prediction
     :param threshold_folder: Where the prediction files will be stored
     :return: Saves the predictions in the corresponding folder. The predictions are:
     _FIB: The original ground truth file
     _PROB: The raw prediction obtained from the model each pixel represents the probability of predicting a fiber
     _PRED: The boolean mask prediction
     _MASKED: The original image with a mask that represents TP,FP,FN
     _STAT_MASK: The mask with the TP,FP,FN
     """
     img, label = load_image_label(self.path_data, name)
     sizex = img.shape[0]
     sizey = img.shape[1]
     colored_image = np.concatenate((img.reshape(sizex, sizey, 1), ) * 3,
                                    axis=2)
     # Reshape the image so it can be fed to the model
     img = img.reshape(1, sizex, sizey, 1)
     # Make the prediction and reshape it
     prediction = model.predict(img).reshape(sizex, sizey)
     prediction_bool = (prediction >= threshold)
     prediction = prediction * 255
     __, __, __, colored_mask = prediction_masks(prediction_bool, label)
     # Write the created images in the corresponding folder
     cv2.imwrite(
         threshold_folder + '/' +
         name.replace(get_file_extension(name), '_FIB' + '.tiff'), label)
     cv2.imwrite(
         threshold_folder + '/' +
         name.replace(get_file_extension(name), '_PROB' + '.tiff'),
         prediction.astype(np.uint8))
     cv2.imwrite(
         threshold_folder + '/' +
         name.replace(get_file_extension(name), '_PRED' + '.tiff'),
         prediction_bool * 255)
     cv2.imwrite(
         threshold_folder + '/' +
         name.replace(get_file_extension(name), '_MASKED' + '.tiff'),
         np.multiply(colored_mask, colored_image))
     cv2.imwrite(
         threshold_folder + '/' +
         name.replace(get_file_extension(name), '_STATMASK' + '.tiff'),
         colored_mask * 255)
コード例 #4
0
 def separate_hard_example_name(self, name):
     extension = get_file_extension(name)
     root_name = name.split('_H_')[0]
     indexes = name.split('_H_')[-1].split('.')[0]
     index1 = int(indexes.split('_')[0])
     index2 = int(indexes.split('_')[1])
     return root_name, index1, index2, extension
コード例 #5
0
            def summary_image(self, threshold_folder):
                """
                Produces an image with the summary of the data obtained previously
                :param threshold_folder: Where the image is going to be stored
                :return: Saves in the threshold_folder an image with the corresponding produced table
                """
                print("Saving the image summary table")

                try:
                    object_precision = self.found_fibers / (
                        self.found_fibers + self.false_positive_objects)
                except ZeroDivisionError:
                    object_precision = None
                try:
                    object_recall = self.found_fibers / (self.total_fibers)
                except ZeroDivisionError:
                    object_recall = None

                filename_fiber_detailed = self.name.replace(
                    get_file_extension(self.name), '') + '_FD.txt'
                ffd = open(join(threshold_folder, filename_fiber_detailed),
                           'w+')
                for fiber in range(len(self.image_percentages)):
                    ffd.write(
                        'Fiber {} Predicted_Pixels {} GTPixels {} Percentage {} \n'
                        .format(fiber + 1,
                                self.image_intersection_pixels[fiber],
                                self.image_fiber_pixels[fiber],
                                self.image_percentages[fiber]))
                ffd.close()

                filename_image_summary = self.name.replace(
                    get_file_extension(self.name), '') + '_FIS.txt'
                fis = open(join(threshold_folder, filename_image_summary),
                           'w+')

                fis.write(
                    'Total_fibers {} Found_fibers {} False_Positive_Objects {} \n'
                    .format(self.total_fibers, self.found_fibers,
                            self.false_positive_objects))
                fis.write(
                    'Object_precision {} Object_recall {} Pixel_precision {} Pixel_recall {} \n'
                    .format(object_precision, object_recall, self.precision,
                            self.recall))
                fis.close()

                return self.precision, self.recall, self.found_fibers, self.total_fibers, self.image_percentages, self.false_positive_objects
コード例 #6
0
    def convolutional_selection(self, comparison, img, label, name,
                                HE_per_image):
        # Obtain the left top corner for the hard example window
        hard_example_names = []
        convolved = convolve2d(comparison,
                               np.ones((self.data.size[1], self.data.size[0])),
                               mode='valid')
        for num_example in range(HE_per_image):
            index1, index2 = np.unravel_index(convolved.argmax(),
                                              convolved.shape)
            hard_example = img[index1:(index1 + self.data.size[1]), index2:(
                index2 + self.data.size[0])]  # Get the hard example window
            hard_example_label = label[index1:(
                index1 + self.data.size[1]), index2:(
                    index2 +
                    self.data.size[0])]  # Get the hard example label window

            # Remove a certain search area for the convolution
            index1_rmv_conv_start = max(
                [index1 - int(self.data.size[1] / 4) + 1, 0])
            index2_rmv_conv_start = max(
                [index2 - int(self.data.size[0] / 4) + 1, 0])
            index1_rmv_conv_end = min([
                index1_rmv_conv_start + (self.data.size[1] - 2), img.shape[0]
            ])
            index2_rmv_conv_end = min([
                index2_rmv_conv_start + (self.data.size[0] - 2), img.shape[1]
            ])
            convolved[index1_rmv_conv_start:index1_rmv_conv_end,
                      index2_rmv_conv_start:index2_rmv_conv_end] = 0

            save_name = name.replace(
                get_file_extension(name), '_HEP_' + str(index1) + '_' +
                str(index2) + self.UNETnet.data_type)
            hard_example_names.append(save_name)
            cv2.imwrite(join(self.data.temp_train, save_name), hard_example)
            cv2.imwrite(
                join(
                    self.data.temp_train,
                    save_name.replace(get_file_extension(save_name),
                                      '_FIB' + get_file_extension(save_name))),
                hard_example_label)
            self.UNETnet.train_names.append(save_name)
            print("HE %d created \n" % num_example)
        return hard_example_names
コード例 #7
0
 def __init__(self, path_hard_example_files, path_image_files):
     self.path_hard_example_files = path_hard_example_files
     self.hard_example_texts = name_list(path_hard_example_files,
                                         extension='.txt')
     self.path_image_files = path_image_files
     self.image_names = name_list(path_image_files)
     self.image_extension = get_file_extension(self.image_names[-1])
     self.sizes = self.size_hard_example()
     print("Existing hard example files are\n")
     print(self.hard_example_texts)
コード例 #8
0
 def hard_example_generator_convolution(self, HE_per_image=2):
     '''
     This function reads the images in the read path and produces a prediction with the input model.
     The region of certain size with the most FP errors is identified.
     The crops are evaluated with the model and then HEpi crops with the worst score are then saved into the save_path
     '''
     print("Hard example generation started...\n")
     # Read the image names in the read_path
     names = self.data.train_names_original
     hard_examples = []
     for num_name, name in enumerate(names):
         print("Generating HE for image %d\n" % num_name)
         # Load the image with the corresponding labels
         print(self.data.path_name, name)
         img = cv2.imread(join(self.data.path_name, name))
         label = cv2.imread(
             join(
                 self.data.path_name,
                 name.replace(get_file_extension(name),
                              '_FIB' + get_file_extension(name))), 0)
         img = pad_image(self.num_layers, img)
         label = pad_image(self.num_layers, label)
         #img, label = load_image_label(self.data.path_name, name)
         label_thresh = (label == 255).astype(np.int)
         # Create the predictions from the original image
         prediction = self.UNETnet.model.predict(img[np.newaxis, :, :])
         # Compare the prediction with the ground truth
         print('Shape prediction', prediction.shape, 'Label',
               label_thresh.shape)
         comparison = np.multiply((1 - prediction[0, :, :, 0]),
                                  label_thresh)
         print('Comparison', comparison.shape)
         # Make the convolution to find the left top corner for the hard example
         hard_example_names = self.convolutional_selection(
             comparison, img, label, name, HE_per_image)
         for name_hard in hard_example_names:
             hard_examples.append(name_hard)
     if not (exists('./' + self.data.data_name + '/Hard Examples')):
         makedirs('./' + self.data.data_name + '/Hard Examples')
     save_names(hard_examples,
                './' + self.data.data_name + '/Hard Examples/',
                self.UNETnet.model_name + " Iter " + str(self.iteration))
コード例 #9
0
 def save_images(self,name,image,threshold_folder,label,prediction_probability_mask,prediction_processed,colored_mask,colored_image,contours_prediction_processed):
     """
     Saves the predictions in the corresponding folder. The predictions are:
     _FIB: The original ground truth file
     _PROB: The raw prediction obtained from the model each pixel represents the probability of predicting a fiber
     _PRED: The boolean mask prediction
     _MASKED: The original image with a mask that represents TP,FP,FN
     _STAT_MASK: The mask with the TP,FP,FN
     _OBJNUM: Numbered objects in the prediction
     :param name: Name of the image
     :param threshold_folder: Folder where it will be stored
     :param label: Label image
     :param prediction_probability_mask: Output of the model prediction to create an image with it
     :param prediction_processed: Prediction after removing small isolated pixels
     :param colored_mask: Colored mask with TP,FP,FN
     :param colored_image: Image for use together with colored mask
     :param contours_prediction_processed: Contours of the prediction after removing small isolated pixels
     :return:
     """
     colored_image = np.concatenate((image.reshape(self.size, self.size, 1),) * 3, axis=2)
     cv2.imwrite(threshold_folder + '/' + name.replace(get_file_extension(name), '_FIB' + '.tiff'), label)
     cv2.imwrite(threshold_folder + '/' + name.replace(get_file_extension(name), '_PROB' + '.tiff'),
                 prediction_probability_mask.astype(np.uint8))
     cv2.imwrite(threshold_folder + '/' + name.replace(get_file_extension(name), '_PRED' + '.tiff'),
                 prediction_processed)
     cv2.imwrite(threshold_folder + '/' + name.replace(get_file_extension(name), '_MASKED' + '.tiff'),
                 np.multiply(colored_mask, colored_image))
     cv2.imwrite(threshold_folder + '/' + name.replace(get_file_extension(name), '_STATMASK' + '.tiff'),
                 colored_mask * 255)
     cv2.imwrite(threshold_folder + '/' + name.replace(get_file_extension(name), '_OBJNUM' + '.tiff'),
                 self.numbered_fibers(np.multiply(colored_mask, colored_image), contours_prediction_processed))
コード例 #10
0
 def save_images(self, threshold_folder):
     """
     Saves the predictions in the corresponding folder. The predictions are:
     _FIB: The original ground truth file
     _PROB: The raw prediction obtained from the model each pixel represents the probability of predicting a fiber
     _PRED: The boolean mask prediction
     _MASKED: The original image with a mask that represents TP,FP,FN
     _STAT_MASK: The mask with the TP,FP,FN
     _OBJNUM: Numbered objects in the prediction
     :param threshold_folder: Folder where it will be stored
     :return:
     """
     print("Saving the prediction images \n")
     colored_image = np.concatenate(
         (self.image.reshape(self.size, self.size, 1), ) * 3,
         axis=2)
     cv2.imwrite(
         threshold_folder + '/' + self.name.replace(
             get_file_extension(self.name), '_FIB' + '.tiff'),
         self.label)
     cv2.imwrite(
         threshold_folder + '/' + self.name.replace(
             get_file_extension(self.name), '_PROB' + '.tiff'),
         self.prediction_prob_mask.astype(np.uint8))
     cv2.imwrite(
         threshold_folder + '/' + self.name.replace(
             get_file_extension(self.name), '_PRED' + '.tiff'),
         self.prediction)
     cv2.imwrite(
         threshold_folder + '/' + self.name.replace(
             get_file_extension(self.name), '_PRED_UN' + '.tiff'),
         self.prediction_unprocessed)
     cv2.imwrite(
         threshold_folder + '/' + self.name.replace(
             get_file_extension(self.name), '_MASKED' + '.tiff'),
         np.multiply(self.colored_mask, colored_image))
     cv2.imwrite(
         threshold_folder + '/' + self.name.replace(
             get_file_extension(self.name), '_STATMASK' + '.tiff'),
         self.colored_mask * 255)
     cv2.imwrite(
         threshold_folder + '/' + self.name.replace(
             get_file_extension(self.name), '_OBJNUM' + '.tiff'),
         self.numbered_fibers(
             np.multiply(self.colored_mask, colored_image),
             self.prediction_contours))
コード例 #11
0
 def get_chip_images(self, size):
     name_array = [
         self.train_names_original, self.val_names_original,
         self.test_names_original
     ]
     folder_array = [self.temp_train, self.temp_val, self.temp_test]
     # Train data creation
     names = name_array[0]
     if not (exists(folder_array[0])):
         makedirs(folder_array[0])
         for name in names:
             image = cv2.imread(join(self.path_name, name))
             label = cv2.imread(
                 join(
                     self.path_name,
                     name.replace(get_file_extension(name),
                                  '_FIB' + get_file_extension(name))), 0)
             self.convolutional_selection(folder_array[0], size, image,
                                          label, name)
     if self.augmentation:
         generate_complete_flipping(folder_array[0],
                                    folder_array[0],
                                    data_type=self.load_extension,
                                    y_flip=False,
                                    xy_flip=False)
     # Validation Test Data
     for num_folder in range(2):
         folder = folder_array[num_folder + 1]
         names = name_array[num_folder + 1]
         if not (exists(folder)):
             makedirs(folder)
         for name in names:
             image = cv2.imread(join(self.path_name, name))
             label = cv2.imread(
                 join(
                     self.path_name,
                     name.replace(get_file_extension(name),
                                  '_FIB' + get_file_extension(name))), 0)
             image = pad_image(image)
             label = pad_image(label)
             cv2.imwrite(join(folder, name), image)
             cv2.imwrite(
                 join(
                     folder,
                     name.replace(get_file_extension(name),
                                  '_FIB' + get_file_extension(name))),
                 label)
コード例 #12
0
    def get_information_image(self, percentage):
        final_precision = 0
        final_recall = 0
        final_total_list = []
        final_found_list = []
        final_total_fibers = 0
        final_total_found = 0
        for num_image, name in enumerate(self.names):
            texname = name.replace(get_file_extension(name), '.tex')
            pdfname = name.replace(get_file_extension(name), '.pdf')
            tablename = join(self.path,
                             name.replace(get_file_extension(name), '.png'))
            image_percentages, total_fibers_image, found_fibers_image, image_fiber_pixels, image_intersection_pixels = self.fiber_discriminator_per_image(
                self.images_contours, num_image, percentage)
            final_total_fibers += total_fibers_image
            final_total_found += found_fibers_image
            final_total_list.append(total_fibers_image)
            final_found_list.append(found_fibers_image)
            precision, recall = self.get_statistics(
                self.statistics_names[num_image])
            dict_information = {
                'Fiber': range(1,
                               len(image_percentages) + 1),
                'Percentage %': image_percentages,
                'GT Pixels': image_fiber_pixels,
                'Predicted Pixels': image_intersection_pixels
            }
            dict_information2 = {
                'Total Fibers': [total_fibers_image],
                'Found Fibers': [found_fibers_image]
            }
            dict_information3 = {'Precision': [precision], 'Recall': [recall]}
            information1 = pd.DataFrame(dict_information,
                                        columns=[
                                            'Fiber', 'Predicted Pixels',
                                            'GT Pixels', 'Percentage %'
                                        ])
            information1.set_index('Fiber', inplace=True)
            information2 = pd.DataFrame(
                dict_information2, columns=['Found Fibers', 'Total Fibers'])
            #information2.set_index('Found Fibers', inplace=True)
            information3 = pd.DataFrame(dict_information3,
                                        columns=['Precision', 'Recall'])
            #information3.set_index('Precision', inplace=True)
            template = r'''\documentclass[preview]{{standalone}}
            \usepackage{{booktabs}}
            \begin{{document}}
            {}
            {}
            {}
            \end{{document}}
            '''
            with open(texname, 'w') as f:
                f.write(
                    template.format(
                        information1.to_latex(column_format='|c|c|c|c|'),
                        information2.to_latex(column_format='|c|c|c|'),
                        information3.to_latex()))
            subprocess.call(['pdflatex', texname])
            subprocess.call([
                'magick', 'convert', '-density', '300', pdfname, '-quality',
                '90', tablename
            ])
            f.close()
            remove(texname)
            remove(pdfname)
            remove(texname.replace('.tex', '.log'))
            final_precision += precision
            final_recall += recall
        dict_information_final1 = {
            'Image': self.names,
            'Found Fibers': final_found_list,
            'Total Fibers': final_total_list
        }
        information_final1 = pd.DataFrame(
            dict_information_final1,
            columns=['Image', 'Found Fibers', 'Total Fibers'])
        information_final1.set_index('Image', inplace=True)

        final_precision = final_precision / len(self.names)
        final_recall = final_recall / len(self.names)
        dict_information_final2 = {
            'Summary': [],
            'Overall Precision': [final_precision],
            'Overall Recall': [final_recall],
            'Total fibers found': [final_total_found],
            'Total fibers': [final_total_fibers]
        }
        information_final2 = pd.DataFrame(dict_information_final2,
                                          columns=[
                                              'Summary', 'Overall Precision',
                                              'Overall Recall',
                                              'Total fibers found',
                                              'Total fibers'
                                          ])
        information_final2.set_index('Summary', inplace=True)
        template2 = r'''\documentclass[preview]{{standalone}}
                    \usepackage{{booktabs}}
                    \begin{{document}}
                    {}
                    {}
                    \end{{document}}
                    '''
        texname = "Final_summary.tex"
        pdfname = "Final_summary.pdf"
        tablename = join(self.path, "Final_summary.png")
        with open(texname, 'w') as f:
            f.write(
                template2.format(
                    information_final1.to_latex(column_format='|c|c|c|c|'),
                    information_final2.to_latex(column_format='|c|c|c|c|c|')))
        subprocess.call(['pdflatex', texname])
        subprocess.call([
            'magick', 'convert', '-density', '300', pdfname, '-quality', '90',
            tablename
        ])
        f.close()
        remove(texname)
        remove(pdfname)
        remove(texname.replace('.tex', '.log'))
コード例 #13
0
            def summary_image(self, threshold_folder):
                """
                Produces an image with the summary of the data obtained previously
                :param threshold_folder: Where the image is going to be stored
                :return: Saves in the threshold_folder an image with the corresponding produced table
                """
                print("Saving the image summary table")
                # Define the summary file names
                texname = self.name.replace(get_file_extension(self.name),
                                            '.tex')
                pdfname = self.name.replace(get_file_extension(self.name),
                                            '.pdf')
                tablename = join(
                    threshold_folder,
                    self.name.replace(get_file_extension(self.name), '.png'))

                # Create the dictionaries for the data frames
                dict_fiber_summary = {
                    'Fiber': range(1,
                                   len(self.image_percentages) + 1),
                    'Percentage %': self.image_percentages,
                    'GT Pixels': self.image_fiber_pixels,
                    'Predicted Pixels': self.image_intersection_pixels
                }
                dict_image_summary = {
                    'Total Fibers': [self.total_fibers],
                    'Found Fibers': [self.found_fibers],
                    'False Positive Objects': [self.false_positive_objects]
                }
                try:
                    object_precision = self.found_fibers / (
                        self.found_fibers + self.false_positive_objects)
                except ZeroDivisionError:
                    object_precision = None
                try:
                    object_recall = self.found_fibers / (self.total_fibers)
                except ZeroDivisionError:
                    object_recall = None

                dict_object_summary = {
                    'Object Precision': [object_precision],
                    'Object Recall': [object_recall]
                }
                dict_pixel_summary = {
                    'Pixel Precision': [self.precision],
                    'Pixel Recall': [self.recall]
                }
                df_fiber_summary = pd.DataFrame(dict_fiber_summary,
                                                columns=[
                                                    'Fiber',
                                                    'Predicted Pixels',
                                                    'GT Pixels', 'Percentage %'
                                                ])
                df_fiber_summary.set_index('Fiber', inplace=True)
                df_image_summary = pd.DataFrame(dict_image_summary,
                                                columns=[
                                                    'Found Fibers',
                                                    'Total Fibers',
                                                    'False Positive Objects'
                                                ])
                df_object_summary = pd.DataFrame(
                    dict_object_summary,
                    columns=['Object Precision', 'Object Recall'])
                df_pixel_summary = pd.DataFrame(
                    dict_pixel_summary,
                    columns=['Pixel Precision', 'Pixel Recall'])

                template = r'''\documentclass[preview]{{standalone}}
                \usepackage{{booktabs}}
                \begin{{document}}
                {}
                {}
                {}
                {}
                \end{{document}}
                '''
                with open(texname, 'w') as f:
                    f.write(
                        template.format(
                            df_fiber_summary.to_latex(
                                column_format='|c|c|c|c|'),
                            df_image_summary.to_latex(
                                column_format='|c|c|c|c|'),
                            df_object_summary.to_latex(
                                column_format='|c|c|c|'),
                            df_pixel_summary.to_latex(
                                column_format='|c|c|c|')))
                subprocess.call(['pdflatex', texname])
                subprocess.call([
                    'magick', 'convert', '-density', '300', pdfname,
                    '-quality', '90', tablename
                ])
                f.close()
                remove(texname)
                remove(pdfname)
                remove(texname.replace('.tex', '.aux'))
                remove(texname.replace('.tex', '.log'))
                return self.precision, self.recall, self.found_fibers, self.total_fibers, self.image_percentages, self.false_positive_objects