#           label_text: group label text in UI
#           choices: list of `labelling_tool.AnnoControlPopupMenu.choice` that provide:
#               value: symbolic value name for choice
#               label_text: choice label text in UI
#               tooltip: extra information for user
ANNO_CONTROLS = [
    labelling_tool.AnnoControlCheckbox('good_quality', 'Good quality'),
    labelling_tool.AnnoControlRadioButtons(
        'visibility',
        'Visible',
        choices=[
            labelling_tool.AnnoControlRadioButtons.choice(
                value='full',
                label_text='Fully',
                tooltip='Object is fully visible'),
            labelling_tool.AnnoControlRadioButtons.choice(
                value='mostly',
                label_text='Mostly',
                tooltip='Object is mostly visible'),
            labelling_tool.AnnoControlRadioButtons.choice(
                value='obscured',
                label_text='Obscured',
                tooltip='Object is significantly obscured'),
        ],
        label_on_own_line=False),
    labelling_tool.AnnoControlPopupMenu(
        'material',
        'Material',
        groups=[
            labelling_tool.AnnoControlPopupMenu.group(
                label_text='Artifical/buildings',
                choices=[
def run_app(images_dir, images_pat, labels_dir, readonly,
            update_label_object_ids, enable_dextr, dextr_weights):
    if enable_dextr or dextr_weights is not None:
        from dextr.model import DextrModel
        import torch

        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

        if dextr_weights is not None:
            dextr_weights = pathlib.Path(dextr_weights).expanduser()
            dextr_model = torch.load(dextr_weights, map_location=device)
        else:
            dextr_model = DextrModel.pascalvoc_resunet101().to(device)

        dextr_model.eval()

        dextr_fn = lambda image, points: dextr_model.predict([image], points[
            None, :, :])[0] >= 0.5
    else:
        dextr_fn = None

    # Load schema
    schema_path = pathlib.Path(images_dir) / 'schema.json'
    schema_store = labelling_schema.FileSchemaStore(schema_path,
                                                    readonly=readonly)

    # Annotation controls
    # Labels may also have optional meta-data associated with them
    # You could use this for e.g. indicating if an object is fully visible, mostly visible or significantly obscured.
    # You could also indicate quality (e.g. blurriness, etc)
    # There are four types of annotation. They have some common properties:
    #   - name: symbolic name (Python identifier)
    #   - label_text: label text in UI
    #   Check boxes, radio buttons and popup menus also have:
    #     - visibility_label_text: [optional] if provided, label visibility can be filtered by this annotation value,
    #       in which case a drop down will appear in the UI allowing the user to select a filter value
    #       that will hide/show labels accordingly
    # Control types:
    # Check box (boolean value):
    #   `labelling_tool.AnnoControlCheckbox`; only the 3 common parameters listed above
    # Radio button (choice from a list):
    #   `labelling_tool.AnnoControlRadioButtons`; the 3 common parameters listed above and:
    #       - choices: list of `labelling_tool.AnnoControlRadioButtons.choice` that provide:
    #           - value: symbolic value name for choice
    #           - tooltip: extra information for user
    #       - label_on_own_line [optional]: if True, place the label and the buttons on a separate line in the UI
    # Popup menu (choice from a grouped list):
    #   `labelling_tool.AnnoControlPopupMenu`; the 3 common parameters listed above and:
    #       - groups: list of groups `labelling_tool.AnnoControlPopupMenu.group`:
    #           - label_text: label text in UI
    #           - choices: list of `labelling_tool.AnnoControlPopupMenu.choice` that provide:
    #               - value: symbolic value name for choice
    #               - label_text: choice label text in UI
    #               - tooltip: extra information for user
    # Text (free form plain text):
    #   `labelling_tool.AnnoControlText`; only the 2 common parameters listed above and:
    #       - multiline: boolean; if True a text area will be used, if False a single line text entry
    anno_controls = [
        labelling_tool.AnnoControlCheckbox(
            'good_quality',
            'Good quality',
            visibility_label_text='Filter by good quality'),
        labelling_tool.AnnoControlRadioButtons(
            'visibility',
            'Visible',
            choices=[
                labelling_tool.AnnoControlRadioButtons.choice(
                    value='full',
                    label_text='Fully',
                    tooltip='Object is fully visible'),
                labelling_tool.AnnoControlRadioButtons.choice(
                    value='mostly',
                    label_text='Mostly',
                    tooltip='Object is mostly visible'),
                labelling_tool.AnnoControlRadioButtons.choice(
                    value='obscured',
                    label_text='Obscured',
                    tooltip='Object is significantly obscured'),
            ],
            label_on_own_line=False,
            visibility_label_text='Filter by visibility'),
        labelling_tool.AnnoControlPopupMenu(
            'material',
            'Material',
            groups=[
                labelling_tool.AnnoControlPopupMenu.group(
                    label_text='Artifical/buildings',
                    choices=[
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='concrete',
                            label_text='Concrete',
                            tooltip='Concrete objects'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='plastic',
                            label_text='Plastic',
                            tooltip='Plastic objects'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='asphalt',
                            label_text='Asphalt',
                            tooltip='Road, pavement, etc.'),
                    ]),
                labelling_tool.AnnoControlPopupMenu.group(
                    label_text='Flat natural',
                    choices=[
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='grass',
                            label_text='Grass',
                            tooltip='Grass covered ground'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='water',
                            label_text='Water',
                            tooltip='Water/lake')
                    ]),
                labelling_tool.AnnoControlPopupMenu.group(
                    label_text='Vegetation',
                    choices=[
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='trees', label_text='Trees',
                            tooltip='Trees'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='shrubbery',
                            label_text='Shrubs',
                            tooltip='Shrubs/bushes'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='flowers',
                            label_text='Flowers',
                            tooltip='Flowers'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='ivy', label_text='Ivy', tooltip='Ivy')
                    ]),
            ],
            visibility_label_text='Filter by material'),
        # labelling_tool.AnnoControlText('comment', 'Comment', multiline=False),
    ]

    image_pats = images_pat.split('|')

    # Load in .JPG images from the 'images' directory.
    labelled_images = labelled_image.LabelledImage.for_directory(
        images_dir, image_filename_patterns=image_pats, readonly=readonly)
    print('Loaded {0} images'.format(len(labelled_images)))

    if update_label_object_ids:
        n_updated = 0
        for limg in labelled_images:
            if limg.labels_store.labels_path.exists():
                label_js = json.load(limg.labels_store.labels_path.open('r'))
                prefix = str(uuid.uuid4())
                modified = labelling_tool.ensure_json_object_ids_have_prefix(
                    label_js, id_prefix=prefix)
                if modified:
                    with open(limg.labels_store.labels_path, 'w') as f_out:
                        json.dump(label_js, f_out, indent=3)
                    n_updated += 1
        print('Updated object IDs in {} files'.format(n_updated))

    # For documentation of the configuration, please see the comment above `labelling_tool.DEFAULT_CONFIG`
    config = labelling_tool.DEFAULT_CONFIG

    tasks = [
        dict(name='finished', human_name='[old] finished'),
        dict(name='segmentation', human_name='Outlines'),
        dict(name='classification', human_name='Classification'),
    ]

    flask_labeller_and_schema_editor(labelled_images,
                                     schema_store,
                                     tasks=tasks,
                                     anno_controls=anno_controls,
                                     config=config,
                                     dextr_fn=dextr_fn)
def run_app(dextr_weights, enable_firebug, use_http_memory_cache):
    import pathlib
    import glob
    from image_labelling_tool import labelled_image, labelling_tool

    # Create an application
    app = QtWidgets.QApplication([])

    # Start with a dialog that allows the user to choose the images directory, optionally
    # a labels directory and read only checkbox
    init_dialog = QtWidgets.QDialog()
    # Dialog layout
    dia_layout = QtWidgets.QGridLayout()
    init_dialog.setLayout(dia_layout)

    images_dir = ['.']
    labels_dir = [None]

    # Prompt
    prompt_label = QtWidgets.QLabel(
        'Choose an images directory and optionally a labels directory.')
    dia_layout.addWidget(prompt_label, 0, 0, 1, 2)

    # Images directory
    images_dir_button = QtWidgets.QPushButton('Choose images directory')
    images_dir_button.setIcon(init_dialog.style().standardIcon(
        QtWidgets.QStyle.SP_DirOpenIcon))
    images_dir_label = QtWidgets.QLabel(images_dir[0])

    def _on_images_dir_button():
        file_dialog = QtWidgets.QFileDialog(None, 'Choose images directory',
                                            '')
        file_dialog.setFileMode(QtWidgets.QFileDialog.Directory)
        choice = file_dialog.exec()
        if choice == QtWidgets.QFileDialog.Accepted:
            images_dir[0] = file_dialog.selectedFiles()[0]
            images_dir_label.setText(images_dir[0])

    images_dir_button.clicked.connect(_on_images_dir_button)
    dia_layout.addWidget(images_dir_button, 1, 0)
    dia_layout.addWidget(images_dir_label, 1, 1)

    # Labels directory
    labels_dir_button = QtWidgets.QPushButton(
        '[Optional] Choose labels directory')
    labels_dir_button.setIcon(init_dialog.style().standardIcon(
        QtWidgets.QStyle.SP_DirOpenIcon))
    labels_dir_label = QtWidgets.QLabel('')

    def _on_labels_dir_button():
        file_dialog = QtWidgets.QFileDialog(None, 'Choose labels directory',
                                            '')
        file_dialog.setFileMode(QtWidgets.QFileDialog.Directory)
        choice = file_dialog.exec()
        if choice == QtWidgets.QFileDialog.Accepted:
            labels_dir[0] = file_dialog.selectedFiles()[0]
            labels_dir_label.setText(labels_dir[0])

    labels_dir_button.clicked.connect(_on_labels_dir_button)
    dia_layout.addWidget(labels_dir_button, 2, 0)
    dia_layout.addWidget(labels_dir_label, 2, 1)

    # Read only checkbox
    read_only_check = QtWidgets.QCheckBox('Read only')
    dia_layout.addWidget(read_only_check, 3, 1)

    # Read only checkbox
    read_only_check = QtWidgets.QCheckBox('Read only')
    dia_layout.addWidget(read_only_check, 3, 1)

    # DEXTR checkbox
    dextr_check = QtWidgets.QCheckBox('Enable DEXTR')
    dia_layout.addWidget(dextr_check, 4, 1)

    # Buttons
    ok_button = QtWidgets.QPushButton('Ok')
    ok_button.setIcon(init_dialog.style().standardIcon(
        QtWidgets.QStyle.SP_DialogOkButton))

    def _on_ok():
        init_dialog.accept()

    ok_button.clicked.connect(_on_ok)
    cancel_button = QtWidgets.QPushButton('Cancel')
    cancel_button.setIcon(init_dialog.style().standardIcon(
        QtWidgets.QStyle.SP_DialogCancelButton))

    def _on_cancel():
        init_dialog.reject()

    cancel_button.clicked.connect(_on_cancel)
    dia_layout.addWidget(ok_button, 5, 0)
    dia_layout.addWidget(cancel_button, 5, 1)

    # Run the dialog
    action = init_dialog.exec()

    if action == QtWidgets.QDialog.Accepted:
        images_dir = pathlib.Path(images_dir[0])
        if labels_dir[0] is not None:
            labels_dir = pathlib.Path(labels_dir[0])
        else:
            labels_dir = None
        enable_dextr = dextr_check.checkState()
        readonly = read_only_check.checkState()

        server = web_server.LabellerServer()
        server.start_flask_server()

        try:
            # If DEXTR is to be made available
            if enable_dextr or dextr_weights is not None:
                from dextr.model import DextrModel
                import torch

                # Load the dextr model
                device = torch.device(
                    "cuda:0" if torch.cuda.is_available() else "cpu")

                if dextr_weights is not None:
                    dextr_weights = pathlib.Path(dextr_weights).expanduser()
                    dextr_model = torch.load(dextr_weights,
                                             map_location=device)
                else:
                    dextr_model = DextrModel.pascalvoc_resunet101().to(device)

                # Evaluation mode
                dextr_model.eval()

                # Define a mask prediction function
                dextr_fn = lambda image, points: dextr_model.predict(
                    [image], points[None, :, :])[0] >= 0.5
            else:
                dextr_fn = None

            # Colour schemes
            # The user may select different colour schemes for different tasks.
            # If you have a lot of classes, it will be difficult to select colours that are easily distinguished
            # from one another. For one task e.g. segmentation, design a colour scheme that highlights the different
            # classes for that task, while another task e.g. fine-grained classification would use another scheme.
            # Each colour scheme is a dictionary containing the following:
            #   name: symbolic name (Python identifier)
            #   human_name: human readable name for UI
            # These colour schemes are going to split the classes by 'default' (all), natural, and artificial.
            # Not really useful, but demonstrates the feature.
            colour_schemes = [
                dict(name='default', human_name='All'),
                dict(name='natural', human_name='Natural'),
                dict(name='artificial', human_name='Artifical')
            ]

            # Specify our label classes, organised in groups.
            # `LabelClass` parameters are:
            #   symbolic name (Python identifier)
            #   human readable name for UI
            #   and colours by colour scheme, as a dict mapping colour scheme name to RGB value as a list
            # The label classes are arranged in groups and will be displayed as such in the UI.
            # `LabelClassGroup` parameters are:
            #   human readable name for UI
            #   label class (`LabelClass` instance) list
            label_classes = [
                labelling_tool.LabelClassGroup('Natural', [
                    labelling_tool.LabelClass(
                        'tree', 'Trees',
                        dict(default=[0, 255, 192],
                             natural=[0, 255, 192],
                             artificial=[128, 128, 128])),
                    labelling_tool.LabelClass(
                        'lake', 'Lake',
                        dict(default=[0, 128, 255],
                             natural=[0, 128, 255],
                             artificial=[128, 128, 128])),
                    labelling_tool.LabelClass(
                        'flower', 'Flower',
                        dict(default=[255, 96, 192],
                             natural=[255, 192, 96],
                             artificial=[128, 128, 128])),
                    labelling_tool.LabelClass(
                        'leaf', 'Leaf',
                        dict(default=[65, 255, 0],
                             natural=[65, 255, 0],
                             artificial=[128, 128, 128])),
                    labelling_tool.LabelClass(
                        'stem', 'Stem',
                        dict(default=[128, 64, 0],
                             natural=[128, 64, 0],
                             artificial=[128, 128, 128])),
                ]),
                labelling_tool.LabelClassGroup('Artificial', [
                    labelling_tool.LabelClass(
                        'building', 'Buildings',
                        dict(default=[255, 128, 0],
                             natural=[128, 128, 128],
                             artificial=[255, 128, 0])),
                    labelling_tool.LabelClass(
                        'wall', 'Wall',
                        dict(default=[0, 128, 255],
                             natural=[128, 128, 128],
                             artificial=[0, 128, 255])),
                ])
            ]

            # Annotation controls
            # Labels may also have optional meta-data associated with them
            # You could use this for e.g. indicating if an object is fully visible, mostly visible or significantly obscured.
            # You could also indicate quality (e.g. blurriness, etc)
            # There are four types of annotation. They have some common properties:
            #   - name: symbolic name (Python identifier)
            #   - label_text: label text in UI
            #   Check boxes, radio buttons and popup menus also have:
            #     - visibility_label_text: [optional] if provided, label visibility can be filtered by this annotation value,
            #       in which case a drop down will appear in the UI allowing the user to select a filter value
            #       that will hide/show labels accordingly
            # Control types:
            # Check box (boolean value):
            #   `labelling_tool.AnnoControlCheckbox`; only the 3 common parameters listed above
            # Radio button (choice from a list):
            #   `labelling_tool.AnnoControlRadioButtons`; the 3 common parameters listed above and:
            #       choices: list of `labelling_tool.AnnoControlRadioButtons.choice` that provide:
            #           value: symbolic value name for choice
            #           tooltip: extra information for user
            #       label_on_own_line [optional]: if True, place the label and the buttons on a separate line in the UI
            # Popup menu (choice from a grouped list):
            #   `labelling_tool.AnnoControlPopupMenu`; the 3 common parameters listed above and:
            #       groups: list of groups `labelling_tool.AnnoControlPopupMenu.group`:
            #           label_text: label text in UI
            #           choices: list of `labelling_tool.AnnoControlPopupMenu.choice` that provide:
            #               value: symbolic value name for choice
            #               label_text: choice label text in UI
            #               tooltip: extra information for user
            # Text (free form plain text):
            #   `labelling_tool.AnnoControlText`; only the 2 common parameters listed above and:
            #       - multiline: boolean; if True a text area will be used, if False a single line text entry
            anno_controls = [
                labelling_tool.AnnoControlCheckbox(
                    'good_quality',
                    'Good quality',
                    visibility_label_text='Filter by good quality'),
                labelling_tool.AnnoControlRadioButtons(
                    'visibility',
                    'Visible',
                    choices=[
                        labelling_tool.AnnoControlRadioButtons.choice(
                            value='full',
                            label_text='Fully',
                            tooltip='Object is fully visible'),
                        labelling_tool.AnnoControlRadioButtons.choice(
                            value='mostly',
                            label_text='Mostly',
                            tooltip='Object is mostly visible'),
                        labelling_tool.AnnoControlRadioButtons.choice(
                            value='obscured',
                            label_text='Obscured',
                            tooltip='Object is significantly obscured'),
                    ],
                    label_on_own_line=False,
                    visibility_label_text='Filter by visibility'),
                labelling_tool.AnnoControlPopupMenu(
                    'material',
                    'Material',
                    groups=[
                        labelling_tool.AnnoControlPopupMenu.group(
                            label_text='Artifical/buildings',
                            choices=[
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='concrete',
                                    label_text='Concrete',
                                    tooltip='Concrete objects'),
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='plastic',
                                    label_text='Plastic',
                                    tooltip='Plastic objects'),
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='asphalt',
                                    label_text='Asphalt',
                                    tooltip='Road, pavement, etc.'),
                            ]),
                        labelling_tool.AnnoControlPopupMenu.group(
                            label_text='Flat natural',
                            choices=[
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='grass',
                                    label_text='Grass',
                                    tooltip='Grass covered ground'),
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='water',
                                    label_text='Water',
                                    tooltip='Water/lake')
                            ]),
                        labelling_tool.AnnoControlPopupMenu.group(
                            label_text='Vegetation',
                            choices=[
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='trees',
                                    label_text='Trees',
                                    tooltip='Trees'),
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='shrubbery',
                                    label_text='Shrubs',
                                    tooltip='Shrubs/bushes'),
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='flowers',
                                    label_text='Flowers',
                                    tooltip='Flowers'),
                                labelling_tool.AnnoControlPopupMenu.choice(
                                    value='ivy',
                                    label_text='Ivy',
                                    tooltip='Ivy')
                            ]),
                    ],
                    visibility_label_text='Filter by material'),
                # labelling_tool.AnnoControlText('comment', 'Comment', multiline=False),
            ]

            image_paths = list(images_dir.glob('*.jpg')) + list(
                images_dir.glob('*.png'))
            image_paths = [p.absolute() for p in image_paths]

            # Create a `PersistentLabelledImage` instance for each image file
            labelled_images = labelled_image.LabelledImage.for_image_files(
                image_paths, labels_dir=labels_dir, readonly=bool(readonly))
            print('Loaded {0} images'.format(len(labelled_images)))

            config = web_server.DEFAULT_CONFIG

            # Example tasks to appear in checkboxes
            tasks = [
                dict(name='finished', human_name='[old] finished'),
                dict(name='segmentation', human_name='Outlines'),
                dict(name='classification', human_name='Classification'),
            ]

            # And a window
            win = QtWidgets.QWidget()
            win.setWindowTitle('Simple Qt Image Labeller')

            # And give it a layout
            layout = QtWidgets.QVBoxLayout()
            win.setLayout(layout)

            # Create the labeller
            lbl = controls.QLabellerForLabelledImages(
                server=server,
                label_classes=label_classes,
                labelled_images=labelled_images,
                tasks=tasks,
                colour_schemes=colour_schemes,
                anno_controls=anno_controls,
                config=config,
                dextr_fn=dextr_fn,
                enable_firebug=enable_firebug)
            # Create the web engine view
            view = QtWebEngineWidgets.QWebEngineView()

            # If requested, use a memory-based HTTP cache
            # This is very useful if the client-side Javascript code is being developed
            # as otherwise chromium's cache will often store old versions of the code that
            # will hamper debugging and deveopment
            if use_http_memory_cache:
                view.page().profile().setHttpCacheType(
                    QtWebEngineWidgets.QWebEngineProfile.MemoryHttpCache)

            # Attach the labeller to the web engine view
            lbl.attach_to_web_engine_view(view)

            # Add the QWebView to the layout
            layout.addWidget(view)

            # Show the window and run the app
            win.show()

            app.exec_()
        finally:
            print('Stopping server')
            server.stop_server()
Exemple #4
0
def run_app(images_pat, labels_dir, readonly, update_label_object_ids,
            enable_dextr, dextr_weights):
    import os
    import glob
    import json
    import uuid
    from image_labelling_tool import labelling_tool

    if enable_dextr or dextr_weights is not None:
        from dextr.model import DextrModel
        import torch

        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

        if dextr_weights is not None:
            dextr_weights = os.path.expanduser(dextr_weights)
            dextr_model = torch.load(dextr_weights, map_location=device)
        else:
            dextr_model = DextrModel.pascalvoc_resunet101().to(device)

        dextr_model.eval()

        dextr_fn = lambda image, points: dextr_model.predict([image], points[
            None, :, :])[0] >= 0.5
    else:
        dextr_fn = None

    # Colour schemes
    # The user may select different colour schemes for different tasks.
    # If you have a lot of classes, it will be difficult to select colours that are easily distinguished
    # from one another. For one task e.g. segmentation, design a colour scheme that highlights the different
    # classes for that task, while another task e.g. fine-grained classification would use another scheme.
    # Each colour scheme is a dictionary containing the following:
    #   name: symbolic name (Python identifier)
    #   human_name: human readable name for UI
    # These colour schemes are going to split the classes by 'default' (all), natural, and artificial.
    # Not really useful, but demonstrates the feature.
    colour_schemes = [
        dict(name='default', human_name='All'),
        dict(name='natural', human_name='Natural'),
        dict(name='artificial', human_name='Artifical')
    ]

    # Specify our label classes, organised in groups.
    # `LabelClass` parameters are:
    #   symbolic name (Python identifier)
    #   human readable name for UI
    #   and colours by colour scheme, as a dict mapping colour scheme name to RGB value as a list
    # The label classes are arranged in groups and will be displayed as such in the UI.
    # `LabelClassGroup` parameters are:
    #   human readable name for UI
    #   label class (`LabelClass` instance) list
    label_classes = [
        labelling_tool.LabelClassGroup('Natural', [
            labelling_tool.LabelClass(
                'tree', 'Trees',
                dict(default=[0, 255, 192],
                     natural=[0, 255, 192],
                     artificial=[128, 128, 128])),
            labelling_tool.LabelClass(
                'lake', 'Lake',
                dict(default=[0, 128, 255],
                     natural=[0, 128, 255],
                     artificial=[128, 128, 128])),
            labelling_tool.LabelClass(
                'flower', 'Flower',
                dict(default=[255, 96, 192],
                     natural=[255, 192, 96],
                     artificial=[128, 128, 128])),
            labelling_tool.LabelClass(
                'leaf', 'Leaf',
                dict(default=[65, 255, 0],
                     natural=[65, 255, 0],
                     artificial=[128, 128, 128])),
            labelling_tool.LabelClass(
                'stem', 'Stem',
                dict(default=[128, 64, 0],
                     natural=[128, 64, 0],
                     artificial=[128, 128, 128])),
        ]),
        labelling_tool.LabelClassGroup('Artificial', [
            labelling_tool.LabelClass(
                'building', 'Buildings',
                dict(default=[255, 128, 0],
                     natural=[128, 128, 128],
                     artificial=[255, 128, 0])),
            labelling_tool.LabelClass(
                'wall', 'Wall',
                dict(default=[0, 128, 255],
                     natural=[128, 128, 128],
                     artificial=[0, 128, 255])),
        ])
    ]

    # Annotation controls
    # Labels may also have optional meta-data associated with them
    # You could use this for e.g. indicating if an object is fully visible, mostly visible or significantly obscured.
    # You could also indicate quality (e.g. blurriness, etc)
    # There are three types of annotation:
    # Check box (boolean value):
    #   `labelling_tool.AnnoControlCheckbox` parameters:
    #       name: symbolic name (Python identifier)
    #       label_text: label text in UI
    # Radio button (choice from a list):
    #   `labelling_tool.AnnoControlRadioButtons` parameters:
    #       name: symbolic name (Python identifier)
    #       label_text: label text in UI
    #       choices: list of `labelling_tool.AnnoControlRadioButtons.choice` that provide:
    #           value: symbolic value name for choice
    #           label_text: choice label text in UI
    #           tooltip: extra information for user
    #       label_on_own_line [optional]: if True, place the label and the buttons on a separate line in the UI
    # Popup menu (choice from a grouped list):
    #   `labelling_tool.AnnoControlPopupMenu` parameters:
    #       name: symbolic name (Python identifier)
    #       label_text: label text in UI
    #       groups: list of groups `labelling_tool.AnnoControlPopupMenu.group`:
    #           label_text: group label text in UI
    #           choices: list of `labelling_tool.AnnoControlPopupMenu.choice` that provide:
    #               value: symbolic value name for choice
    #               label_text: choice label text in UI
    #               tooltip: extra information for user
    anno_controls = [
        labelling_tool.AnnoControlCheckbox('good_quality', 'Good quality'),
        labelling_tool.AnnoControlRadioButtons(
            'visibility',
            'Visible',
            choices=[
                labelling_tool.AnnoControlRadioButtons.choice(
                    value='full',
                    label_text='Fully',
                    tooltip='Object is fully visible'),
                labelling_tool.AnnoControlRadioButtons.choice(
                    value='mostly',
                    label_text='Mostly',
                    tooltip='Object is mostly visible'),
                labelling_tool.AnnoControlRadioButtons.choice(
                    value='obscured',
                    label_text='Obscured',
                    tooltip='Object is significantly obscured'),
            ],
            label_on_own_line=False),
        labelling_tool.AnnoControlPopupMenu(
            'material',
            'Material',
            groups=[
                labelling_tool.AnnoControlPopupMenu.group(
                    label_text='Artifical/buildings',
                    choices=[
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='concrete',
                            label_text='Concrete',
                            tooltip='Concrete objects'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='plastic',
                            label_text='Plastic',
                            tooltip='Plastic objects'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='asphalt',
                            label_text='Asphalt',
                            tooltip='Road, pavement, etc.'),
                    ]),
                labelling_tool.AnnoControlPopupMenu.group(
                    label_text='Flat natural',
                    choices=[
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='grass',
                            label_text='Grass',
                            tooltip='Grass covered ground'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='water',
                            label_text='Water',
                            tooltip='Water/lake')
                    ]),
                labelling_tool.AnnoControlPopupMenu.group(
                    label_text='Vegetation',
                    choices=[
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='trees', label_text='Trees',
                            tooltip='Trees'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='shrubbery',
                            label_text='Shrubs',
                            tooltip='Shrubs/bushes'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='flowers',
                            label_text='Flowers',
                            tooltip='Flowers'),
                        labelling_tool.AnnoControlPopupMenu.choice(
                            value='ivy', label_text='Ivy', tooltip='Ivy')
                    ]),
            ])
    ]

    if images_pat.strip() == '':
        image_paths = glob.glob('images/*.jpg') + glob.glob('images/*.png')
    else:
        image_paths = glob.glob(images_pat)

    # Load in .JPG images from the 'images' directory.
    labelled_images = labelling_tool.PersistentLabelledImage.for_files(
        image_paths, labels_dir=labels_dir, readonly=readonly)
    print('Loaded {0} images'.format(len(labelled_images)))

    if update_label_object_ids:
        n_updated = 0
        for limg in labelled_images:
            if os.path.exists(limg.labels_path):
                label_js = json.load(open(limg.labels_path, 'r'))
                prefix = str(uuid.uuid4())
                modified = labelling_tool.ensure_json_object_ids_have_prefix(
                    label_js, id_prefix=prefix)
                if modified:
                    with open(limg.labels_path, 'w') as f_out:
                        json.dump(label_js, f_out, indent=3)
                    n_updated += 1
        print('Updated object IDs in {} files'.format(n_updated))

    config = {
        'tools': {
            'imageSelector': True,
            'labelClassSelector': True,
            'drawPointLabel': False,
            'drawBoxLabel': True,
            'drawOrientedEllipseLabel': True,
            'drawPolyLabel': True,
            'compositeLabel': False,
            'deleteLabel': True,
            'deleteConfig': {
                'typePermissions': {
                    'point': True,
                    'box': True,
                    'polygon': True,
                    'composite': True,
                    'group': True,
                }
            }
        },
        'settings': {
            'brushWheelRate':
            0.025,  # Change rate for brush radius (mouse wheel)
            'brushKeyRate': 2.0,  # Change rate for brush radius (keyboard)
        }
    }

    tasks = [
        dict(name='finished', human_name='[old] finished'),
        dict(name='segmentation', human_name='Outlines'),
        dict(name='classification', human_name='Classification'),
    ]

    flask_labeller(label_classes,
                   labelled_images,
                   tasks=tasks,
                   colour_schemes=colour_schemes,
                   anno_controls=anno_controls,
                   config=config,
                   dextr_fn=dextr_fn)
Exemple #5
0
def run_app(images_dir, images_pat, labels_dir, readonly, update_label_object_ids,
            enable_dextr, dextr_weights):
    import pathlib
    import json
    import uuid
    from image_labelling_tool import labelled_image, labelling_tool

    if enable_dextr or dextr_weights is not None:
        from dextr.model import DextrModel
        import torch

        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

        if dextr_weights is not None:
            dextr_weights = pathlib.Path(dextr_weights).expanduser()
            dextr_model = torch.load(dextr_weights, map_location=device)
        else:
            dextr_model = DextrModel.pascalvoc_resunet101().to(device)

        dextr_model.eval()

        dextr_fn = lambda image, points: dextr_model.predict([image], points[None, :, :])[0] >= 0.5
    else:
        dextr_fn = None


    # Colour schemes
    # The user may select different colour schemes for different tasks.
    # If you have a lot of classes, it will be difficult to select colours that are easily distinguished
    # from one another. For one task e.g. segmentation, design a colour scheme that highlights the different
    # classes for that task, while another task e.g. fine-grained classification would use another scheme.
    # Each colour scheme is a dictionary containing the following:
    #   name: symbolic name (Python identifier)
    #   human_name: human readable name for UI
    # These colour schemes are going to split the classes by 'default' (all), natural, and artificial.
    # Not really useful, but demonstrates the feature.
    colour_schemes = [
        dict(name='default', human_name='All'),
        dict(name='natural', human_name='Natural'),
        dict(name='artificial', human_name='Artifical')
    ]

    # Specify our label classes, organised in groups.
    # `LabelClass` parameters are:
    #   symbolic name (Python identifier)
    #   human readable name for UI
    #   and colours by colour scheme, as a dict mapping colour scheme name to RGB value as a list
    # The label classes are arranged in groups and will be displayed as such in the UI.
    # `LabelClassGroup` parameters are:
    #   human readable name for UI
    #   label class (`LabelClass` instance) list
    label_classes = [
        labelling_tool.LabelClassGroup('Natural', [
            labelling_tool.LabelClass('tree', 'Trees', dict(default=[0, 255, 192], natural=[0, 255, 192],
                                                            artificial=[128, 128, 128])),
            labelling_tool.LabelClass('lake', 'Lake', dict(default=[0, 128, 255], natural=[0, 128, 255],
                                                           artificial=[128, 128, 128])),
            labelling_tool.LabelClass('flower', 'Flower', dict(default=[255, 96, 192], natural=[255, 192, 96],
                                                               artificial=[128, 128, 128])),
            labelling_tool.LabelClass('leaf', 'Leaf', dict(default=[65, 255, 0], natural=[65, 255, 0],
                                                           artificial=[128, 128, 128])),
            labelling_tool.LabelClass('stem', 'Stem', dict(default=[128, 64, 0], natural=[128, 64, 0],
                                                           artificial=[128, 128, 128])),
        ]),
        labelling_tool.LabelClassGroup('Artificial', [
            labelling_tool.LabelClass('building', 'Buildings', dict(default=[255, 128, 0], natural=[128, 128, 128],
                                                                   artificial=[255, 128, 0])),
            labelling_tool.LabelClass('wall', 'Wall', dict(default=[0, 128, 255], natural=[128, 128, 128],
                                                           artificial=[0, 128, 255])),
        ])]

    # Annotation controls
    # Labels may also have optional meta-data associated with them
    # You could use this for e.g. indicating if an object is fully visible, mostly visible or significantly obscured.
    # You could also indicate quality (e.g. blurriness, etc)
    # There are four types of annotation. They have some common properties:
    #   - name: symbolic name (Python identifier)
    #   - label_text: label text in UI
    #   Check boxes, radio buttons and popup menus also have:
    #     - visibility_label_text: [optional] if provided, label visibility can be filtered by this annotation value,
    #       in which case a drop down will appear in the UI allowing the user to select a filter value
    #       that will hide/show labels accordingly
    # Control types:
    # Check box (boolean value):
    #   `labelling_tool.AnnoControlCheckbox`; only the 3 common parameters listed above
    # Radio button (choice from a list):
    #   `labelling_tool.AnnoControlRadioButtons`; the 3 common parameters listed above and:
    #       - choices: list of `labelling_tool.AnnoControlRadioButtons.choice` that provide:
    #           - value: symbolic value name for choice
    #           - tooltip: extra information for user
    #       - label_on_own_line [optional]: if True, place the label and the buttons on a separate line in the UI
    # Popup menu (choice from a grouped list):
    #   `labelling_tool.AnnoControlPopupMenu`; the 3 common parameters listed above and:
    #       - groups: list of groups `labelling_tool.AnnoControlPopupMenu.group`:
    #           - label_text: label text in UI
    #           - choices: list of `labelling_tool.AnnoControlPopupMenu.choice` that provide:
    #               - value: symbolic value name for choice
    #               - label_text: choice label text in UI
    #               - tooltip: extra information for user
    # Text (free form plain text):
    #   `labelling_tool.AnnoControlText`; only the 2 common parameters listed above and:
    #       - multiline: boolean; if True a text area will be used, if False a single line text entry
    anno_controls = [
        labelling_tool.AnnoControlCheckbox('good_quality', 'Good quality',
                                           visibility_label_text='Filter by good quality'),
        labelling_tool.AnnoControlRadioButtons('visibility', 'Visible', choices=[
            labelling_tool.AnnoControlRadioButtons.choice(value='full', label_text='Fully',
                                                          tooltip='Object is fully visible'),
            labelling_tool.AnnoControlRadioButtons.choice(value='mostly', label_text='Mostly',
                                                          tooltip='Object is mostly visible'),
            labelling_tool.AnnoControlRadioButtons.choice(value='obscured', label_text='Obscured',
                                                          tooltip='Object is significantly obscured'),
        ], label_on_own_line=False, visibility_label_text='Filter by visibility'),
        labelling_tool.AnnoControlPopupMenu('material', 'Material', groups=[
            labelling_tool.AnnoControlPopupMenu.group(label_text='Artifical/buildings', choices=[
                labelling_tool.AnnoControlPopupMenu.choice(value='concrete', label_text='Concrete',
                                                           tooltip='Concrete objects'),
                labelling_tool.AnnoControlPopupMenu.choice(value='plastic', label_text='Plastic',
                                                           tooltip='Plastic objects'),
                labelling_tool.AnnoControlPopupMenu.choice(value='asphalt', label_text='Asphalt',
                                                           tooltip='Road, pavement, etc.'),
            ]),
            labelling_tool.AnnoControlPopupMenu.group(label_text='Flat natural', choices=[
                labelling_tool.AnnoControlPopupMenu.choice(value='grass', label_text='Grass',
                                                           tooltip='Grass covered ground'),
                labelling_tool.AnnoControlPopupMenu.choice(value='water', label_text='Water', tooltip='Water/lake')]),
            labelling_tool.AnnoControlPopupMenu.group(label_text='Vegetation', choices=[
                labelling_tool.AnnoControlPopupMenu.choice(value='trees', label_text='Trees', tooltip='Trees'),
                labelling_tool.AnnoControlPopupMenu.choice(value='shrubbery', label_text='Shrubs',
                                                           tooltip='Shrubs/bushes'),
                labelling_tool.AnnoControlPopupMenu.choice(value='flowers', label_text='Flowers',
                                                           tooltip='Flowers'),
                labelling_tool.AnnoControlPopupMenu.choice(value='ivy', label_text='Ivy', tooltip='Ivy')]),
        ], visibility_label_text='Filter by material'),
        # labelling_tool.AnnoControlText('comment', 'Comment', multiline=False),
    ]

    image_pats = images_pat.split('|')

    # Load in .JPG images from the 'images' directory.
    labelled_images = labelled_image.LabelledImage.for_directory(
        images_dir, image_filename_patterns=image_pats, readonly=readonly)
    print('Loaded {0} images'.format(len(labelled_images)))

    if update_label_object_ids:
        n_updated = 0
        for limg in labelled_images:
            if limg.labels_store.labels_path.exists():
                label_js = json.load(limg.labels_store.labels_path.open('r'))
                prefix = str(uuid.uuid4())
                modified = labelling_tool.ensure_json_object_ids_have_prefix(
                    label_js, id_prefix=prefix)
                if modified:
                    with open(limg.labels_store.labels_path, 'w') as f_out:
                        json.dump(label_js, f_out, indent=3)
                    n_updated += 1
        print('Updated object IDs in {} files'.format(n_updated))



    # For documentation of the configuration, please see the comment above `labelling_tool.DEFAULT_CONFIG`
    config = labelling_tool.DEFAULT_CONFIG

    tasks = [
        dict(name='finished', human_name='[old] finished'),
        dict(name='segmentation', human_name='Outlines'),
        dict(name='classification', human_name='Classification'),
    ]

    flask_labeller(label_classes, labelled_images, tasks=tasks, colour_schemes=colour_schemes,
                   anno_controls=anno_controls, config=config, dextr_fn=dextr_fn)
def _labeller_window(app,
                     images_dir: pathlib.Path,
                     labels_dir: Optional[pathlib.Path],
                     schema_path: pathlib.Path,
                     readonly: bool,
                     enable_dextr: bool,
                     dextr_weights=Optional[pathlib.Path],
                     enable_firebug: bool = False,
                     use_http_memory_cache: bool = False):
    from image_labelling_tool import labelled_image, labelling_tool, labelling_schema

    server = web_server.LabellerServer()
    server.start_flask_server()

    try:
        # If DEXTR is to be made available
        if enable_dextr or dextr_weights is not None:
            from dextr.model import DextrModel
            import torch

            # Load the dextr model
            device = torch.device(
                "cuda:0" if torch.cuda.is_available() else "cpu")

            if dextr_weights is not None:
                dextr_weights = dextr_weights.expanduser()
                dextr_model = torch.load(dextr_weights, map_location=device)
            else:
                dextr_model = DextrModel.pascalvoc_resunet101().to(device)

            # Evaluation mode
            dextr_model.eval()

            # Define a mask prediction function
            dextr_fn = lambda image, points: dextr_model.predict(
                [image], points[None, :, :])[0] >= 0.5
        else:
            dextr_fn = None

        schema_store = labelling_schema.FileSchemaStore(schema_path,
                                                        readonly=readonly)

        # Annotation controls
        # Labels may also have optional meta-data associated with them
        # You could use this for e.g. indicating if an object is fully visible, mostly visible or significantly obscured.
        # You could also indicate quality (e.g. blurriness, etc)
        # There are four types of annotation. They have some common properties:
        #   - name: symbolic name (Python identifier)
        #   - label_text: label text in UI
        #   Check boxes, radio buttons and popup menus also have:
        #     - visibility_label_text: [optional] if provided, label visibility can be filtered by this annotation value,
        #       in which case a drop down will appear in the UI allowing the user to select a filter value
        #       that will hide/show labels accordingly
        # Control types:
        # Check box (boolean value):
        #   `labelling_tool.AnnoControlCheckbox`; only the 3 common parameters listed above
        # Radio button (choice from a list):
        #   `labelling_tool.AnnoControlRadioButtons`; the 3 common parameters listed above and:
        #       choices: list of `labelling_tool.AnnoControlRadioButtons.choice` that provide:
        #           value: symbolic value name for choice
        #           tooltip: extra information for user
        #       label_on_own_line [optional]: if True, place the label and the buttons on a separate line in the UI
        # Popup menu (choice from a grouped list):
        #   `labelling_tool.AnnoControlPopupMenu`; the 3 common parameters listed above and:
        #       groups: list of groups `labelling_tool.AnnoControlPopupMenu.group`:
        #           label_text: label text in UI
        #           choices: list of `labelling_tool.AnnoControlPopupMenu.choice` that provide:
        #               value: symbolic value name for choice
        #               label_text: choice label text in UI
        #               tooltip: extra information for user
        # Text (free form plain text):
        #   `labelling_tool.AnnoControlText`; only the 2 common parameters listed above and:
        #       - multiline: boolean; if True a text area will be used, if False a single line text entry
        anno_controls = [
            labelling_tool.AnnoControlCheckbox(
                'good_quality',
                'Good quality',
                visibility_label_text='Filter by good quality'),
            labelling_tool.AnnoControlRadioButtons(
                'visibility',
                'Visible',
                choices=[
                    labelling_tool.AnnoControlRadioButtons.choice(
                        value='full',
                        label_text='Fully',
                        tooltip='Object is fully visible'),
                    labelling_tool.AnnoControlRadioButtons.choice(
                        value='mostly',
                        label_text='Mostly',
                        tooltip='Object is mostly visible'),
                    labelling_tool.AnnoControlRadioButtons.choice(
                        value='obscured',
                        label_text='Obscured',
                        tooltip='Object is significantly obscured'),
                ],
                label_on_own_line=False,
                visibility_label_text='Filter by visibility'),
            labelling_tool.AnnoControlPopupMenu(
                'material',
                'Material',
                groups=[
                    labelling_tool.AnnoControlPopupMenu.group(
                        label_text='Artifical/buildings',
                        choices=[
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='concrete',
                                label_text='Concrete',
                                tooltip='Concrete objects'),
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='plastic',
                                label_text='Plastic',
                                tooltip='Plastic objects'),
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='asphalt',
                                label_text='Asphalt',
                                tooltip='Road, pavement, etc.'),
                        ]),
                    labelling_tool.AnnoControlPopupMenu.group(
                        label_text='Flat natural',
                        choices=[
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='grass',
                                label_text='Grass',
                                tooltip='Grass covered ground'),
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='water',
                                label_text='Water',
                                tooltip='Water/lake')
                        ]),
                    labelling_tool.AnnoControlPopupMenu.group(
                        label_text='Vegetation',
                        choices=[
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='trees',
                                label_text='Trees',
                                tooltip='Trees'),
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='shrubbery',
                                label_text='Shrubs',
                                tooltip='Shrubs/bushes'),
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='flowers',
                                label_text='Flowers',
                                tooltip='Flowers'),
                            labelling_tool.AnnoControlPopupMenu.choice(
                                value='ivy', label_text='Ivy', tooltip='Ivy')
                        ]),
                ],
                visibility_label_text='Filter by material'),
            # labelling_tool.AnnoControlText('comment', 'Comment', multiline=False),
        ]

        image_paths = list(images_dir.glob('*.jpg')) + list(
            images_dir.glob('*.png'))
        image_paths = [p.absolute() for p in image_paths]

        # Create a `PersistentLabelledImage` instance for each image file
        labelled_images = labelled_image.LabelledImage.for_image_files(
            image_paths, labels_dir=labels_dir, readonly=bool(readonly))
        print('Loaded {0} images'.format(len(labelled_images)))

        config = web_server.DEFAULT_CONFIG

        # Example tasks to appear in checkboxes
        tasks = [
            dict(name='finished', human_name='[old] finished'),
            dict(name='segmentation', human_name='Outlines'),
            dict(name='classification', human_name='Classification'),
        ]

        tool = Tool(server=server,
                    labelled_images=labelled_images,
                    schema_store=schema_store,
                    tasks=tasks,
                    anno_controls=anno_controls,
                    config=config,
                    dextr_fn=dextr_fn,
                    enable_firebug=enable_firebug,
                    use_http_memory_cache=use_http_memory_cache)

        # Show the window and run the app
        tool.open_labeller()

        app.exec_()
    finally:
        print('Stopping server')
        server.stop_server()