コード例 #1
0
def visualizer(request):
    logged_in = True
    image_descriptors = [
        labelling_tool.image_descriptor(image_id=img.id,
                                        url=img.image.url,
                                        width=img.image.width,
                                        height=img.image.height)
        for img in models.ImageWithLabels.objects.all()
    ]

    # Convert the label class tuples in `settings` to `labelling_tool.LabelClass` instances
    label_classes = [
        labelling_tool.LabelClass(*c) for c in settings.LABEL_CLASSES
    ]

    # list example / demonstration images
    image_path = os.path.join(settings.STATIC_ROOT, 'example_images')
    image_dir_files = os.listdir(image_path)

    context = {
        'label_classes': [c.to_json() for c in label_classes],
        'image_descriptors': image_descriptors,
        'initial_image_index': 0,
        'labelling_tool_config': settings.LABELLING_TOOL_CONFIG,
        'example_images': image_dir_files,
        'logged_in': logged_in,
    }
    return render(request, 'visualizer.html', context)
コード例 #2
0
def refresh():
        # `LabelClass` parameters are: symbolic name, human readable name for UI, and RGB colour as list
        with open(args.label_names, 'r') as f:
            label_names = yaml.load(f)

        cmap = plt.get_cmap('nipy_spectral')
        colors = [(np.array(cmap(i)[:3]) * 255).astype(np.int32).tolist()
                for i in range(1, len(label_names) + 1)]
        global label_classes
        label_classes = [labelling_tool.LabelClass(name, name, color)
                        for color, name in zip(colors, label_names)]

        img_dir = args.image_dir
        '''
        if args.slic:

            for path in glob.glob(os.path.join(img_dir, '*{}'.format(file_ext))):
                name = os.path.splitext(path)[0]
                out_name = name + '__labels.json'
                if os.path.exists(out_name):
                    print('Label already exits at {}'.format(out_name))
                    # raise ValueError
                    continue

                print('Segmenting {0}'.format(path))
                img = plt.imread(path)
                # slic_labels = slic(img, 1000, compactness=20.0)
                # slic_labels = slic(img, 1000, slic_zero=True) + 1
                slic_labels = slic(img, 1000, slic_zero=True) + 1

                print('Converting SLIC labels to vector labels...')
                labels = labelling_tool.ImageLabels.from_label_image(slic_labels)

                with open(out_name, 'w') as f:
                    json.dump(labels.labels_json, f)
'''
        readonly = args.readonly
        # Load in .JPG images from the 'images' directory.
        labelled_images = labelling_tool.PersistentLabelledImage.for_directory(
            img_dir, image_filename_pattern='*{}'.format(file_ext),
            readonly=readonly)
        print('Loaded {0} images'.format(len(labelled_images)))

        # Generate image IDs list
        image_ids = [str(i) for i in range(len(labelled_images))]
        # Generate images table mapping image ID to image so we can get an image by ID
        global images_table
        images_table = {image_id: img for image_id, img in zip(image_ids, labelled_images)}
        # Generate image descriptors list to hand over to the labelling tool
        # Each descriptor provides the image ID, the URL and the size
        global image_descriptors
        image_descriptors = []
        for image_id, img in zip(image_ids, labelled_images):
            data, mimetype, width, height = img.data_and_mime_type_and_size()
            image_descriptors.append(labelling_tool.image_descriptor(
                image_id=image_id, url=args.prefix+'/image/{}'.format(image_id),
                width=width, height=height
            ))
コード例 #3
0
def home(request):
    image_descriptors = [labelling_tool.image_descriptor(
            image_id=img.id, url=img.image.url,
            width=img.image.width, height=img.image.height) for img in models.ImageWithLabels.objects.all()]

    # Convert the label class tuples in `settings` to `labelling_tool.LabelClass` instances
    label_classes = [labelling_tool.LabelClass(*c) for c in settings.LABEL_CLASSES]

    context = {
        'label_classes': [c.to_json()   for c in label_classes],
        'image_descriptors': image_descriptors,
        'initial_image_index': 0,
        'labelling_tool_config': settings.LABELLING_TOOL_CONFIG,
    }
    return render(request, 'index.html', context)
コード例 #4
0
ファイル: views.py プロジェクト: biggie-inc/django-labeller
def tool(request):
    image_descriptors = [
        labelling_tool.image_descriptor(image_id=img.id,
                                        url=img.image.url,
                                        width=img.image.width,
                                        height=img.image.height)
        for img in models.ImageWithLabels.objects.all()
    ]

    context = {
        'colour_schemes': settings.LABEL_COLOUR_SCHEMES,
        'label_class_groups': [g.to_json() for g in settings.LABEL_CLASSES],
        'image_descriptors': image_descriptors,
        'initial_image_index': str(0),
        'labelling_tool_config': settings.LABELLING_TOOL_CONFIG,
        'anno_controls': [c.to_json() for c in settings.ANNO_CONTROLS],
        'enable_locking': settings.LABELLING_TOOL_ENABLE_LOCKING,
        'dextr_available': settings.LABELLING_TOOL_DEXTR_AVAILABLE,
        'dextr_polling_interval':
        settings.LABELLING_TOOL_DEXTR_POLLING_INTERVAL,
    }
    return render(request, 'tool.html', context)
コード例 #5
0
ファイル: views.py プロジェクト: chunmusic/django-labeller
def tool(request):
    image_descriptors = [
        labelling_tool.image_descriptor(image_id=img.id,
                                        url=img.image.url,
                                        width=img.image.width,
                                        height=img.image.height)
        for img in models.ImageWithLabels.objects.all()
    ]

    try:
        schema = lt_models.LabellingSchema.objects.get(name='default')
    except lt_models.LabellingSchema.DoesNotExist:
        schema_js = dict(colour_schemes=[], label_class_groups=[])
    else:
        schema_js = schema.json_for_tool()

    context = {
        'labelling_schema':
        schema_js,
        'image_descriptors':
        image_descriptors,
        'initial_image_index':
        str(0),
        'labelling_tool_config':
        settings.LABELLING_TOOL_CONFIG,
        'tasks':
        lt_models.LabellingTask.objects.filter(
            enabled=True).order_by('order_key'),
        'anno_controls': [c.to_json() for c in settings.ANNO_CONTROLS],
        'enable_locking':
        settings.LABELLING_TOOL_ENABLE_LOCKING,
        'dextr_available':
        settings.LABELLING_TOOL_DEXTR_AVAILABLE,
        'dextr_polling_interval':
        settings.LABELLING_TOOL_DEXTR_POLLING_INTERVAL,
    }
    return render(request, 'tool.html', context)
コード例 #6
0
    def __init__(self,
                 server,
                 labelled_images,
                 schema,
                 tasks=None,
                 colour_schemes=None,
                 anno_controls=None,
                 config=None,
                 dextr_fn=None,
                 enable_firebug=False):
        """
        :param server: the `web_server.LabellerServer` instance that manages the Flask server.
        :param label_classes: grouped label classes that will be passed to the tool
        :param labelled_images: a list of labelled images to edit (see `labelling_tool.AbstractLabelledImage`)
        :param tasks: [optional] a list of tasks for the user to check when they are done
        :param colour_schemes: [optional] the list of colour schemes for display
        :param anno_controls: [optional] additional annotation controls for metadata
        :param config: [optional] labelling tool configuration
        :param dextr_fn: [optional] DEXTR prediction function
        :param enable_firebug: [default=False] if True, load Firebug-lite development tools
        """
        super(QLabellerForLabelledImages,
              self).__init__(server=server,
                             schema=schema,
                             tasks=tasks,
                             anno_controls=anno_controls,
                             config=config,
                             enable_firebug=enable_firebug)

        self._dextr_fn = dextr_fn

        # Generate image IDs list
        image_ids = [
            '{}__{}'.format(self._tool_id, i)
            for i in range(len(labelled_images))
        ]
        # Generate images table mapping image ID to image so we can get an image by ID
        images_table = {
            image_id: img
            for image_id, img in zip(image_ids, labelled_images)
        }
        # Generate image descriptors list to hand over to the labelling tool
        # Each descriptor provides the image ID, the URL and the size
        self.__image_descriptors = []
        for image_id, img in zip(image_ids, labelled_images):
            height, width = img.image_source.image_size
            local_path = img.image_source.local_path
            if local_path is not None:
                self._server_pipe.add_image(
                    image_id,
                    web_server._ImagePath(path=str(local_path.absolute()),
                                          width=width,
                                          height=height))
            else:
                data, mime_type = img.image_source.image_binary_and_mime_type()
                self._server_pipe.add_image(
                    image_id,
                    web_server._ImageBinary(data=data,
                                            mime_type=mime_type,
                                            width=width,
                                            height=height))
            self.__image_descriptors.append(
                labelling_tool.image_descriptor(
                    image_id=image_id,
                    url='/image/{}'.format(image_id),
                    width=width,
                    height=height))
        self.__images_table = images_table
コード例 #7
0
def flask_labeller(labelled_images,
                   label_classes,
                   config=None,
                   use_reloader=True,
                   debug=True):
    import json
    import flask

    from flask import Flask, render_template, request, make_response, send_from_directory
    import flask_login

    try:
        from flask_socketio import SocketIO, emit as socketio_emit
    except ImportError:
        SocketIO = None
        socketio_emit = None

    from image_labelling_tool import labelling_tool

    # Generate image IDs list
    image_ids = [str(i) for i in range(len(labelled_images))]
    # Generate images table mapping image ID to image so we can get an image by ID
    images_table = {
        image_id: img
        for image_id, img in zip(image_ids, labelled_images)
    }
    # Generate image descriptors list to hand over to the labelling tool
    # Each descriptor provides the image ID, the URL and the size
    image_descriptors = []
    for image_id, img in zip(image_ids, labelled_images):
        height, width = img.image_size
        image_descriptors.append(
            labelling_tool.image_descriptor(image_id=image_id,
                                            url='/image/{}'.format(image_id),
                                            width=width,
                                            height=height))

    app = Flask(__name__, static_folder='static')
    app.secret_key = 'super secret string'

    login_manager = flask_login.LoginManager()
    login_manager.init_app(app)

    users = {'atkins_annotator': {'password': '******'}}

    class User(flask_login.UserMixin):
        pass

    @login_manager.user_loader
    def user_loader(email):
        if email not in users:
            return

        user = User()
        user.id = email
        return user

    @login_manager.request_loader
    def request_loader(request):
        email = request.form.get('email')
        if email not in users or request.form['password'] != users[email][
                'password']:
            return

        user = User()
        user.id = email

        # DO NOT ever store passwords in plaintext and always compare password
        # hashes using constant-time comparison!
        user.is_authenticated = request.form['password'] == users[email][
            'password']
        return user

    if SocketIO is not None:
        print('Using web sockets')
        socketio = SocketIO(app)
    else:
        socketio = None

    if config is None:
        config = {
            'tools': {
                'imageSelector': True,
                'labelClassSelector': True,
                'labelClassFilterInitial': None,
                'drawPolyLabel': True,
                'compositeLabel': True,
                'deleteLabel': True,
                'deleteConfig': {
                    'typePermissions': {
                        'point': True,
                        'box': True,
                        'polygon': True,
                        'composite': True,
                        'group': True,
                    }
                }
            }
        }

    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if flask.request.method == 'GET':
            return render_template('login.html')

        email = flask.request.form['email']

        if email not in users:
            return render_template('login.html')

        if flask.request.form['password'] == users[email]['password']:
            user = User()
            user.id = email
            flask_login.login_user(user)
            return flask.redirect(flask.url_for('index'))
        else:
            return render_template('login.html')

    @app.route('/logout')
    def logout():
        flask_login.logout_user()
        return render_template('login.html')

    @login_manager.unauthorized_handler
    def unauthorized_handler():
        return render_template('login.html')

    @app.route('/')
    @flask_login.login_required
    def index():
        label_classes_json = [(cls.to_json() if isinstance(
            cls, labelling_tool.LabelClassGroup) else cls)
                              for cls in label_classes]
        return render_template('labeller_page.jinja2',
                               tool_js_urls=labelling_tool.js_file_urls(
                                   '/static/labelling_tool/'),
                               label_classes=json.dumps(label_classes_json),
                               image_descriptors=json.dumps(image_descriptors),
                               initial_image_index=0,
                               config=json.dumps(config),
                               use_websockets=socketio is not None)

    if socketio is not None:

        @socketio.on('get_labels')
        def handle_get_labels(arg_js):
            image_id = arg_js['image_id']

            image = images_table[image_id]

            labels, complete = image.get_label_data_for_tool()

            label_header = dict(labels=labels,
                                image_id=image_id,
                                complete=complete)

            socketio_emit('get_labels_reply', label_header)

        @socketio.on('set_labels')
        def handle_set_labels(arg_js):
            label_header = arg_js['label_header']

            image_id = label_header['image_id']

            image = images_table[image_id]

            image.set_label_data_from_tool(label_header['labels'],
                                           label_header['complete'])

            socketio_emit('set_labels_reply', '')

    else:

        @app.route('/labelling/get_labels/<image_id>')
        @flask_login.login_required
        def get_labels(image_id):
            image = images_table[image_id]

            labels = image.labels_json
            complete = False

            label_header = {
                'labels': labels,
                'image_id': image_id,
                'complete': complete
            }

            r = make_response(json.dumps(label_header))
            r.mimetype = 'application/json'
            return r

        @app.route('/labelling/set_labels', methods=['POST'])
        @flask_login.login_required
        def set_labels():
            label_header = json.loads(request.form['labels'])
            image_id = label_header['image_id']
            complete = label_header['complete']
            labels = label_header['labels']

            image = images_table[image_id]
            image.labels_json = labels

            return make_response('')

    @app.route('/image/<image_id>')
    @flask_login.login_required
    def get_image(image_id):
        image = images_table[image_id]
        data, mimetype, width, height = image.data_and_mime_type_and_size()
        r = make_response(data)
        r.mimetype = mimetype
        return r

    @app.route('/ext_static/<path:filename>')
    @flask_login.login_required
    def base_static(filename):
        return send_from_directory(app.root_path + '/../ext_static/', filename)

    if socketio is not None:
        socketio.run(app,
                     host="0.0.0.0",
                     port=5000,
                     debug=debug,
                     use_reloader=use_reloader)
    else:
        app.run(host="0.0.0.0",
                port=5000,
                debug=debug,
                use_reloader=use_reloader)
コード例 #8
0
def flask_labeller_and_schema_editor(
        labelled_images: Sequence[labelled_image.LabelledImage],
        schema_store: labelling_schema.SchemaStore,
        tasks: Optional[Sequence[Any]] = None,
        anno_controls: Optional[Sequence[Any]] = None,
        config: Optional[Mapping[str, Any]] = None,
        dextr_fn: Optional[DextrFunctionType] = None,
        use_reloader: bool = True,
        debug: bool = True,
        port: Optional[int] = None):
    vue_tmpl_path = pathlib.Path(
        __file__
    ).parent / 'templates' / 'inline' / 'schema_editor_vue_templates.html'

    # Generate image IDs list
    image_ids = [str(i) for i in range(len(labelled_images))]
    # Generate images table mapping image ID to image so we can get an image by ID
    images_table = {
        image_id: img
        for image_id, img in zip(image_ids, labelled_images)
    }
    # Generate image descriptors list to hand over to the labelling tool
    # Each descriptor provides the image ID, the URL and the size
    image_descriptors = []
    for image_id, img in zip(image_ids, labelled_images):
        height, width = img.image_source.image_size
        image_descriptors.append(
            labelling_tool.image_descriptor(image_id=image_id,
                                            url='/image/{}'.format(image_id),
                                            width=width,
                                            height=height))

    app = Flask(__name__, static_folder='static')
    if SocketIO is not None:
        print('Using web sockets')
        socketio = SocketIO(app)
    else:
        socketio = None

    if config is None:
        config = labelling_tool.DEFAULT_CONFIG

    @app.route('/')
    def index():
        return render_template(
            'index.jinja2',
            num_images=len(image_descriptors),
        )

    @app.route('/labeller')
    def labeller():
        schema_json = schema_store.get_schema_json()
        if anno_controls is not None:
            anno_controls_json = [c.to_json() for c in anno_controls]
        else:
            anno_controls_json = []
        return render_template('labeller_page.jinja2',
                               labelling_schema=schema_json,
                               tasks=tasks,
                               image_descriptors=image_descriptors,
                               initial_image_index=0,
                               anno_controls=anno_controls_json,
                               labelling_tool_config=config,
                               dextr_available=dextr_fn is not None,
                               use_websockets=socketio is not None)

    @app.route('/schema_editor')
    def schema_editor():
        schema_editor_vue_templates_html = vue_tmpl_path.open().read()

        return render_template(
            'schema_editor_page.jinja2',
            schema=schema_store.get_schema_json(),
            schema_editor_vue_templates_html=schema_editor_vue_templates_html)

    _register_labeller_routes(app, socketio, socketio_emit, images_table,
                              dextr_fn)
    _register_schema_editor_routes(app, socketio, socketio_emit, schema_store)

    if socketio is not None:
        socketio.run(app, debug=debug, port=port, use_reloader=use_reloader)
    else:
        app.run(debug=debug, port=port, use_reloader=use_reloader)
コード例 #9
0
def flask_labeller(labelled_images, label_classes, config=None):
    import json

    from flask import Flask, render_template, request, make_response, send_from_directory
    try:
        from flask_socketio import SocketIO, emit as socketio_emit
    except ImportError:
        SocketIO = None
        socketio_emit = None

    from image_labelling_tool import labelling_tool

    # Generate image IDs list
    image_ids = [str(i) for i in range(len(labelled_images))]
    # Generate images table mapping image ID to image so we can get an image by ID
    images_table = {
        image_id: img
        for image_id, img in zip(image_ids, labelled_images)
    }
    # Generate image descriptors list to hand over to the labelling tool
    # Each descriptor provides the image ID, the URL and the size
    image_descriptors = []
    for image_id, img in zip(image_ids, labelled_images):
        height, width = img.image_size
        image_descriptors.append(
            labelling_tool.image_descriptor(image_id=image_id,
                                            url='/image/{}'.format(image_id),
                                            width=width,
                                            height=height))

    app = Flask(__name__, static_folder='static')
    if SocketIO is not None:
        print('Using web sockets')
        socketio = SocketIO(app)
    else:
        socketio = None

    if config is None:
        config = {
            'tools': {
                'imageSelector': True,
                'labelClassSelector': True,
                'drawPolyLabel': True,
                'compositeLabel': True,
                'deleteLabel': True,
                'deleteConfig': {
                    'typePermissions': {
                        'point': True,
                        'box': True,
                        'polygon': True,
                        'composite': True,
                        'group': True,
                    }
                }
            }
        }

    @app.route('/')
    def index():
        label_classes_json = [cls.to_json() for cls in label_classes]
        return render_template('labeller_page.jinja2',
                               tool_js_urls=labelling_tool.js_file_urls(
                                   '/static/labelling_tool/'),
                               label_classes=json.dumps(label_classes_json),
                               image_descriptors=json.dumps(image_descriptors),
                               initial_image_index=0,
                               config=json.dumps(config),
                               use_websockets=socketio is not None)

    if socketio is not None:

        @socketio.on('get_labels')
        def handle_get_labels(arg_js):
            image_id = arg_js['image_id']

            image = images_table[image_id]

            labels, complete = image.get_label_data_for_tool()

            label_header = dict(labels=labels,
                                image_id=image_id,
                                complete=complete)

            socketio_emit('get_labels_reply', label_header)

        @socketio.on('set_labels')
        def handle_set_labels(arg_js):
            label_header = arg_js['label_header']

            image_id = label_header['image_id']

            image = images_table[image_id]

            image.set_label_data_from_tool(label_header['labels'],
                                           label_header['complete'])

            socketio_emit('set_labels_reply', '')

    else:

        @app.route('/labelling/get_labels/<image_id>')
        def get_labels(image_id):
            image = images_table[image_id]

            labels = image.labels_json
            complete = False

            label_header = {
                'labels': labels,
                'image_id': image_id,
                'complete': complete
            }

            r = make_response(json.dumps(label_header))
            r.mimetype = 'application/json'
            return r

        @app.route('/labelling/set_labels', methods=['POST'])
        def set_labels():
            label_header = json.loads(request.form['labels'])
            image_id = label_header['image_id']
            complete = label_header['complete']
            labels = label_header['labels']

            image = images_table[image_id]
            image.labels_json = labels

            return make_response('')

    @app.route('/image/<image_id>')
    def get_image(image_id):
        image = images_table[image_id]
        data, mimetype, width, height = image.data_and_mime_type_and_size()
        r = make_response(data)
        r.mimetype = mimetype
        return r

    @app.route('/ext_static/<path:filename>')
    def base_static(filename):
        return send_from_directory(app.root_path + '/../ext_static/', filename)

    if socketio is not None:
        socketio.run(app, debug=True)
    else:
        app.run(debug=True)
コード例 #10
0
def home(request):
    #print("request META:", request.META)
    #request_str = "request - 'USERNAME':"******"; REMOTE_ADDR:" +  request.META['REMOTE_ADDR']
    #logger.info(request.META)
    # Force Log out the user if his browser has save the session data and he is being automatically logged in.
    logout(request)
    logged_in = False
    query_string = ''
    assignmentId = 'NOT_SET'
    preview_mode = True

    mturk_urls = ['workersandbox.mturk.com', 'worker.mturk.com']

    try:
        # Check if the request comes from either Sandbox or the production Mturk.
        if any(x in request.META['HTTP_REFERER'] for x in mturk_urls):
            query_string = request.META['QUERY_STRING']
            assignmentId = query_string.split('assignmentId=')[1].split('&')[0]
            log_str = "assignmentId:" + assignmentId
            logger.info(log_str)
            try:
                if 'ASSIGNMENT_ID_NOT_AVAILABLE' not in assignmentId:
                    workerId = query_string.split('workerId=')[1].split('&')[0]
                    log_str = "workerId:" + workerId
                    logger.info(log_str)
                    preview_mode = False
                    if not User.objects.filter(username=workerId).exists():
                        logger.info("New user was created")
                        user = User.objects.create_user(
                            username=workerId, password='******')
                        user.save()
                        user = authenticate(username=workerId,
                                            password='******')
                        login(request, user)
                        logged_in = True
                    else:
                        logger.info("User was logged in")
                        user = authenticate(username=workerId,
                                            password='******')
                        login(request, user)
                        logged_in = True

            except:
                logger.warning("Something went wrong with user authentication")
    except:
        logger.warning("The request from a non AMT address was made.")

    image_descriptors = [
        labelling_tool.image_descriptor(image_id=img.id,
                                        url=img.image.url,
                                        width=img.image.width,
                                        height=img.image.height)
        for img in models.ImageWithLabels.objects.all()
    ]

    # Convert the label class tuples in `settings` to `labelling_tool.LabelClass` instances
    label_classes = [
        labelling_tool.LabelClass(*c) for c in settings.LABEL_CLASSES
    ]

    #list example / demonstration images
    image_path = os.path.join(settings.STATIC_ROOT, 'example_images')
    image_dir_files = os.listdir(image_path)

    context = {
        'label_classes': [c.to_json() for c in label_classes],
        'image_descriptors': image_descriptors,
        'initial_image_index': 0,
        'labelling_tool_config': settings.LABELLING_TOOL_CONFIG,
        'example_images': image_dir_files,
        'assignmentId': assignmentId,
        'preview_mode': preview_mode,
        'logged_in': logged_in,
    }
    return render(request, 'index.html', context)
コード例 #11
0
    # Generate image IDs list
    image_ids = [str(i) for i in range(len(labelled_images))]
    # Generate images table mapping image ID to image so we can get an image by ID
    images_table = {
        image_id: img
        for image_id, img in zip(image_ids, labelled_images)
    }
    # Generate image descriptors list to hand over to the labelling tool
    # Each descriptor provides the image ID, the URL and the size
    image_descriptors = []
    for image_id, img in zip(image_ids, labelled_images):
        data, mimetype, width, height = img.data_and_mime_type_and_size()
        image_descriptors.append(
            labelling_tool.image_descriptor(image_id=image_id,
                                            url='/image/{}'.format(image_id),
                                            width=width,
                                            height=height))

    app = Flask(__name__, static_folder='image_labelling_tool/static')
    config = {
        'tools': {
            'imageSelector': True,
            'labelClassSelector': True,
            'drawPolyLabel': True,
            'compositeLabel': True,
            'deleteLabel': True,
        }
    }

    @app.route('/')
    def index():
コード例 #12
0
def flask_labeller(label_classes,
                   labelled_images,
                   tasks=None,
                   colour_schemes=None,
                   anno_controls=None,
                   config=None,
                   dextr_fn=None,
                   use_reloader=True,
                   debug=True,
                   port=None):
    import json
    import uuid
    import numpy as np

    from flask import Flask, render_template, request, make_response, send_from_directory
    try:
        from flask_socketio import SocketIO, emit as socketio_emit
    except ImportError:
        SocketIO = None
        socketio_emit = None

    from image_labelling_tool import labelling_tool

    # Generate image IDs list
    image_ids = [str(i) for i in range(len(labelled_images))]
    # Generate images table mapping image ID to image so we can get an image by ID
    images_table = {
        image_id: img
        for image_id, img in zip(image_ids, labelled_images)
    }
    # Generate image descriptors list to hand over to the labelling tool
    # Each descriptor provides the image ID, the URL and the size
    image_descriptors = []
    for image_id, img in zip(image_ids, labelled_images):
        height, width = img.image_size
        image_descriptors.append(
            labelling_tool.image_descriptor(image_id=image_id,
                                            url='/image/{}'.format(image_id),
                                            width=width,
                                            height=height))

    app = Flask(__name__, static_folder='static')
    if SocketIO is not None:
        print('Using web sockets')
        socketio = SocketIO(app)
    else:
        socketio = None

    def apply_dextr_js(image, dextr_points_js):
        pixels = image.read_pixels()
        dextr_points = np.array([[p['y'], p['x']] for p in dextr_points_js])
        if dextr_fn is not None:
            mask = dextr_fn(pixels, dextr_points)
            regions = labelling_tool.PolygonLabel.mask_image_to_regions_cv(
                mask, sort_decreasing_area=True)
            regions_js = labelling_tool.PolygonLabel.regions_to_json(regions)
            return regions_js
        else:
            return []

    if config is None:
        config = {
            'useClassSelectorPopup': True,
            'tools': {
                'imageSelector': True,
                'labelClassSelector': True,
                'labelClassFilterInitial': None,
                'drawPolyLabel': True,
                'compositeLabel': False,
                'deleteLabel': True,
                'deleteConfig': {
                    'typePermissions': {
                        'point': True,
                        'box': True,
                        'polygon': True,
                        'composite': True,
                        'group': True,
                    }
                }
            }
        }

    if tasks is None:
        tasks = [dict(identifier='finished', human_name='Finished')]

    @app.route('/')
    def index():
        label_classes_json = [(cls.to_json() if isinstance(
            cls, labelling_tool.LabelClassGroup) else cls)
                              for cls in label_classes]
        if anno_controls is not None:
            anno_controls_json = [c.to_json() for c in anno_controls]
        else:
            anno_controls_json = []
        return render_template('labeller_page.jinja2',
                               tasks=tasks,
                               colour_schemes=colour_schemes,
                               label_class_groups=label_classes_json,
                               image_descriptors=image_descriptors,
                               initial_image_index=0,
                               anno_controls=anno_controls_json,
                               labelling_tool_config=config,
                               dextr_available=dextr_fn is not None,
                               use_websockets=socketio is not None)

    if socketio is not None:

        @socketio.on('get_labels')
        def handle_get_labels(arg_js):
            image_id = arg_js['image_id']

            image = images_table[image_id]

            labels, completed_tasks = image.get_label_data_for_tool()

            label_header = dict(
                image_id=image_id,
                labels=labels,
                completed_tasks=completed_tasks,
                timeElapsed=0.0,
                state='editable',
                session_id=str(uuid.uuid4()),
            )

            socketio_emit('get_labels_reply', label_header)

        @socketio.on('set_labels')
        def handle_set_labels(arg_js):
            label_header = arg_js['label_header']

            image_id = label_header['image_id']

            image = images_table[image_id]

            image.set_label_data_from_tool(label_header['labels'],
                                           label_header['completed_tasks'])

            socketio_emit('set_labels_reply', '')

        @socketio.on('dextr')
        def handle_dextr(dextr_js):
            if 'request' in dextr_js:
                dextr_request_js = dextr_js['request']
                image_id = dextr_request_js['image_id']
                dextr_id = dextr_request_js['dextr_id']
                dextr_points = dextr_request_js['dextr_points']

                image = images_table[image_id]

                regions_js = apply_dextr_js(image, dextr_points)

                dextr_labels = dict(image_id=image_id,
                                    dextr_id=dextr_id,
                                    regions=regions_js)
                dextr_reply = dict(labels=[dextr_labels])

                socketio_emit('dextr_reply', dextr_reply)
            elif 'poll' in dextr_js:
                dextr_reply = dict(labels=[])
                socketio_emit('dextr_reply', dextr_reply)
            else:
                dextr_reply = {'error': 'unknown_command'}
                socketio_emit('dextr_reply', dextr_reply)

    else:

        @app.route('/labelling/get_labels/<image_id>')
        def get_labels(image_id):
            image = images_table[image_id]
            labels, completed_tasks = image.get_label_data_for_tool()

            label_header = {
                'image_id': image_id,
                'labels': labels,
                'completed_tasks': completed_tasks,
                'timeElapsed': 0.0,
                'state': 'editable',
                'session_id': str(uuid.uuid4()),
            }

            r = make_response(json.dumps(label_header))
            r.mimetype = 'application/json'
            return r

        @app.route('/labelling/set_labels', methods=['POST'])
        def set_labels():
            label_header = json.loads(request.form['labels'])
            image_id = label_header['image_id']

            image = images_table[image_id]

            image.set_label_data_from_tool(label_header['labels'],
                                           label_header['completed_tasks'])

            return make_response('')

        @app.route('/labelling/dextr', methods=['POST'])
        def dextr():
            dextr_js = json.loads(request.form['dextr'])
            if 'request' in dextr_js:
                dextr_request_js = dextr_js['request']
                image_id = dextr_request_js['image_id']
                dextr_id = dextr_request_js['dextr_id']
                dextr_points = dextr_request_js['dextr_points']

                image = images_table[image_id]
                regions_js = apply_dextr_js(image, dextr_points)

                dextr_labels = dict(image_id=image_id,
                                    dextr_id=dextr_id,
                                    regions=regions_js)
                dextr_reply = dict(labels=[dextr_labels])

                return make_response(json.dumps(dextr_reply))
            elif 'poll' in dextr_js:
                dextr_reply = dict(labels=[])
                return make_response(json.dumps(dextr_reply))
            else:
                return make_response(json.dumps({'error': 'unknown_command'}))

    @app.route('/image/<image_id>')
    def get_image(image_id):
        image = images_table[image_id]
        data, mimetype, width, height = image.data_and_mime_type_and_size()
        r = make_response(data)
        r.mimetype = mimetype
        return r

    if socketio is not None:
        socketio.run(app, debug=debug, port=port, use_reloader=use_reloader)
    else:
        app.run(debug=debug, port=port, use_reloader=use_reloader)