| from . import * | |
| from abcli import file | |
| from abcli import string | |
| import cv2 | |
| import numpy as np | |
| import os.path | |
| import abcli.logging | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| def eval(input_path, output_path): | |
| from sklearn.metrics import accuracy_score | |
| report = {"accuracy": None} | |
| success, ground_truth = file.load(f"{input_path}/test_labels.pyndarray") | |
| if success: | |
| logger.info( | |
| "groundtruth: {} - {}".format( | |
| string.pretty_shape_of_matrix(ground_truth), | |
| ",".join([str(value) for value in ground_truth[:10]] + ["..."]), | |
| ) | |
| ) | |
| success, predictions = file.load( | |
| f"{input_path}/image_classifier/predictions.pyndarray" | |
| ) | |
| if success: | |
| predictions = np.argmax(predictions, axis=1).astype(np.uint8) | |
| logger.info( | |
| "predictions: {} - {}".format( | |
| string.pretty_shape_of_matrix(predictions), | |
| ",".join([str(value) for value in predictions[:10]] + ["..."]), | |
| ) | |
| ) | |
| report["accuracy"] = accuracy_score(predictions, ground_truth) | |
| logger.info( | |
| "image_classifier.eval({}->{}): {:.2f}%".format( | |
| input_path, output_path, 100 * report["accuracy"] | |
| ) | |
| ) | |
| return file.save_json(os.path.join(output_path, "evaluation_report.json"), report) | |
| def preprocess( | |
| output_path, | |
| objects="", | |
| infer_annotation=True, | |
| purpose="predict", | |
| test_size=1.0 / 6, | |
| window_size=28, | |
| ): | |
| if objects: | |
| logger.info( | |
| "image_classifier.preprocess({}{})->{} - {}x{} - for {}".format( | |
| ",".join(objects), | |
| " + annotation" if infer_annotation else "", | |
| output_path, | |
| window_size, | |
| window_size, | |
| purpose, | |
| ) | |
| ) | |
| annotations = [] | |
| list_of_images = [] | |
| for index, object in enumerate(objects): | |
| list_of_images_ = [ | |
| "{}/Data/{}/camera.jpg".format(object, frame) | |
| for frame in objects.list_of_frames(object) | |
| ] | |
| annotations += len(list_of_images_) * [index] | |
| list_of_images += list_of_images_ | |
| annotations = np.array(annotations) if infer_annotation else [] | |
| else: | |
| logger.info( | |
| "image_classifier.preprocess({}) - {}x{} - for {}".format( | |
| output_path, | |
| window_size, | |
| window_size, | |
| purpose, | |
| ) | |
| ) | |
| list_of_images = [ | |
| "{}/Data/{}/camera.jpg".format(output_path, frame) | |
| for frame in objects.list_of_frames(output_path) | |
| ] | |
| annotations = np.array( | |
| file.load_json( | |
| f"{output_path}/annotations.json".format(), | |
| civilized=True, | |
| default=None, | |
| )[1] | |
| ).astype(np.uint8) | |
| if len(annotations) and len(list_of_images) != len(annotations): | |
| logger.error( | |
| f"-{name}: preprocess: mismatch between frame and annotation counts: {len(list_of_images):,g} != {len(annotations):,g}" | |
| ) | |
| return False | |
| logger.info("{:,} frame(s)".format(len(list_of_images))) | |
| tensor = np.zeros( | |
| (len(list_of_images), window_size, window_size, 3), | |
| dtype=np.uint8, | |
| ) | |
| error_count = 0 | |
| for index, filename in enumerate(list_of_images): | |
| logger.info("+= {}".format(filename)) | |
| success_, image = file.load_image(filename) | |
| if success_: | |
| try: | |
| tensor[index, :, :, :] = cv2.resize(image, (window_size, window_size)) | |
| except: | |
| from abcli.logging import crash_report | |
| crash_report("image_classifier.preprocess() failed") | |
| success_ = False | |
| if not success_: | |
| error_count += 1 | |
| logger.info( | |
| "tensor: {}{}".format( | |
| string.pretty_shape_of_matrix(tensor), | |
| " {} error(s)".format(error_count) if error_count else "", | |
| ) | |
| ) | |
| success = False | |
| if purpose == "predict": | |
| if not file.save("{}/test_images.pyndarray".format(output_path), tensor): | |
| return False | |
| if len(annotations): | |
| if not file.save( | |
| "{}/test_labels.pyndarray".format(output_path), annotations | |
| ): | |
| return False | |
| success = True | |
| elif purpose == "train": | |
| if not len(annotations): | |
| logger.error(f"-{name}: preprocess: annotations are not provided.") | |
| return False | |
| from sklearn.model_selection import train_test_split | |
| ( | |
| tensor_train, | |
| tensor_test, | |
| annotations_train, | |
| annotations_test, | |
| ) = train_test_split(tensor, annotations, test_size=test_size) | |
| logger.info( | |
| "test-train split: {:.0f}%-{:.0f}% ".format( | |
| len(annotations_test) / len(annotations) * 100, | |
| len(annotations_train) / len(annotations) * 100, | |
| ) | |
| ) | |
| logger.info( | |
| "tensor_train: {}".format(string.pretty_shape_of_matrix(tensor_train)) | |
| ) | |
| logger.info( | |
| "tensor_test: {}".format(string.pretty_shape_of_matrix(tensor_test)) | |
| ) | |
| logger.info( | |
| "annotations_train: {}".format( | |
| string.pretty_shape_of_matrix(annotations_train) | |
| ) | |
| ) | |
| logger.info( | |
| "annotations_test: {}".format( | |
| string.pretty_shape_of_matrix(annotations_test) | |
| ) | |
| ) | |
| success = ( | |
| file.save("{}/train_images.pyndarray".format(output_path), tensor_train) | |
| and file.save("{}/test_images.pyndarray".format(output_path), tensor_test) | |
| and file.save( | |
| "{}/train_labels.pyndarray".format(output_path), annotations_train | |
| ) | |
| and file.save( | |
| "{}/test_labels.pyndarray".format(output_path), annotations_test | |
| ) | |
| ) | |
| else: | |
| logger.error(f"-{name}: preprocess: {purpose}: purpose not found.") | |
| return success | |