You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

229 lines
7.4 KiB
Python

#
#
# DEPENDENCIES
import os
from flask import Flask, url_for, render_template, flash, request, redirect
from werkzeug.utils import secure_filename
import json
import mariadb
import sys
from PIL import Image
#
#
# GLOBAL VARIABLES
UPLOAD_FOLDER = os.path.join(os.getcwd(), 'static/uploads/annotation-compass/')
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
#
#
# FUNCTIONS
def connection():
''' Open a connection to the mariaDB database '''
try:
conn = mariadb.connect(
user="guardian_of_the_labels",
password="soup_of_the_labels",
host="localhost",
port=3306,
database='collecting_labels',
autocommit=True
)
except mariadb.Error as e:
print(f'Error connecting to MariaDB Platflorm: {e}')
sys.exit(1)
return conn
def make_link_list(names, base_url):
''' Generate a list of link from the files in a folder '''
link_list = ''
for name in names:
if allowed_file(name, ALLOWED_EXTENSIONS):
link = f'<a href="{base_url}/{name}/">{name}</a><br/>'
link_list = link_list + link
return link_list
def allowed_file(filename, extensions):
''' Check if the file extension is in the allowed extensions array '''
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in extensions
def temp_fix_date(timestamp):
''' JS Date to mySQL Date '''
from datetime import datetime
from time import strftime
date = datetime.fromtimestamp(timestamp / 1000.0)
return date.strftime('%Y-%m-%d %H:%M:%S')
def add_label(cursor, label):
''' Insert a new label in the database '''
x = label['position']['x']
y = label['position']['y']
width = label['size']['width']
height = label['size']['height']
text = label['text']
timestamp = temp_fix_date(label['timestamp'])
user_id = str(label['userID'])
image = label['image']
try:
cursor.execute(f'INSERT INTO labels (x,y,width,height,text,timestamp,userID,image) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', (x, y, width, height, text, timestamp, user_id, image ))
print(f'Insert label#{cursor.lastrowid} from user {user_id} on {image} at {timestamp}.')
except mariadb.Error as e:
print(f"Error error error in MariaDB Platform: {e}")
return {"message":"oh no", "error":e}
def get_labels(cursor, filename):
''' List the labels for a specific image from the database '''
try:
cursor.execute(f"SELECT * FROM labels WHERE image = '{filename}'")
db_labels = cursor.fetchall()
labels = []
for (index, x, y, width, height, text, timestamp, user_id, image) in db_labels:
label = {
'position': {
'x': x,
'y': y
},
'size': {
'width': width,
'height': height
},
'text': text,
'timestamp': timestamp,
'userID': user_id,
'image': image
}
labels.append(label)
return labels
except mariadb.Error as e:
print(f"Error error error in MariaDB Platform: {e}")
return {"message":"oh no", "error":e}
def add_image_description(filename, description):
''' Set description for an image during upload '''
image_description_output = {}
with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "r") as f:
image_description_input = json.loads(f.read())
image_description_output = image_description_input
image_description_output[filename] = {
'description': description
}
with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "w") as f:
f.write(json.dumps(image_description_output))
def get_image_description(filename):
''' Get the description of an uploaded image '''
with open(os.path.join(os.getcwd(), "projects/annotation-compass/descriptions.json"), "r") as f:
descriptions = json.loads(f.read())
return descriptions[filename]['description']
def thumbnail(image):
try:
img = Image.open(image)
img.thumbnail((128,128))
name = image.rsplit('.', 1)[0]
ext = image.rsplit('.', 1)[1]
img.save(f'{name}_thumb.{ext}')
except IOError:
pass
# TODO: clean up this dai
# /generic-labels/ → /si16/annotation-compass/ (GET, POST)
def upload_file(request):
''' Upload a new image in the Annotation Compass '''
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename, ALLOWED_EXTENSIONS):
filename = secure_filename(file.filename)
file.save(os.path.join(UPLOAD_FOLDER, filename))
thumbnail(os.path.join(UPLOAD_FOLDER, filename))
description = request.form['description']
add_image_description(filename, description)
def list_images():
''' List the images in the Annotation Compass. '''
files = os.listdir(UPLOAD_FOLDER)
files.sort()
not_thumbs = filter(lambda file: '_thumb.' not in file, files)
images = []
for image in not_thumbs:
if allowed_file(image, ALLOWED_EXTENSIONS):
name = image.rsplit('.', 1)[0]
ext = image.rsplit('.', 1)[1]
img = image
thumb = f'{name}_thumb.{ext}'
images.append((img, thumb))
return images
# links = make_link_list(images, 'annotate/' )
# TODO: transform this in a template
# return f'''
# <!doctype html>
# <title>Collecting Labels</title>
# {links}
# <h2>Upload new File</h2>
# <form method=post enctype=multipart/form-data>
# <input type=file name=file>
# <input type=submit value=Upload>
# <textarea name=description ></textarea>
# </form>
# '''
# /generic-labels/annotate/<image>/ → /si16/annotation-compass/annotate/<image>/
# def annotate_image(image=None):
# ''' Open the Annotation Compass on a specific image '''
# description = ''
# try:
# description = get_image_description(image)
# except:
# print("There is no description")
# return render_template('annotate_image.html', image=image, description=description)
# /generic-labels/add-label/ → /si16/annotation-compass/add-label
# in the URL there is no reference to the image because the info is in the json body of the label itself
def insert_label(request):
''' Insert a new label in the database '''
connect = connection()
cursor = connect.cursor()
add_label(cursor, request.json)
connect.close()
return {"response": "ok"}
# /generic-labels/get-labels/ → /si16/annotation-compass/get-labels/<image>/
# TODO: adapt the old url with the query
# OLD: /get-labels/?image=<image>
# NEW: /get-labels/<image>/
def get_labels_list(image = None):
connect = connection()
cursor = connect.cursor()
labels = get_labels(cursor, image)
connect.close()
return {"response": "ok", "labels": labels }