| import os |
| import shutil |
| import uuid |
| import logging |
| import json |
|
|
| from flask import Flask, redirect, url_for, request, flash, session, after_this_request |
| from flask import render_template |
| from flask import send_file |
|
|
| logger = logging.getLogger(__name__) |
| logging.basicConfig(level=logging.INFO) |
|
|
| UPLOAD_FOLDER = './images' |
| OUT_FOLDER = './anno' |
|
|
| app = Flask(__name__) |
| app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 |
| app.config["SECRET_KEY"] = '#thaistartsfirst!' |
| app.config["IMAGES"] = UPLOAD_FOLDER |
| app.config["OUT"] = OUT_FOLDER |
| app.config["LABELS"] = [] |
| app.config["CATEGORIES"] = {} |
| app.config["HEAD"] = 0 |
| app.config["SESSION_PERMANENT"] = False |
|
|
| |
| |
| if not os.path.exists(UPLOAD_FOLDER): |
| os.makedirs(UPLOAD_FOLDER) |
| |
| if not os.path.exists(OUT_FOLDER): |
| os.makedirs(OUT_FOLDER) |
|
|
|
|
| def get_anno_path(user_id): |
| return os.path.join(OUT_FOLDER, f'{user_id}.csv') |
|
|
|
|
| def get_images_directory(user_id): |
| return os.path.join(UPLOAD_FOLDER, f'{user_id}') |
|
|
|
|
| @app.route('/', methods=['GET', 'POST']) |
| def index(): |
| user_id = session.get('_id') |
| |
| if user_id is None: |
| user_id = uuid.uuid4() |
| session['_id'] = user_id |
| logger.info(user_id) |
| anno_path = get_anno_path(user_id) |
| with open(anno_path, 'w') as f: |
| f.write("image,category,name,xMin,yMin,xMax,yMax\n") |
|
|
| if request.method == 'POST': |
| if 'file' not in request.files: |
| flash('No files selected') |
| return redirect('/') |
| img_dir = get_images_directory(user_id) |
| try: |
| os.makedirs(img_dir) |
| except FileExistsError: |
| logger.info('user already has an active session') |
| files = request.files.getlist("file") |
| filenames = [] |
| for f in files: |
| f.save(os.path.join(img_dir, f.filename)) |
| filenames.append(f.filename) |
| app.config["FILES"] = filenames |
| |
| return redirect('/tagger', code=302) |
| else: |
| return render_template('index.html') |
|
|
|
|
| @app.route('/tagger') |
| def tagger(): |
| if (app.config["HEAD"] == len(app.config["FILES"])): |
| |
| app.config["HEAD"] = 0 |
| return redirect(url_for('final')) |
| user_id = session.get('_id') |
| |
| img_dir = get_images_directory(user_id) |
| image = app.config["FILES"][app.config["HEAD"]] |
| labels = app.config["LABELS"] |
| not_end = not (app.config["HEAD"] == len(app.config["FILES"]) - 1) |
| return render_template('tagger.html', not_end=not_end, directory=img_dir, image=image, labels=labels, head=app.config["HEAD"] + 1, len=len(app.config["FILES"])) |
|
|
|
|
| @app.route('/next') |
| def next(): |
| image = app.config["FILES"][app.config["HEAD"]] |
| app.config["HEAD"] = app.config["HEAD"] + 1 |
| user_id = session.get("_id") |
| anno_path = get_anno_path(user_id) |
| with open(anno_path, 'a+') as f: |
| for label in app.config["LABELS"]: |
| f.write(image + "," + |
| str(label["category"]) + "," + |
| label["name"] + "," + |
| str(round(float(label["xMin"]))) + "," + |
| str(round(float(label["yMin"]))) + "," + |
| str(round(float(label["xMax"]))) + "," + |
| str(round(float(label["yMax"]))) + "\n") |
| app.config["LABELS"] = [] |
| return redirect(url_for('tagger')) |
|
|
|
|
| @app.route("/final") |
| def final(): |
| return render_template('final.html') |
|
|
|
|
| @app.route('/add/<id>') |
| def add(id): |
| xMin = request.args.get("xMin") |
| xMax = request.args.get("xMax") |
| yMin = request.args.get("yMin") |
| yMax = request.args.get("yMax") |
| app.config["LABELS"].append( |
| {"id": id, "name": "", "category": "", "xMin": xMin, "xMax": xMax, "yMin": yMin, "yMax": yMax}) |
| return redirect(url_for('tagger')) |
|
|
|
|
| @app.route('/remove/<id>') |
| def remove(id): |
| index = int(id) - 1 |
| del app.config["LABELS"][index] |
| for label in app.config["LABELS"][index:]: |
| label["id"] = str(int(label["id"]) - 1) |
| return redirect(url_for('tagger')) |
|
|
|
|
| @app.route('/label/<id>') |
| def label(id): |
| name = request.args.get("name").lower() |
| app.config["LABELS"][int(id) - 1]["name"] = name |
| category = app.config["CATEGORIES"].get(name, None) |
| if category is None: |
| |
| category = len(app.config["CATEGORIES"]) |
| app.config["CATEGORIES"][name] = category |
| app.config["LABELS"][int(id) - 1]["category"] = category |
| return redirect(url_for('tagger')) |
|
|
|
|
| @app.route('/image/<f>') |
| def images(f): |
| user_id = session.get('_id') |
| img_dir = get_images_directory(user_id) |
| img_path = os.path.join(img_dir, f'{f}') |
| return send_file(img_path) |
|
|
|
|
| @app.route('/download') |
| def download(): |
| user_id = session.get('_id') |
| anno_path = get_anno_path(user_id) |
| img_dir = get_images_directory(user_id) |
| data = {} |
| with open(anno_path, 'r') as f: |
| for line in f.readlines(): |
| elems = line.strip().split(',') |
| file_name = data.get(elems[0], None) |
| if file_name is None: |
| data[elems[0]] = {'bbox': [], 'categories': [], 'names': []} |
| data[elems[0]]['categories'].append(int(elems[1])) |
| data[elems[0]]['names'].append(elems[2]) |
| data[elems[0]]['bbox'].append([int(elems[i]) for i in range(3, len(elems))]) |
| img_dataset = [] |
| for file_name, obj in data.items(): |
| img_dataset.append( |
| { |
| 'file_name': file_name, |
| 'objects': obj |
| } |
| ) |
| with open(f'{img_dir}/metadata.jsonl', 'w') as f: |
| for item in img_dataset: |
| f.write(json.dumps(item) + "\n") |
|
|
| |
| download_zip = os.path.join(img_dir, 'final') |
| print(download_zip) |
| shutil.make_archive('final', 'zip', img_dir) |
| |
| |
| |
|
|
| @after_this_request |
| def remove_directory(response): |
| try: |
| shutil.rmtree(img_dir) |
| os.remove(anno_path) |
| except Exception as e: |
| print(f"Error deleting directory {img_dir}: {e}") |
| return response |
|
|
| return send_file('final.zip', |
| mimetype='text/csv', |
| download_name='annotated_data.zip', |
| as_attachment=True) |
|
|
|
|
| if __name__ == "__main__": |
| app.run(debug="True") |
|
|