File size: 6,748 Bytes
9bbf7fe
 
 
2f83e6d
d806786
9bbf7fe
4a33e04
9bbf7fe
 
 
2f83e6d
 
a190092
2a4e18c
 
a190092
9bbf7fe
 
 
a190092
 
9bbf7fe
43bd8fd
9bbf7fe
 
a190092
 
2a4e18c
 
a190092
2a4e18c
 
a190092
9bbf7fe
 
7a43999
 
 
 
 
 
 
 
9bbf7fe
 
7a43999
 
9bbf7fe
 
 
2f83e6d
7a43999
 
43bd8fd
9bbf7fe
 
 
 
 
7a43999
9bbf7fe
7a43999
a190092
2f83e6d
9bbf7fe
 
 
7a43999
9bbf7fe
 
e8b9871
9bbf7fe
 
 
 
 
 
 
 
 
 
 
 
43bd8fd
 
9bbf7fe
 
43bd8fd
7a43999
9bbf7fe
 
 
 
 
 
 
7a43999
 
9bbf7fe
 
43bd8fd
 
 
 
 
 
9bbf7fe
 
 
01f7b8a
9bbf7fe
 
 
 
01f7b8a
9bbf7fe
 
 
 
 
 
43bd8fd
 
9bbf7fe
 
01f7b8a
9bbf7fe
 
 
 
 
 
 
 
01f7b8a
9bbf7fe
 
d806786
9bbf7fe
d806786
 
 
 
 
 
9bbf7fe
 
01f7b8a
9bbf7fe
 
7a43999
 
 
ccf3267
9bbf7fe
01f7b8a
9bbf7fe
 
 
7a43999
 
43bd8fd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a33e04
 
7a43999
4a33e04
 
 
 
 
 
 
 
 
 
 
 
 
9bbf7fe
 
4a33e04
9bbf7fe
 
01f7b8a
9bbf7fe
d806786
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
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

# Ensure the upload directory exists
#if not os.path.exists(os.path.join(os.getcwd(), UPLOAD_FOLDER)):
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
#if not os.path.exists(os.path.join(os.getcwd(), OUT_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')
    # user_id = request.cookies.get('session')
    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
        # logger.info(app.config["FILES"], app.config["HEAD"])
        return redirect('/tagger', code=302)
    else:
        return render_template('index.html')


@app.route('/tagger')
def tagger():
    if (app.config["HEAD"] == len(app.config["FILES"])):
        # done annotating the batch of images
        app.config["HEAD"] = 0
        return redirect(url_for('final'))
    user_id = session.get('_id')
    # app.config["IMAGES"] + f'/{user_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:
        # add to category
        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")

    #shutil.copyfile(anno_path, f'{img_dir}/annotations_pascal_voc.csv')
    download_zip = os.path.join(img_dir, 'final')
    print(download_zip)
    shutil.make_archive('final', 'zip', img_dir)
    # shutil.make_archive(base_name=download_zip,
    #                     format='zip',
    #                     base_dir=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")