Example #1
0
def main(argv):
    # 0. Initialize Cytomine client and job
    with CytomineJob.from_cli(argv) as cj:
        cj.job.update(status=Job.RUNNING,
                      progress=0,
                      statusComment="Initialisation...")

        # 1. Create working directories on the machine:
        # - WORKING_PATH/in: input images
        # - WORKING_PATH/out: output images
        # - WORKING_PATH/ground_truth: ground truth images
        base_path = "{}".format(os.getenv("HOME"))
        gt_suffix = "_lbl"
        working_path = os.path.join(base_path, str(cj.job.id))
        in_path = os.path.join(working_path, "in")
        out_path = os.path.join(working_path, "out")
        gt_path = os.path.join(working_path, "ground_truth")

        if not os.path.exists(working_path):
            os.makedirs(working_path)
            os.makedirs(in_path)
            os.makedirs(out_path)
            os.makedirs(gt_path)

        # 2. Download the images (first input, then ground truth image)
        cj.job.update(
            progress=1,
            statusComment="Downloading images (to {})...".format(in_path))
        image_group = ImageGroupCollection().fetch_with_filter(
            "project", cj.parameters.cytomine_id_project)

        input_images = [i for i in image_group if gt_suffix not in i.name]
        gt_images = [i for i in image_group if gt_suffix in i.name]

        for input_image in input_images:
            input_image.download(os.path.join(in_path, "{id}.tif"))

        for gt_image in gt_images:
            related_name = gt_image.name.replace(gt_suffix, '')
            related_image = [i for i in input_images if related_name == i.name]
            if len(related_image) == 1:
                gt_image.download(
                    os.path.join(gt_path,
                                 "{}.tif".format(related_image[0].id)))

        # 3. Call the image analysis workflow using the run script
        cj.job.update(progress=25, statusComment="Launching workflow...")
        command = "/usr/bin/xvfb-run java -Xmx6000m -cp /fiji/jars/ij-1.52d.jar ij.ImageJ --headless --console " \
                  "-macro macro.ijm \"input={}, output={}\"".format(in_path, out_path)
        return_code = call(command, shell=True,
                           cwd="/fiji")  # waits for the subprocess to return

        if return_code != 0:
            err_desc = "Failed to execute the ImageJ macro (return code: {})".format(
                return_code)
            cj.job.update(progress=50, statusComment=err_desc)
            raise ValueError(err_desc)

        # 4. Upload the annotation and labels to Cytomine (annotations are extracted from the mask using
        # the AnnotationExporter module)


#        for image in cj.monitor(input_images, start=60, end=80, period=0.1, prefix="Extracting and uploading polygons from masks"):
#            file = "{}.tif".format(image.id)
#            path = os.path.join(out_path, file)
#            data = io.imread(path)

# extract objects
#            slices = mask_to_objects_2d(data)

#            print("Found {} polygons in this image {}.".format(len(slices), image.id))

# upload
#            collection = AnnotationCollection()
#            for obj_slice in slices:
#                collection.append(Annotation(
#                    location=affine_transform(obj_slice.polygon, [1, 0, 0, -1, 0, image.height]).wkt,
#                    id_image=image.id, id_project=cj.parameters.cytomine_id_project, property=[
#                        {"key": "index", "value": str(obj_slice.label)}
#                    ]
#                ))
#            collection.save()

# 5. Compute the metrics
        cj.job.update(progress=80, statusComment="Computing metrics...")
        for image in cj.monitor(input_images,
                                start=80,
                                end=98,
                                period=0.1,
                                prefix="computing metrics"):
            afile = "{}.tif".format(image.id)
            pathi = os.path.join(in_path, afile)
            patho = os.path.join(out_path, afile)
            #            data = io.imread(path)

            metrics, params = computemetrics(pathi, patho, "TreTrc", '/tmp')
            print('metrics for ' + pathi)
            print(metrics)

        # TODO: compute metrics:
        # in /out: output files {id}.tiff
        # in /ground_truth: label files {id}.tiff

        cj.job.update(progress=99, statusComment="Cleaning...")
        #        for image in input_images:
        #            os.remove(os.path.join(in_path, "{}.tif".format(image.id)))

        cj.job.update(status=Job.TERMINATED,
                      progress=100,
                      statusComment="Finished.")
def main(argv):
    with CytomineJob.from_cli(argv) as cj:
        # prepare paths
        working_path = str(Path.home())
        data_path = os.path.join(working_path, "pred_data")
        if not os.path.exists(data_path):
            os.makedirs(data_path)

        model_filename = "model.pkl"

        cj.job.update(progress=5, statusComment="Download model ...")
        model_job = Job().fetch(cj.parameters.cytomine_model_job_id)
        attached_files = AttachedFileCollection(model_job).fetch_with_filter(
            "project", cj.project.id)
        if not (0 < len(attached_files) < 2):
            raise ValueError(
                "More or less than 1 file attached to the Job (found {} file(s))."
                .format(len(attached_files)))
        attached_file = attached_files[0]
        if attached_file.filename != model_filename:
            raise ValueError(
                "Expected model file name is '{}' (found: '{}').".format(
                    model_filename, attached_file.filename))
        model_path = os.path.join(working_path, model_filename)
        attached_file.download(model_path)

        # load model
        with open(model_path, "rb") as file:
            data = pickle.load(file)
            model = data["model"]
            classifier = data["classifier"]
            network = data["network"]
            reduction = data["reduction"]

        # load and dump annotations
        cj.job.update(progress=10, statusComment="Download annotations.")
        annotations = get_annotations(
            project_id=cj.parameters.cytomine_project_id,
            images=parse_list_or_none(cj.parameters.cytomine_images_ids),
            users=parse_list_or_none(cj.parameters.cytomine_users_ids),
            showWKT=True)

        cj.job.update(statusComment="Fetch crops.", progress=15)
        n_samples = len(annotations)
        x = np.zeros([n_samples], dtype=np.object)
        for i, annotation in cj.monitor(enumerate(annotations),
                                        start=15,
                                        end=40,
                                        prefix="Fetch crops",
                                        period=0.1):
            file_format = os.path.join(data_path, "{id}.png")
            if not annotation.dump(dest_pattern=file_format):
                raise ValueError("Download error for annotation '{}'.".format(
                    annotation.id))
            x[i] = file_format.format(id=annotation.id)

        available_nets = {
            MODEL_RESNET50, MODEL_VGG19, MODEL_VGG16, MODEL_INCEPTION_V3,
            MODEL_INCEPTION_RESNET_V2, MODEL_MOBILE, MODEL_DENSE_NET_201,
            MODEL_NASNET_LARGE, MODEL_NASNET_MOBILE
        }

        if network not in available_nets:
            raise ValueError(
                "Invalid value (='{}'} for parameter 'network'.".format(
                    network))
        if reduction not in {"average_pooling"}:
            raise ValueError(
                "Invalid value (='{}') for parameter 'reduction'.".format(
                    reduction))
        if classifier not in {"svm"}:
            raise ValueError(
                "Invalid value (='{}') for parameter 'classifier'.".format(
                    classifier))

        # prepare network
        cj.job.update(statusComment="Load neural network '{}'".format(network),
                      progress=40)
        features = PretrainedModelFeatures(model=network,
                                           layer="last",
                                           reduction=reduction,
                                           weights="imagenet")
        height, width, _ = features._get_input_shape(network)
        loader = ImageLoader(load_size_range=(height, height),
                             crop_size=height,
                             random_crop=False)

        cj.job.update(statusComment="Transform features.", progress=50)
        x_feat = batch_transform(loader,
                                 features,
                                 x,
                                 logger=cj.logger(start=50, end=70,
                                                  period=0.1),
                                 batch_size=128)

        cj.job.update(statusComment="Prediction with '{}'.".format(classifier),
                      progress=70)
        if hasattr(model, "n_jobs"):
            model.n_jobs = cj.parameters.n_jobs

        probas = None
        if hasattr(model, "predict_proba"):
            probas = model.predict_proba(x_feat)
            y_pred = model.classes_.take(np.argmax(probas, axis=1), axis=0)
        else:
            y_pred = model.predict(x_feat)

        cj.job.update(statusComment="Upload annotations.", progress=80)
        annotation_collection = AnnotationCollection()
        for i, annotation in cj.monitor(enumerate(annotations),
                                        start=80,
                                        end=100,
                                        period=0.1,
                                        prefix="Upload annotations"):
            annotation_collection.append(
                Annotation(location=annotation.location,
                           id_image=annotation.image,
                           id_project=annotation.project,
                           term=[int(y_pred[i])],
                           rate=float(probas[i])
                           if probas is not None else 1.0).save())
        annotation_collection.save()

        cj.job.update(statusComment="Finished.", progress=100)