Web platform for sharing free data for ML and research

By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

Send annotations to server

roundabout,
created on Wednesday, 4 September 2024, 16:44:59 (1725468299), received on Thursday, 5 September 2024, 07:25:39 (1725521139)
Author identity: vlad <vlad.muntoiu@gmail.com>

424bf305a78ccf73dd8f754c948ca462df417940

.idea/markdown.xml

@@ -0,0 +1,7 @@

                                
                                
                                
                            
                                
                                    
                                        
                                        <?xml version="1.0" encoding="UTF-8"?>
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        <project version="4">
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          <component name="MarkdownSettings">
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            <option name="customStylesheetText" value="pre, code {&#10;    font-family: monospace;&#10;}" />
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            <option name="useCustomStylesheetText" value="true" />
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          </component>
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        </project>
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                            
                                

app.py

@@ -40,6 +40,7 @@ with app.app_context():

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    username = db.Column(db.String(32), unique=True, nullable=False, primary_key=True)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    password_hashed = db.Column(db.String(60), nullable=False)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    admin = db.Column(db.Boolean, nullable=False, default=False, server_default="false")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                pictures = db.relationship("PictureResource", back_populates="author")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    def __init__(self, username, password):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.username = username
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -140,7 +141,7 @@ with app.app_context():

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    json = db.Column(sqlalchemy.dialects.postgresql.JSONB, nullable=False)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    resource_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), nullable=False)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                object_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"), nullable=False)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                object_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"), nullable=True)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    resource = db.relationship("PictureResource", backref="regions")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    object = db.relationship("PictureObject", backref="regions")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -158,6 +159,8 @@ with app.app_context():

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    width = db.Column(db.Integer, nullable=False)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    height = db.Column(db.Integer, nullable=False)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    nature_id = db.Column(db.String(32), db.ForeignKey("picture_nature.id"), nullable=True)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                author_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                author = db.relationship("User", back_populates="pictures")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    nature = db.relationship("PictureNature", back_populates="resources")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -172,9 +175,10 @@ with app.app_context():

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    licences = db.relationship("PictureLicence", back_populates="resource")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                def __init__(self, title, description, origin_url, licence_ids, mime, nature=None,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                def __init__(self, title, author, description, origin_url, licence_ids, mime, nature=None,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                 replaces=None):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.title = title
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    self.author = author
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.description = description
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.origin_url = origin_url
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        self.file_format = mime
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -287,6 +291,7 @@ def upload_post():

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                title = flask.request.form["title"]
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                description = flask.request.form["description"]
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                origin_url = flask.request.form["origin_url"]
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            author = db.session.get(User, flask.session.get("username"))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                file = flask.request.files["file"]
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -294,7 +299,7 @@ def upload_post():

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    flask.flash("No selected file")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    return flask.redirect(flask.request.url)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            resource = PictureResource(title, description, origin_url, ["CC0-1.0"], file.mimetype)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            resource = PictureResource(title, author, description, origin_url, ["CC0-1.0"], file.mimetype)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                db.session.add(resource)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                db.session.commit()
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                file.save(path.join(config.DATA_PATH, "pictures", str(resource.id)))
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -316,6 +321,10 @@ def picture(id):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            @app.route("/picture/<int:id>/annotate")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            def annotate_picture(id):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                resource = db.session.get(PictureResource, id)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            current_user = db.session.get(User, flask.session.get("username"))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            if resource.author != current_user and not current_user.admin:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                return flask.abort(403)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                if resource is None:
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    return flask.abort(404)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -323,6 +332,60 @@ def annotate_picture(id):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                                             file_extension=mimetypes.guess_extension(resource.file_format))
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        @app.route("/picture/<int:id>/save-annotations", methods=["POST"])
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        def save_annotations(id):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            resource = db.session.get(PictureResource, id)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            if resource is None:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                return flask.abort(404)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            current_user = db.session.get(User, flask.session.get("username"))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            if resource.author != current_user and not current_user.admin:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                return flask.abort(403)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # Delete all previous annotations
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            db.session.query(PictureRegion).filter_by(resource_id=id).delete()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            json = flask.request.json
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            for region in json:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                object_id = region["object"]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                picture_object = db.session.get(PictureObject, object_id)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                region_data = {
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "type": region["type"],
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "shape": region["shape"],
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                }
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                region_row = PictureRegion(region_data, resource, picture_object)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                db.session.add(region_row)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            db.session.commit()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            response = flask.make_response()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            response.status_code = 204
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            return response
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        @app.route("/picture/<int:id>/get-annotations")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        def get_annotations(id):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            resource = db.session.get(PictureResource, id)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            if resource is None:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                return flask.abort(404)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            regions = db.session.query(PictureRegion).filter_by(resource_id=id).all()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            regions_json = []
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            for region in regions:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                regions_json.append({
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "object": region.object_id,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "type": region.json["type"],
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "shape": region.json["shape"],
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                })
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            return flask.jsonify(regions_json)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            @app.route("/raw/picture/<int:id>")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            def raw_picture(id):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                resource = db.session.get(PictureResource, id)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                            
                                

formats.md

@@ -0,0 +1,110 @@

                                
                                
                                
                            
                                
                                    
                                        
                                        Data formats
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ============
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        This document describes the various data formats that are used in the system.
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        Raw annotation data (client → server)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        -------------------------------------
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        The client sends raw data for image annotations in a JSON format which is a list
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        of shapes. Each shape is a dictionary with the following keys:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        * `type`: The type of the shape which can be:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * `bbox` (bounding box, rectangle)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * `polygon`
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * `polyline`
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * `point`
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        * `shape`: The shape data. Its format depends on the shape `type`:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * For `bbox` it is a dictionary with keys x, y, w, h:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            ~~~json
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            {"x": x, "y": y, "w": w, "h": h}
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            ~~~
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * For `polygon` and `polyline` it is a list of points; each point is a
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            dictionary with keys x and y:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            ~~~json
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            [{"x": x1, "y": y1}, {"x": x2, "y": y2}, ...]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            ~~~
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            The only difference between `polygon` and `polyline` is that the former is
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            supposed to be closed so the last point is connected to the first one.
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * For `point` it is a dictionary with keys x and y:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            ~~~json
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            {"x": x, "y": y}
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            ~~~
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          * All coordinates are floating-point numbers in the range [0, 1] and relative
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            to the image size, with the origin in the top-left corner.
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        * `object`: The ID of the type of object (label) depicted in the shape. This ID
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          is a human-readable string that must be registered in the system before
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                          being used on shapes.
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ### Example
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ~~~json
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        [
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            {
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "type": "bbox",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "shape": {"x": 0.1, "y": 0.1, "w": 0.5, "h": 0.5},
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "object": "Cat (Felis catus)"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            },
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            {
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "type": "polygon",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "shape": [{"x": 0, "y": 0}, {"x": 1, "y": 0}, {"x": 0, "y": 1}],
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "object": "Slice of pizza margherita"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            },
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            {
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "type": "point",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "shape": {"x": 0.5, "y": 0.5},
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                "object": "Cat (Felis catus) - left eye"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            }
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ~~~
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        Query format
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ------------
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        The query format is based on YAML and used to query for pictures in the system.
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ### Example
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ~~~yaml
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # Restrictions for queried images
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        - want:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # This means that the image must contain both rules, so both a cat and a dog
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - has_object: ["Cat (Felis catus)"]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - has_object: ["Dog (Canis lupus familiaris)"]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # Or we can put them in a list to mean that the image can contain any of the
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # objects in the list
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - has_object: ["Grass", "Flower"]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # So the image must contain a cat and a dog, as well as either grass or
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # a flower
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # The following rule restricts the images to those with a certain source,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # like a camera or a drawing; omitting this rule means that the images can
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # be of any type
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - nature: ["photo", "drawing"]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # The following rule restricts the images to those with a certain licence
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - licence: ["CC-BY-1.0", "CC-BY-2.0", "CC-BY-3.0", "CC-BY-4.0", "CC0-1.0",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        "Unlicense", "WTFPL", "MIT", "BSD-2-Clause", "BSD-3-Clause",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        "Apache-2.0", "Informal-attribution", "Informal-do-anything",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        "Public-domain-old", "Public-domain"]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # Prohibitions for queried images
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        - exclude:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # This means that the image must not contain any of the objects in the list
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - has_object: ["Human"]
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # This excludes images taken before the given date
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - before_date: 2019-01-01
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            # This requires images to have a minimum resolution
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - below_width: 800
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            - below_height: 600
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # Pagination
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        - limit: 32
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        - offset: 0
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # Sorting
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        - sort_by: "date-uploaded-recent"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # Format
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        - format: "jpg"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        - max_resolution: [800, 800]  # resizes
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # In summary, we want the 32 most recent images that contain both a cat and
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # a dog, either a grass or a flower, but not a human, taken after 2019-01-01,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # must be a photo or a drawing, must carry one of certain permissive licences
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # and have a resolution of at least 800x600 pixels.
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        ~~~
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                            
                                

static/picture-annotation.py

@@ -2,6 +2,7 @@ from pyscript import document

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            from pyodide.ffi import create_proxy
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            from pyodide.http import pyfetch
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            import asyncio
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        import json
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            document.getElementById("shape-options").style.display = "flex"
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -13,6 +14,7 @@ backspace_button = document.getElementById("annotation-backspace")

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            delete_button = document.getElementById("annotation-delete")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            previous_button = document.getElementById("annotation-previous")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            next_button = document.getElementById("annotation-next")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        save_button = document.getElementById("annotation-save")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            object_list = document.getElementById("object-types")
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -52,6 +54,122 @@ def change_object_type(event):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            change_object_type_proxy = create_proxy(change_object_type)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        def list_shapes():
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            shapes = list(zone.getElementsByClassName("shape"))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            json_shapes = []
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            for shape in shapes:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                shape_dict = {}
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                match shape.tagName:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    case "rect":
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        shape_dict["type"] = "bbox"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        shape_dict["shape"] = {
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            "x": float(shape.getAttribute("x")) / image.naturalWidth,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            "y": float(shape.getAttribute("y")) / image.naturalHeight,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            "w": float(shape.getAttribute("width")) / image.naturalWidth,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            "h": float(shape.getAttribute("height")) / image.naturalHeight
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        }
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    case "polygon" | "polyline":
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        if shape.tagName == "polygon":
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            shape_dict["type"] = "polygon"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        elif shape.tagName == "polyline":
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            shape_dict["type"] = "polyline"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        points = shape.getAttribute("points").split(" ")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        json_points = []
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        for point in points:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            x, y = point.split(",")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            x, y = float(x), float(y)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            json_points.append({
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                "x": x / image.naturalWidth,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                                "y": y / image.naturalHeight
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            })
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        shape_dict["shape"] = json_points
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    case "circle" if shape.classList.contains("shape-point"):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        shape_dict["type"] = "point"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        shape_dict["shape"] = {
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            "x": float(shape.getAttribute("cx")) / image.naturalWidth,
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                            "y": float(shape.getAttribute("cy")) / image.naturalHeight
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        }
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    case _:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        continue
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                shape_dict["object"] = shape.getAttribute("data-object-type")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                json_shapes.append(shape_dict)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            return json_shapes
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        def put_shapes(json_shapes):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            for shape in json_shapes:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                new_shape = document.createElementNS("http://www.w3.org/2000/svg", "svg")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                new_shape.setAttribute("width", "100%")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                new_shape.setAttribute("height", "100%")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                zone_rect = zone.getBoundingClientRect()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                new_shape.setAttribute("viewBox", f"0 0 {image.naturalWidth} {image.naturalHeight}")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                new_shape.classList.add("shape-container")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                if shape["type"] == "bbox":
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle = document.createElementNS("http://www.w3.org/2000/svg", "rect")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.setAttribute("x", str(shape["shape"]["x"] * image.naturalWidth))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.setAttribute("y", str(shape["shape"]["y"] * image.naturalHeight))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.setAttribute("width", str(shape["shape"]["w"] * image.naturalWidth))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.setAttribute("height", str(shape["shape"]["h"] * image.naturalHeight))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.setAttribute("fill", "none")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.setAttribute("data-object-type", shape["object"])
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.classList.add("shape-bbox")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    rectangle.classList.add("shape")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    new_shape.appendChild(rectangle)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                elif shape["type"] == "polygon" or shape["type"] == "polyline":
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    polygon = document.createElementNS("http://www.w3.org/2000/svg", shape["type"])
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    points = " ".join(
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        [f"{point['x'] * image.naturalWidth},{point['y'] * image.naturalHeight}" for point in shape["shape"]])
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    polygon.setAttribute("points", points)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    polygon.setAttribute("fill", "none")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    polygon.setAttribute("data-object-type", shape["object"])
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    polygon.classList.add(f"shape-{shape['type']}")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    polygon.classList.add("shape")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    new_shape.appendChild(polygon)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                elif shape["type"] == "point":
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    point = document.createElementNS("http://www.w3.org/2000/svg", "circle")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    point.setAttribute("cx", str(shape["shape"]["x"] * image.naturalWidth))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    point.setAttribute("cy", str(shape["shape"]["y"] * image.naturalHeight))
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    point.setAttribute("r", "0")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    point.classList.add("shape-point")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    point.classList.add("shape")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    point.setAttribute("data-object-type", shape["object"])
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    new_shape.appendChild(point)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                zone.appendChild(new_shape)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        async def load_shapes():
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            resource_id = document.getElementById("resource-id").value
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            response = await pyfetch(f"/picture/{resource_id}/get-annotations")
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            if response.ok:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                shapes = await response.json()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                return shapes
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        async def save_shapes(event):
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            shapes = list_shapes()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            resource_id = document.getElementById("resource-id").value
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            print("Saving shapes:", shapes)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            response = await pyfetch(f"/picture/{resource_id}/save-annotations",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                method="POST",
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                headers={
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    "Content-Type": "application/json"
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                },
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                body=json.dumps(shapes)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            )
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            if response.ok:
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                return await response
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        save_shapes_proxy = create_proxy(save_shapes)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        save_button.addEventListener("click", save_shapes_proxy)
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            async def focus_shape(shape):
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                global selected_shape
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        

@@ -480,3 +598,9 @@ for button in list(document.getElementById("shape-selector").children):

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            zone.addEventListener("mousemove", follow_cursor_proxy)
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            zone.addEventListener("click", create_proxy(open_shape))
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        # Load existing annotations, if any
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        async def load_existing():
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            put_shapes(await load_shapes())
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        load_existing()
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                            
                                

templates/picture-annotation.html

@@ -57,9 +57,14 @@

                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        <button class="button-flat" title="select next shape" id="annotation-next">
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                            <iconify-icon icon="mdi:chevron-right"></iconify-icon>
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                        </button>
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    <div class="flexible-space"></div>
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    <button id="annotation-save">
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                        Save
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                                    </button>
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    </x-buttonbox>
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    <x-vbox id="object-types" style="--gap-box: 0.25rem; --padding-box: 1rem;">
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                    </x-vbox>
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                </x-frame>
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            <input type="hidden" id="resource-id" name="resource-id" value="{{ resource.id }}">
                                        
                                        
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                                <script type="py" src="/static/picture-annotation.py"></script>
                                        
                                        
                                            
                                            
                                            
                                            
                                        
                                    
                                
                                
                                
                            
                                
                                    
                                        
                                            
                                            {% endblock %}