예제 #1
0
def clean_tree(email, token, label_tree_id):
    # Init API
    api = Api(email, token)

    # Get label tree info
    label_tree_info = api.get('label-trees/{}'.format(label_tree_id)).json()['labels']
    z_ids = []
    for label_info in label_tree_info:
        if label_info['name'].startswith('z_'):
            z_ids.append(label_info['id'])

    # Remove z kids
    for label_info in label_tree_info:
        if label_info['parent_id'] in z_ids:
            try:
                api.post('label-trees/{}/merge-labels'.format(label_tree_id), json={'remove': [label_info['id']]})
            except:
                print(label_info)
                #print(api.get('labels/{}/annotations'.format(label_info['id'])).json())
                #print(api.get('annotations/{}'.format('7875997')).json())

    # Empty parents
    for zid in z_ids:
        parent = api.get('labels/{}/annotations'.format(zid)).json()
        for annotation_id in parent:
            api.delete('annotations/{}'.format(annotation_id))

    # Remove parents
    #api.post('label-trees/{}/merge-labels'.format(label_tree_id), json={'remove': z_ids})

    print('{}'.format('\n'.join([(' '.join([l['name'], str(l['id']), str(l['parent_id'])])) for l in label_tree_info])))

    # Create new parent
    #api.post('label-trees/{}/labels'.format(label_tree_id), json={'color': "#0be6c8",
    #                                                               "name": "HydroCorals"
    #                                                               })

    # Move HydroCorals
    #api.put('labels/{}'.format(133260), json={"parent_id": 155169, "name": 'Branching'})
    #api.put('labels/{}'.format(133261), json={"parent_id": 155169, "name": 'Encrusting'})

    # Rename Hydroids
    #api.put('labels/{}'.format(133262), json={"name": 'Colonial feather'})
    #api.put('labels/{}'.format(133263), json={"name": 'Solitary'})
    #api.put('labels/{}'.format(133259), json={"name": 'Matrix'})
    #api.put('labels/{}'.format(133258), json={"name": 'Hydroids'})

    print('\n\n---------- Finished ----------\n\n')
예제 #2
0
def fetch_incorrect_laser(email, token, survey_name, ofolder):
    # Init API
    api = Api(email, token)

    # Get all surveys
    surveys = api.get('volumes').json()
    # Get info for survey of interest
    survey_dict = get_survey(surveys, survey_name)
    survey_id = survey_dict['id']

    # Get the list of image IDs that belong to the survey of interest
    image_ids = api.get('volumes/{}/images'.format(survey_id)).json()
    print("\n\t... Found {} images.".format(len(image_ids)))

    # Init result dict
    dict = {'image_fname': [], 'image_id': [], 'n_laser': []}

    print("\n... Looping across images.")
    for image_id in image_ids:
        # Get all annotations for the current image
        annotation_info = api.get(
            'images/{}/annotations'.format(image_id)).json()
        # Get laser annotations for the given image
        laser_annotations = get_label_annotations(annotation_info, LABEL_NAME)

        # Check if nb laser annotations is wrong
        if len(laser_annotations) != 2:
            dict['image_id'].append(image_id)
            dict['image_fname'].append(
                api.get('images/{}'.format(image_id)).json()['filename'])
            dict['n_laser'].append(len(laser_annotations))

    # Output folder
    if os.path.isdir(ofolder):
        print('\nOutput folder already exists: {}.'.format(ofolder))
    else:
        print('\nCreating output folder: {}.'.format(ofolder))
        os.makedirs(ofolder)
    fname_out = os.path.join(ofolder, survey_name + '_incorrect_laser.csv')
    df = pd.DataFrame.from_dict(dict)
    df.to_csv(fname_out)
    print('\nSaving results in: {}.'.format(fname_out))

    print('\n\n---------- Finished ----------\n\n')
예제 #3
0
def convert_laser_circle_to_point(email, token, survey_name):
    # Init API
    api = Api(email, token)

    # Get the available annotation shapes.
    # https://biigle.de/doc/api/index.html#api-Shapes-IndexShapes
    shapes = api.get('shapes').json()
    shapes = {s['name']: s['id'] for s in shapes}

    # Get all surveys
    surveys = api.get('volumes').json()
    # Get info for survey of interest
    survey_dict = get_survey(surveys, survey_name)
    survey_id = survey_dict['id']

    # Get the list of image IDs that belong to the survey of interest
    image_ids = api.get('volumes/{}/images'.format(survey_id)).json()
    print("\n\t... Found {} images.".format(len(image_ids)))

    print("\n... Looping across images.")
    for image_id in image_ids:
        # Check if laser point already exist
        try:
            laser_info = api.get(
                'images/{}/laserpoints'.format(image_id)).json()

            if laser_info:
                print('\tAlready a laser point for image {}, skipping.'.format(
                    image_id))
                continue

        except:
            # Get all annotations for the current image
            annotation_info = api.get(
                'images/{}/annotations'.format(image_id)).json()
            # Get laser annotations for the given image
            laser_annotations = get_label_annotations(annotation_info,
                                                      LABEL_NAME)

            # Check if there is some laser annotations
            if len(laser_annotations):
                # Loop across laser points
                for laser in laser_annotations:
                    # Check if laser shape is not a Point
                    if laser['shape_id'] != shapes['Point']:
                        # Check if laser shape is a circle
                        if laser['shape_id'] != 4:
                            print(
                                "NOT IMPLEMENTED YET: laser shape: {}.".format(
                                    laser['shape_id']))
                            exit()

                        print(
                            '\t\tImage {} --> converting annotation {} to Point.'
                            .format(laser['image_id'], laser["id"]))
                        api.put('annotations/{}'.format(laser["id"]),
                                json={
                                    'shape_id': shapes['Point'],
                                    'points': laser['points'][:-1]
                                })

                    else:
                        print(
                            '\t\tCorrect laser annotation shape on image {}, annotation '
                            '{}.'.format(laser['image_id'], laser["id"]))

            else:
                print('\tNo {} found for image {}, skipping.'.format(
                    LABEL_NAME, image_id))
                continue

    print('\n\n---------- Finished ----------\n\n')
예제 #4
0
def remove_maia_duplicates(email,
                           token,
                           label_tree_id,
                           survey_name,
                           maia_date,
                           range_image=None,
                           label_id=None):
    # Init API
    api = Api(email, token)

    # Get all surveys
    surveys = api.get('volumes').json()
    # Get info for survey of interest
    survey_dict = get_survey(surveys, survey_name)
    survey_id = survey_dict['id']

    # Get all labels from label tree
    if label_id is None:
        label_list = api.get(
            'label-trees/{}'.format(label_tree_id)).json()['labels']
    else:
        label_list = [{'id': i} for i in label_id]

    cmpt_new = 0
    # Loop through labels
    for label in label_list:
        # Get annotations
        annotation_list = api.get(
            'volumes/{}/annotations/filter/label/{}'.format(
                survey_id, label['id'])).json()

        if len(annotation_list):
            print('\nProcessing Label ID: {}.'.format(label['id']))
            annotation_id_list = list(annotation_list.keys())
            for id_ in annotation_id_list:
                annotation_info = api.get('annotations/{}'.format(id_)).json()
                if annotation_info['created_at'].startswith(maia_date):
                    if range_image is not None and annotation_info['image_id'] in \
                            list(range(range_image[0], range_image[1]+1)):
                        labels_in_img = [
                            l for l in api.get('images/{}/annotations'.format(
                                annotation_info['image_id'])).json()
                        ]
                        labels_in_img = [
                            l for l in labels_in_img if
                            int(l['labels'][0]['label_id']) == int(label['id'])
                            and not l['created_at'].startswith(maia_date)
                        ]
                        if len(labels_in_img):
                            print('\tDeleting: ')
                            print(annotation_info)
                            api.delete('annotations/{}'.format(id_))
                        else:
                            print('\tSave: ')
                            print(annotation_info)
                            cmpt_new += 1
                    else:
                        cmpt_new += 1

    print('\nNb of new annotations thanks of MAIA: {}.'.format(cmpt_new))

    print('\n\n---------- Finished ----------\n\n')
예제 #5
0
def review_annotations(email,
                       token,
                       label_tree_id,
                       input_folder,
                       wnd_dims,
                       n_patches=None,
                       label_folder=[]):
    # Init API
    api = Api(email, token)

    # subfolder list
    if label_folder is None or len(label_folder) == 0:
        taxa_list = [
            f for f in os.listdir(input_folder)
            if os.path.isdir(os.path.join(input_folder, f))
        ]
        print('\nFound {} taxa.'.format(len(taxa_list)))
    else:
        taxa_list = []
        for l in label_folder:
            if os.path.isdir(os.path.join(input_folder, l)):
                taxa_list.append(l)
                print('\nReviewing {}.'.format(os.path.join(input_folder, l)))
            else:
                print('\nFolder not found: {}.'.format(
                    os.path.join(input_folder, l)))
                exit()

    # Get all labels from label tree
    label_tree_info = api.get(
        'label-trees/{}'.format(label_tree_id)).json()['labels']
    label_dict = biigle_utils.get_folders_match_tree(label_tree_info)

    # Log file
    fname_log = os.path.join(
        input_folder,
        "logfile_" + datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + ".csv")
    dict_log = {"annotation_id": [], "from": [], "to": [], "who": []}

    # Init GUI
    gui = Tk()
    gui.geometry(
        str(wnd_dims[2]) + "x" + str(wnd_dims[3]) + "+" + str(550) + "+" +
        str(0))
    # Init main window
    app = Window(master=gui,
                 height=wnd_dims[1],
                 width=wnd_dims[0],
                 list_labels=sorted(list(label_dict.keys())))

    # Loop across taxa
    for taxa in taxa_list:
        print('\nReviewing: {} ...'.format(taxa))
        taxa_folder = os.path.join(input_folder, taxa)
        fname_list = [f for f in os.listdir(taxa_folder) if f.endswith('.jpg')]
        if n_patches is not None and len(fname_list) > n_patches:
            fname_list = random.sample(fname_list, n_patches)
        fname_nested = [
            fname_list[i:i + N_IMG_PER_WND]
            for i in range(0, len(fname_list), N_IMG_PER_WND)
        ]

        # Review per chuncks
        for fname_sublist in tqdm(fname_nested, desc="Reviewing"):
            path_list = [os.path.join(taxa_folder, f) for f in fname_sublist]

            # Show image and wait
            app.show_img(path_list, taxa)
            app.wait_variable(app.accept_key)
            # Close window
            app.sample.destroy()
            # Get changes
            change_list = app.changes_list
            # Reset
            app.reset_accept()

            # Loop across changes
            for change in change_list:
                annotation_id, annotation_folder = change

                # Inform about change
                image_id = api.get('image-annotations/{}'.format(
                    annotation_id)).json()['image_id']
                image_info = api.get('images/{}'.format(image_id)).json()
                print(
                    '\n\tChange annotation {} from {} to {} on image {} (image ID: {}).'
                    .format(annotation_id, taxa, annotation_folder,
                            image_info['filename'], image_info['id']))

                # Change label
                if annotation_folder != "NOT_VME":
                    api.post(
                        'image-annotations/{}/labels'.format(annotation_id),
                        json={
                            'label_id': label_dict[annotation_folder]['id'],
                            'confidence': 1
                        })

                # Remove old label
                old_label_id = [
                    ann['id']
                    for ann in api.get('image-annotations/{}/labels'.format(
                        annotation_id)).json()
                    if ann["label_id"] == label_dict[taxa]['id']
                ][0]
                api.delete('image-annotation-labels/{}'.format(old_label_id))

                # fill Log file
                dict_log["annotation_id"].append(annotation_id)
                dict_log["from"].append(taxa)
                dict_log["to"].append(annotation_folder)
                dict_log["who"].append(email)

                # Move patch folder
                ifname = os.path.join(input_folder, taxa,
                                      str(annotation_id) + '.jpg')
                ofname = os.path.join(input_folder, annotation_folder,
                                      str(annotation_id) + '.jpg')
                if not os.path.isdir(
                        os.path.join(input_folder, annotation_folder)):
                    os.makedirs(os.path.join(input_folder, annotation_folder))
                shutil.move(ifname, ofname)

            # Quit if asked
            if app.quit_:
                print('\nQuitting the review process.')
                gui.destroy()
                break

        if app.quit_:
            break

    # Quit if not done yet
    if not app.quit_:
        gui.destroy()

    # Save Log file
    df = pd.DataFrame.from_dict(dict_log)
    df.to_csv(fname_log, index=False)
    print('\nSaving log file in: {}'.format(fname_log))
예제 #6
0
def move_annotations(email,
                     token,
                     input_folder,
                     output_folder,
                     label_tree_id,
                     src,
                     dest,
                     batch_size=100):
    # Init API
    api = Api(email, token)

    # Get all labels from label tree
    label_tree_info = api.get(
        'label-trees/{}'.format(label_tree_id)).json()['labels']
    label_dict = biigle_utils.get_folders_match_tree(label_tree_info)

    # Check folders exist
    src_folder = os.path.join(output_folder, src)
    dest_folder = os.path.join(output_folder, dest)
    for f in [input_folder, src_folder]:
        if not os.path.isdir(f):
            print('\nFolder not found: {}'.format(f))
            exit()
    if not os.path.isdir(dest_folder) and dest != "NOT_VME":
        if dest in label_dict:
            print('\nCreating destination folder: {}'.format(dest_folder))
            os.makedirs(dest_folder)
        else:
            print('\nUnknown destination category: {}'.format(dest))
            exit()

    # Log file
    fname_log = os.path.join(
        output_folder,
        "logfile_" + datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + ".csv")
    dict_log = {"annotation_id": [], "from": [], "to": [], "who": []}

    # Get annotation fnames
    input_fname_list = [
        f for f in os.listdir(input_folder) if f.endswith('.jpg')
    ]

    # Check if all annotations from input folder are coming from source folder
    input_fname_list_new = []
    for idx, f in enumerate(input_fname_list):
        src_fname_cur = os.path.join(src_folder, f)
        if not os.path.isfile(src_fname_cur):
            print('\tWARNING: {} is not found in {}'.format(f, src_folder))
        else:
            input_fname_list_new.append(f)
    print('\nFound {} annotations to move.'.format(len(input_fname_list_new)))

    # Nested list
    input_fname_nested = [
        input_fname_list_new[i:i + batch_size]
        for i in range(0, len(input_fname_list_new), batch_size)
    ]

    # Move per batch
    for fname_sublist in tqdm(input_fname_nested, desc="Reviewing"):
        annotation_ids = [f.split('.jpg')[0] for f in fname_sublist]
        annotation_infos = [
            api.get('image-annotations/{}'.format(annotation_id)).json()
            for annotation_id in annotation_ids
        ]

        # Create batch
        batch = []
        for annotation_info in annotation_infos:
            if dest != "NOT_VME":
                annotation_info["label_id"] = label_dict[dest]['id']
            annotation_info["confidence"] = 1.00
            batch.append(copy.copy(annotation_info))

        # Run batch
        if dest != "NOT_VME":
            api.post('image-annotations', json=batch)

        # Cleanup
        for batch_info in batch:
            # Print info
            image_info = api.get('images/{}'.format(
                batch_info['image_id'])).json()
            print(
                '\n\tChange annotation {} from {} to {} on image {} (image ID: {}).'
                .format(batch_info['id'], src, dest, image_info['filename'],
                        image_info['id']))

            # Detach old label
            old_label_id = [
                ann['id']
                for ann in api.get('image-annotations/{}/labels'.format(
                    batch_info['id'])).json()
                if ann["label_id"] == label_dict[src]['id']
            ][0]
            api.delete('image-annotation-labels/{}'.format(old_label_id))

            # Move file
            if dest != "NOT_VME":
                shutil.move(
                    os.path.join(src_folder,
                                 str(batch_info['id']) + '.jpg'),
                    os.path.join(dest_folder,
                                 str(batch_info['id']) + '.jpg'))
            else:
                os.remove(
                    os.path.join(src_folder,
                                 str(batch_info['id']) + '.jpg'))

            # fill Log file
            dict_log["annotation_id"].append(batch_info['id'])
            dict_log["from"].append(src)
            dict_log["to"].append(dest)
            dict_log["who"].append(email)

    # Save Log file
    df = pd.DataFrame.from_dict(dict_log)
    df.to_csv(fname_log, index=False)
    print('\nSaving log file in: {}'.format(fname_log))
예제 #7
0
def pull_patches(email,
                 token,
                 survey_name,
                 label_tree_id,
                 output_folder,
                 range_image=[],
                 label_id=None,
                 skip=False):
    # Init API
    api = Api(email, token)

    # Get all surveys
    surveys = api.get('volumes').json()
    # Get info for survey of interest
    survey_dict = get_survey(surveys, survey_name)
    survey_id = survey_dict['id']

    # Output folder
    if os.path.isdir(output_folder):
        print('\nOutput folder already exists: {}.'.format(output_folder))
    else:
        print('\nCreating output folder: {}.'.format(output_folder))
        os.makedirs(output_folder)

    # Get label info
    labels_info_list = api.get(
        'volumes/{}/annotation-labels'.format(survey_id)).json()
    label_tree_info = api.get('label-trees/{}'.format(label_tree_id)).json()
    labels_info_list = add_parent_name(label_tree_info['labels'],
                                       labels_info_list)

    # Pick the label of interest
    if label_id != None:
        labels_info_list = [
            label_info for label_info in labels_info_list
            if label_info['id'] == label_id
        ]

    # Init patch URL
    patch_url = 'https://biigle.de/storage/largo-patches/{}/{}/{}/{}.jpg'

    # List annotations of interest
    if len(range_image):
        list_img_annotations = []
        images = api.get('volumes/{}/files'.format(survey_id)).json()
        images_range = list(range(range_image[0], range_image[1] + 1))
        images_of_interest = [ii for ii in images_range if ii in images]
        for image_id in tqdm(images_of_interest,
                             desc="Fetching annotations of interest"):
            try:
                annotations_list = api.get(
                    'images/{}/annotations'.format(image_id)).json()
                annotations_id_list = [str(a['id']) for a in annotations_list]
                list_img_annotations = list_img_annotations + annotations_id_list
            except:
                pass
    else:
        list_img_annotations = None

    for label_dict in labels_info_list:
        annotations = api.get(
            'volumes/{}/image-annotations/filter/label/{}'.format(
                survey_id, label_dict['id'])).json()
        if len(annotations) > 0:
            # Label full name
            full_name = label_dict['name'].replace(' ', '_')
            if len(label_dict['parent_name']) > 0:
                full_name = label_dict['parent_name'].replace(
                    ' ', '_') + '-' + full_name
            print('\tPulling patches for Label: {}.'.format(full_name))
            print('\tFound {} annotations.'.format(len(annotations)))

            # Label output folder
            label_ofolder = os.path.join(output_folder, full_name)
            if os.path.isdir(label_ofolder):
                print('\tOutput folder already exists: {}.'.format(
                    label_ofolder))
                if skip:
                    print('\t\tSkipping.')
                    continue
            else:
                print('\tCreating output folder: {}.'.format(label_ofolder))
                os.makedirs(label_ofolder)

            for annotation_id, image_uuid in tqdm(annotations.items(),
                                                  desc="Pulling"):
                if list_img_annotations is None or (
                        len(list_img_annotations) > 0
                        and annotation_id in list_img_annotations):
                    url = patch_url.format(image_uuid[:2], image_uuid[2:4],
                                           image_uuid, annotation_id)
                    patch = requests.get(url, stream=True)
                    if patch.ok != True:
                        print('Failed to fetch {}'.format(url))
                        continue
                    with open(
                            os.path.join(label_ofolder,
                                         '{}.jpg'.format(annotation_id)),
                            'wb') as f:
                        patch.raw.decode_content = True
                        shutil.copyfileobj(patch.raw, f)

    print('\n\n---------- Finished ----------\n\n')