├── .DS_Store
├── .gitignore
├── LICENSE
├── README.md
├── gtm_hit
├── .DS_Store
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_auto_20161108_1322.py
│ ├── 0003_auto_20161108_1544.py
│ ├── 0004_auto_20161108_1607.py
│ ├── 0005_auto_20161110_1512.py
│ ├── 0006_auto_20161110_1558.py
│ ├── 0007_auto_20161110_1654.py
│ ├── 0008_auto_20161110_1705.py
│ ├── 0009_remove_validationcode_workerid.py
│ ├── 0010_worker_time_list.py
│ ├── 0011_auto_20161202_1255.py
│ └── __init__.py
├── models.py
├── static
│ ├── .DS_Store
│ └── gtm_hit
│ │ ├── .DS_Store
│ │ ├── cst.txt
│ │ ├── day_2
│ │ ├── images
│ │ ├── .DS_Store
│ │ ├── arrows0_3D.png
│ │ ├── arrows1_3D.png
│ │ ├── arrows2_3D.png
│ │ ├── arrows3_3D.png
│ │ ├── arrows4_3D.png
│ │ ├── arrows5_3D.png
│ │ ├── arrows6_3D.png
│ │ ├── arrows_plane.png
│ │ ├── bad.png
│ │ ├── epfl_logo.png
│ │ ├── ex2.png
│ │ ├── fns_logo.png
│ │ ├── good.png
│ │ └── idiap_logo.png
│ │ ├── index.css
│ │ ├── jquery.hotkeys.js
│ │ ├── marker.js
│ │ └── tuto.css
├── templates
│ ├── .DS_Store
│ ├── gtm_hit
│ │ ├── .DS_Store
│ │ ├── finish.html
│ │ ├── frame.html
│ │ ├── index.html
│ │ ├── requestID.html
│ │ └── tuto.html
│ └── includes_hit
│ │ ├── controller.html
│ │ ├── footer.html
│ │ ├── help.html
│ │ ├── navbar.html
│ │ └── side_menu.html
├── templatetags
│ ├── __init__.py
│ └── gtm_hit_extra.py
├── tests.py
├── urls.py
└── views.py
├── gtmarker
├── .DS_Store
├── __init__.py
├── dump.rdb
├── settings.py
├── urls.py
└── wsgi.py
├── home
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ └── __init__.py
├── models.py
├── static
│ ├── epfl_logo.png
│ ├── fns_logo.png
│ └── idiap_logo.png
├── templates
│ ├── .DS_Store
│ ├── home
│ │ ├── error.html
│ │ ├── index.html
│ │ └── login.html
│ └── includes_home
│ │ ├── footer.html
│ │ └── navbar.html
├── tests.py
└── views.py
├── manage.py
└── marker
├── .DS_Store
├── __init__.py
├── admin.py
├── apps.py
├── context_processors.py
├── management
├── .DS_Store
└── commands
│ ├── add_data.py
│ └── set_data.py
├── middleware.py
├── migrations
├── 0001_initial.py
├── 0002_auto_20161013_1455.py
├── 0003_rectanges.py
├── 0004_auto_20161018_1310.py
├── 0005_auto_20161018_1341.py
├── 0006_rectangle_xmid.py
├── 0007_remove_annotation_pom_file.py
├── 0008_delete_rectangle.py
├── 0009_worker.py
├── 0010_auto_20161110_1512.py
└── __init__.py
├── models.py
├── static
├── .DS_Store
└── marker
│ ├── .DS_Store
│ ├── arrows.gif
│ ├── arrows.png
│ ├── cst.txt
│ ├── day_2
│ ├── find_rect.pickle
│ ├── frame.css
│ ├── images
│ ├── .DS_Store
│ ├── arrows0_3D.png
│ ├── arrows1_3D.png
│ ├── arrows2_3D.png
│ ├── arrows3_3D.png
│ ├── arrows4_3D.png
│ ├── arrows5_3D.png
│ ├── arrows6_3D.png
│ ├── arrows_plane.png
│ ├── bad.png
│ ├── epfl_logo.png
│ ├── ex2.png
│ ├── fns_logo.png
│ ├── good.png
│ └── idiap_logo.png
│ ├── index.css
│ ├── jquery.hotkeys.js
│ ├── marker.js
│ ├── raphael.js
│ └── rect.pickle
├── templates
├── .DS_Store
├── includes
│ ├── controller.html
│ ├── footer.html
│ ├── help.html
│ ├── load.html
│ ├── navbar.html
│ ├── side_menu.html
│ └── tuto.html
└── marker
│ ├── download.html
│ ├── download_worker.html
│ ├── frame.html
│ ├── index.html
│ └── login.html
├── templatetags
├── __init__.py
└── marker_extra.py
├── tests.py
├── urls.py
└── views.py
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.json
3 | *.pom
4 | day2
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EPFL Multi-camera detection annotation tool
2 | Our web-application to annotate multi-camera detection datasets. Feel free to download and use it to annotate other datasets.
3 |
4 | ### Usage
5 |
6 | ### Dependencies
7 | Django==1.10.2
8 | django-bootstrap-form==3.2.1
9 | numpy==1.11.2
10 | pandas==0.19.0
11 |
12 | ### Acknowledgements
13 | Written by Stephane Bouquet during his MSc. Thesis at CVLab, EPFL, under the supervision of Pierre Baqué.
14 | We acknowledge the WILDTRACK project and the Swiss National Scientific Fund.
15 |
--------------------------------------------------------------------------------
/gtm_hit/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/.DS_Store
--------------------------------------------------------------------------------
/gtm_hit/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/__init__.py
--------------------------------------------------------------------------------
/gtm_hit/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import *
3 |
4 | admin.site.register(Worker)
5 | admin.site.register(ValidationCode)
6 |
--------------------------------------------------------------------------------
/gtm_hit/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class Gtm_hitConfig(AppConfig):
5 | name = 'gtm_hit'
6 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-07 16:00
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='Worker',
18 | fields=[
19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20 | ('workerID', models.PositiveIntegerField(default=0)),
21 | ('frameNB', models.PositiveSmallIntegerField(default=0)),
22 | ('validationoCode', models.PositiveIntegerField(default=0)),
23 | ('finished', models.BooleanField(default=False)),
24 | ('state', models.IntegerField(default=-1)),
25 | ],
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0002_auto_20161108_1322.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-08 13:22
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('gtm_hit', '0001_initial'),
12 | ]
13 |
14 | operations = [
15 | migrations.RenameField(
16 | model_name='worker',
17 | old_name='validationoCode',
18 | new_name='validationCode',
19 | ),
20 | migrations.AddField(
21 | model_name='worker',
22 | name='tuto',
23 | field=models.BooleanField(default=False),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0003_auto_20161108_1544.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-08 15:44
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('gtm_hit', '0002_auto_20161108_1322'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='worker',
17 | name='workerID',
18 | field=models.TextField(default='', max_length=40),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0004_auto_20161108_1607.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-08 16:07
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('gtm_hit', '0003_auto_20161108_1544'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='worker',
17 | name='frame_labeled',
18 | field=models.PositiveSmallIntegerField(default=0),
19 | ),
20 | migrations.AlterField(
21 | model_name='worker',
22 | name='frameNB',
23 | field=models.IntegerField(default=-1),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0005_auto_20161110_1512.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-10 15:12
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('gtm_hit', '0004_auto_20161108_1607'),
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='ValidationCode',
18 | fields=[
19 | ('validationCode', models.PositiveIntegerField(primary_key=True, serialize=False)),
20 | ],
21 | ),
22 | migrations.RemoveField(
23 | model_name='worker',
24 | name='id',
25 | ),
26 | migrations.RemoveField(
27 | model_name='worker',
28 | name='validationCode',
29 | ),
30 | migrations.AlterField(
31 | model_name='worker',
32 | name='workerID',
33 | field=models.TextField(max_length=40, primary_key=True, serialize=False),
34 | ),
35 | migrations.AddField(
36 | model_name='validationcode',
37 | name='workerID',
38 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gtm_hit.Worker'),
39 | ),
40 | ]
41 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0006_auto_20161110_1558.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-10 15:58
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('gtm_hit', '0005_auto_20161110_1512'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='validationcode',
17 | name='validationCode',
18 | field=models.TextField(primary_key=True, serialize=False),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0007_auto_20161110_1654.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-10 16:54
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('gtm_hit', '0006_auto_20161110_1558'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='validationcode',
18 | name='worker',
19 | field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='gtm_hit.Worker', unique=True),
20 | preserve_default=False,
21 | ),
22 | migrations.AlterField(
23 | model_name='validationcode',
24 | name='workerID',
25 | field=models.TextField(max_length=40, unique=True),
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0008_auto_20161110_1705.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-10 17:05
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('gtm_hit', '0007_auto_20161110_1654'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='validationcode',
18 | name='worker',
19 | field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='gtm_hit.Worker'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0009_remove_validationcode_workerid.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-10 17:06
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('gtm_hit', '0008_auto_20161110_1705'),
12 | ]
13 |
14 | operations = [
15 | migrations.RemoveField(
16 | model_name='validationcode',
17 | name='workerID',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0010_worker_time_list.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-12-02 11:12
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('gtm_hit', '0009_remove_validationcode_workerid'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='worker',
17 | name='time_list',
18 | field=models.TextField(default=0),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/0011_auto_20161202_1255.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-12-02 12:55
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('gtm_hit', '0010_worker_time_list'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='worker',
17 | name='time_list',
18 | field=models.TextField(default=''),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/gtm_hit/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/migrations/__init__.py
--------------------------------------------------------------------------------
/gtm_hit/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.core.validators import validate_comma_separated_integer_list
3 | import json
4 |
5 | class Worker(models.Model):
6 |
7 | workerID = models.TextField(primary_key=True,max_length=40)
8 | frameNB = models.IntegerField(default=-1)
9 | frame_labeled = models.PositiveSmallIntegerField(default=0)
10 | #validationCode = models.PositiveIntegerField(default=0)
11 | finished = models.BooleanField(default=False)
12 | state = models.IntegerField(default=-1)
13 | tuto = models.BooleanField(default=False)
14 | time_list = models.TextField(default="")
15 |
16 |
17 | def increaseFrame(self,val):
18 | self.frame_labeled = self.frame_labeled + val
19 |
20 | def decreaseFrame(self,val):
21 | self.frame_labeled = self.frame_labeled - val
22 |
23 | def setTimeList(self,x):
24 | self.time_list = json.dumps(x)
25 | def getTimeList(self):
26 | return json.loads(self.time_list)
27 | def __str__(self):
28 | return 'Worker: ' + self.workerID
29 | class ValidationCode(models.Model):
30 | validationCode = models.TextField(primary_key=True)
31 | worker = models.OneToOneField('Worker',on_delete=models.CASCADE)
32 | def __str__(self):
33 | return 'Code: ' + self.worker.workerID
34 |
--------------------------------------------------------------------------------
/gtm_hit/static/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/.DS_Store
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/.DS_Store
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/cst.txt:
--------------------------------------------------------------------------------
1 | WIDTH 12
2 | HEIGHT 32
3 | NB_WIDTH 480
4 | NB_HEIGHT 1280
5 | MAN_RAY 0.16
6 | MAN_HEIGHT 1.8
7 | REDUCTION 1
8 | ORIGINE_X -3.0
9 | ORIGINE_Y -6.0
10 | NB_CAMERA 7
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/day_2:
--------------------------------------------------------------------------------
1 | /cvlabdata1/cvlab/datasets_people_tracking/ETH/day_2/
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/.DS_Store
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows0_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows0_3D.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows1_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows1_3D.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows2_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows2_3D.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows3_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows3_3D.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows4_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows4_3D.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows5_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows5_3D.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows6_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows6_3D.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/arrows_plane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/arrows_plane.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/bad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/bad.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/epfl_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/epfl_logo.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/ex2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/ex2.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/fns_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/fns_logo.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/good.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/good.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/images/idiap_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/static/gtm_hit/images/idiap_logo.png
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/index.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Start Bootstrap - Landing Page (http://startbootstrap.com/)
3 | * Copyright 2013-2016 Start Bootstrap
4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
5 | */
6 |
7 | body,
8 | html {
9 | width: 100%;
10 | height: 100%;
11 | }
12 |
13 | body {
14 | font-family: "Lato","Helvetica Neue",Arial,sans-serif;
15 | font-weight: 500;
16 | }
17 | h1,
18 | h2,
19 | h3,
20 | h4,
21 | h5,
22 | h6 {
23 | font-family: "Lato","Helvetica Neue",Arial,sans-serif;
24 | font-weight: 700;
25 | }
26 |
27 |
28 | .intro-header {
29 | text-align: center;
30 | }
31 |
32 | .intro-message {
33 | position: relative;
34 | padding-top: 10%;
35 | padding-bottom: 10%;
36 | }
37 |
38 | .intro-message > h1 {
39 | margin: 0;
40 | font-size: 5em;
41 | }
42 |
43 | .intro-divider {
44 | width: 400px;
45 | border-top: 1px solid #f8f8f8;
46 | border-bottom: 1px solid rgba(0,0,0,0.2);
47 | }
48 |
49 | .button-name {
50 | text-transform: uppercase;
51 | font-size: 14px;
52 | font-weight: 400;
53 | letter-spacing: 2px;
54 | }
55 |
56 | .footer {
57 | position: relative;
58 | bottom: 0;
59 | width: 100%;
60 | }
61 |
62 | .top5 { margin-top:5px; }
63 | .top7 { margin-top:7px; }
64 | .top10 { margin-top:10px; }
65 | .top15 { margin-top:15px; }
66 | .top17 { margin-top:17px; }
67 | .top30 { margin-top:30px; }
68 |
69 | .big {
70 | line-height: 150%;
71 | }
72 |
73 | #my-row {
74 | display: table;
75 | }
76 |
77 | #my-row .panel {
78 | float: none;
79 | display: table-cell;
80 | vertical-align: top;
81 | }
82 |
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/jquery.hotkeys.js:
--------------------------------------------------------------------------------
1 | /*jslint browser: true*/
2 | /*jslint jquery: true*/
3 |
4 | /*
5 | * jQuery Hotkeys Plugin
6 | * Copyright 2010, John Resig
7 | * Dual licensed under the MIT or GPL Version 2 licenses.
8 | *
9 | * Based upon the plugin by Tzury Bar Yochay:
10 | * https://github.com/tzuryby/jquery.hotkeys
11 | *
12 | * Original idea by:
13 | * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
14 | */
15 |
16 | /*
17 | * One small change is: now keys are passed by object { keys: '...' }
18 | * Might be useful, when you want to pass some other data to your handler
19 | */
20 |
21 | (function(jQuery) {
22 |
23 | jQuery.hotkeys = {
24 | version: "0.2.0",
25 |
26 | specialKeys: {
27 | 8: "backspace",
28 | 9: "tab",
29 | 10: "return",
30 | 13: "return",
31 | 16: "shift",
32 | 17: "ctrl",
33 | 18: "alt",
34 | 19: "pause",
35 | 20: "capslock",
36 | 27: "esc",
37 | 32: "space",
38 | 33: "pageup",
39 | 34: "pagedown",
40 | 35: "end",
41 | 36: "home",
42 | 37: "left",
43 | 38: "up",
44 | 39: "right",
45 | 40: "down",
46 | 45: "insert",
47 | 46: "del",
48 | 59: ";",
49 | 61: "=",
50 | 96: "0",
51 | 97: "1",
52 | 98: "2",
53 | 99: "3",
54 | 100: "4",
55 | 101: "5",
56 | 102: "6",
57 | 103: "7",
58 | 104: "8",
59 | 105: "9",
60 | 106: "*",
61 | 107: "+",
62 | 109: "-",
63 | 110: ".",
64 | 111: "/",
65 | 112: "f1",
66 | 113: "f2",
67 | 114: "f3",
68 | 115: "f4",
69 | 116: "f5",
70 | 117: "f6",
71 | 118: "f7",
72 | 119: "f8",
73 | 120: "f9",
74 | 121: "f10",
75 | 122: "f11",
76 | 123: "f12",
77 | 144: "numlock",
78 | 145: "scroll",
79 | 173: "-",
80 | 186: ";",
81 | 187: "=",
82 | 188: ",",
83 | 189: "-",
84 | 190: ".",
85 | 191: "/",
86 | 192: "`",
87 | 219: "[",
88 | 220: "\\",
89 | 221: "]",
90 | 222: "'"
91 | },
92 |
93 | shiftNums: {
94 | "`": "~",
95 | "1": "!",
96 | "2": "@",
97 | "3": "#",
98 | "4": "$",
99 | "5": "%",
100 | "6": "^",
101 | "7": "&",
102 | "8": "*",
103 | "9": "(",
104 | "0": ")",
105 | "-": "_",
106 | "=": "+",
107 | ";": ": ",
108 | "'": "\"",
109 | ",": "<",
110 | ".": ">",
111 | "/": "?",
112 | "\\": "|"
113 | },
114 |
115 | // excludes: button, checkbox, file, hidden, image, password, radio, reset, search, submit, url
116 | textAcceptingInputTypes: [
117 | "text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime",
118 | "datetime-local", "search", "color", "tel"],
119 |
120 | // default input types not to bind to unless bound directly
121 | textInputTypes: /textarea|input|select/i,
122 |
123 | options: {
124 | filterInputAcceptingElements: true,
125 | filterTextInputs: true,
126 | filterContentEditable: true
127 | }
128 | };
129 |
130 | function keyHandler(handleObj) {
131 | if (typeof handleObj.data === "string") {
132 | handleObj.data = {
133 | keys: handleObj.data
134 | };
135 | }
136 |
137 | // Only care when a possible input has been specified
138 | if (!handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== "string") {
139 | return;
140 | }
141 |
142 | var origHandler = handleObj.handler,
143 | keys = handleObj.data.keys.toLowerCase().split(" ");
144 |
145 | handleObj.handler = function(event) {
146 | // Don't fire in text-accepting inputs that we didn't directly bind to
147 | if (this !== event.target &&
148 | (jQuery.hotkeys.options.filterInputAcceptingElements &&
149 | jQuery.hotkeys.textInputTypes.test(event.target.nodeName) ||
150 | (jQuery.hotkeys.options.filterContentEditable && jQuery(event.target).attr('contenteditable')) ||
151 | (jQuery.hotkeys.options.filterTextInputs &&
152 | jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1))) {
153 | return;
154 | }
155 |
156 | var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[event.which],
157 | character = String.fromCharCode(event.which).toLowerCase(),
158 | modif = "",
159 | possible = {};
160 |
161 | jQuery.each(["alt", "ctrl", "shift"], function(index, specialKey) {
162 |
163 | if (event[specialKey + 'Key'] && special !== specialKey) {
164 | modif += specialKey + '+';
165 | }
166 | });
167 |
168 | // metaKey is triggered off ctrlKey erronously
169 | if (event.metaKey && !event.ctrlKey && special !== "meta") {
170 | modif += "meta+";
171 | }
172 |
173 | if (event.metaKey && special !== "meta" && modif.indexOf("alt+ctrl+shift+") > -1) {
174 | modif = modif.replace("alt+ctrl+shift+", "hyper+");
175 | }
176 |
177 | if (special) {
178 | possible[modif + special] = true;
179 | }
180 | else {
181 | possible[modif + character] = true;
182 | possible[modif + jQuery.hotkeys.shiftNums[character]] = true;
183 |
184 | // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
185 | if (modif === "shift+") {
186 | possible[jQuery.hotkeys.shiftNums[character]] = true;
187 | }
188 | }
189 |
190 | for (var i = 0, l = keys.length; i < l; i++) {
191 | if (possible[keys[i]]) {
192 | return origHandler.apply(this, arguments);
193 | }
194 | }
195 | };
196 | }
197 |
198 | jQuery.each(["keydown", "keyup", "keypress"], function() {
199 | jQuery.event.special[this] = {
200 | add: keyHandler
201 | };
202 | });
203 |
204 | })(jQuery || this.jQuery || window.jQuery);
205 |
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/marker.js:
--------------------------------------------------------------------------------
1 | var rectsID = [];
2 | var boxes = {};
3 | var chosen_rect;
4 | var imgArray = [];
5 | var arrArray = [];
6 | var validation = {};
7 | var identities = {};
8 | var personID = 0;
9 | var cameras = 7;
10 | var camName = '';
11 | var loadcount = 0;
12 | var zoomOn = false;
13 | var zoomratio = [];
14 | var rotation = [50,230,150,75,265,340,80];
15 | var bounds = [[0,396,1193,180,1883,228,1750,1080],[0,344,1467,77,1920,82,-1,-1],
16 | [97,1080,73,273,864,202,1920,362],[0,444,1920,261,-1,-1,-1,-1],
17 | [0,435,1920,403,-1,-1,-1,-1],[0,243,29,203,656,191,1920,442],
18 | [0,244,1920,162,-1,-1,-1,-1]];
19 | var toggle_ground;
20 | var toggle_orientation;
21 | var to_label = 9;
22 | // hashsets --> rect per camera ? rect -> id to coordinates?
23 | // store variables here? in db ? (reupload db?)
24 | window.onload = function() {
25 | toggle_ground = true;
26 | toggle_orientation = true;
27 |
28 | var d = document.getElementById("changeF");
29 | if(d != null){
30 | d.className = d.className + " disabled";
31 | if(nblabeled >= to_label) {
32 | var button = document.getElementById("changeF");
33 | button.href="/gtm_hit/" + workerID + "/processFrame";
34 | button.text = "Finish";
35 | }
36 | }
37 | if (nblabeled > 0) {
38 | load_prev();
39 | }
40 | camName = cams.substring(2,cams.length-2).split("', '");
41 | for (var i = 0; i < cameras; i++) {
42 | boxes[i] = {};
43 |
44 | arrArray[i] = new Image();
45 | arrArray[i].id=("arrows"+i);
46 | arrArray[i].src = '../../static/gtm_hit/images/arrows'+i+'_3D.png';
47 |
48 | imgArray[i] = new Image();
49 | imgArray[i].id=(i+1);
50 | imgArray[i].onload = function() {
51 | var c = document.getElementById("canv"+this.id);
52 | var ctx = c.getContext('2d');
53 |
54 | ctx.drawImage(this,0,0);
55 | if(toggle_orientation)
56 | drawArrows(ctx,this.id-1);
57 | c.addEventListener('click',mainClick);
58 | loadcount++;
59 | if(loadcount == 7) {
60 | $("#loader").hide();
61 | }
62 | update();
63 | }
64 |
65 | loadcount = 0;
66 | $("#loader").show();
67 | imgArray[i].src = '../../static/gtm_hit/day_2/annotation_final/'+ camName[i]+ '/begin/'+frame_str+'.png'; // change 00..0 by a frame variable
68 | //imgArray[i].src = '../../static/gtm_hit/frames/'+ camName[i]+frame_str+'.png'; // change 00..0 by a frame variable
69 | }
70 |
71 | $(document).bind('keydown', "backspace",backSpace);
72 | $(document).bind('keydown', "left",left);
73 | $(document).bind('keydown', "right",right);
74 | $(document).bind('keydown', "up",up);
75 | $(document).bind('keydown', "down",down);
76 | $(document).bind('keydown', "tab",tab);
77 | $(document).bind('keydown', "space",space);
78 | $(document).bind( "keydown", "e",validate);
79 | $(document).bind( "keydown", "z",zoomControl);
80 | $(document).bind( "keydown", "t",toggleGround);
81 | $(document).bind( "keydown", "h",toggleOrientation);
82 | $("#pID").bind( "keydown", "return",changeID);
83 | $("#pID").val(-1);
84 | $("#pHeight").val(-1);
85 | $("#pWidth").val(-1);
86 |
87 | };
88 |
89 | function mainClick(e) {
90 | var canv = this;
91 | var offset = $(this).offset();
92 | var relativeX = (e.pageX - offset.left)-15;
93 | var relativeY = (e.pageY - offset.top);
94 | var xCorr = Math.round(relativeX*1920/(this.clientWidth-30));
95 | var yCorr = Math.round(relativeY*1080/this.clientHeight);
96 | if(relativeX >=0 && relativeX<=(this.clientWidth - 29)) {
97 | if(zoomOn)
98 | zoomOut();
99 | //post
100 | $.ajax({
101 | method: "POST",
102 | url: "click",
103 | data: {
104 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
105 | x: xCorr,
106 | y: yCorr,
107 | canv: this.id
108 | },
109 | dataType: "json",
110 | success: function(msg) {
111 | var rid = msg[0].rectangleID;
112 | var indof = rectsID.indexOf(rid);
113 | if(indof == -1) {
114 | rectsID.push(rid);
115 | chosen_rect = rectsID.length-1;
116 | while(personID in validation)
117 | personID++;
118 | identities[rid] = personID;
119 | validation[personID] = true;
120 | saveRect(msg,personID);
121 | } else {
122 | chosen_rect = indof;
123 | }
124 | update();
125 | }
126 | });
127 |
128 | }
129 | }
130 |
131 | function backSpace() {
132 | if (rectsID.length > 0){
133 | var rid = rectsID[chosen_rect];
134 | rectsID.splice(chosen_rect,1);
135 | var idPers = identities[rid];
136 | delete validation[idPers];
137 | delete identities[rid];
138 | //validation_dict.pop(idPers)
139 | //identities.pop(idRect)
140 | //for i in range(NB_PICTURES):
141 | // if idPers in person_rect[i]:
142 | // person_rect[i].pop(idPers)
143 | if (chosen_rect == rectsID.length) {
144 | chosen_rect--;
145 | }
146 | if(zoomOn) {
147 | zoomOut();
148 | }
149 | update();
150 | }
151 | return false;
152 | }
153 |
154 | function tab() {
155 | if (rectsID.length <= 1)
156 | return false;
157 |
158 | chosen_rect++;
159 | if(zoomOn)
160 | zoomOut();
161 | update();
162 | return false;
163 |
164 | }
165 |
166 | function space() {
167 | if (rectsID.length <= 1)
168 | return false;
169 |
170 | chosen_rect--;
171 | if(zoomOn)
172 | zoomOut();
173 | update();
174 | return false;
175 | }
176 |
177 | function left() {
178 | sendAJAX("move","left",rectsID[chosen_rect],moveRect);
179 | update();
180 | return false;
181 | }
182 |
183 | function right() {
184 | sendAJAX("move","right",rectsID[chosen_rect],moveRect);
185 | update();
186 | return false;
187 | }
188 |
189 | function up() {
190 | sendAJAX("move","up",rectsID[chosen_rect],moveRect);
191 | update();
192 | return false;
193 | }
194 |
195 | function down() {
196 | sendAJAX("move","down",rectsID[chosen_rect],moveRect);
197 | update()
198 | return false;
199 | }
200 |
201 | function incrWidth() {
202 | var ind = getIndx();
203 | var pid = identities[rectsID[chosen_rect]];
204 | var rect = boxes[ind][pid];
205 | rect.x1 = rect.x1-1;
206 | rect.x2 = rect.x2+1;
207 | boxes[ind][pid] = rect;
208 |
209 | var size = (rect.x2-rect.x1)*rect.ratio;
210 | updateSize(false,size,ind);
211 | return false;
212 |
213 | }
214 |
215 | function decrWidth() {
216 | var ind = getIndx();
217 | var pid = identities[rectsID[chosen_rect]];
218 | var rect = boxes[ind][pid];
219 | rect.x1 = rect.x1+1;
220 | if(rect.x2 - rect.x1 < 1) {
221 | rect.x1 = rect.x2 -1;
222 | } else {
223 | rect.x2 = rect.x2-1;
224 | }
225 | boxes[ind][pid] = rect;
226 | var size = (rect.x2-rect.x1)*rect.ratio;
227 | updateSize(false,size,ind);
228 | return false;
229 |
230 | }
231 |
232 | function incrHeight() {
233 |
234 | var ind = getIndx();
235 | var pid = identities[rectsID[chosen_rect]];
236 | var rect = boxes[ind][pid];
237 | rect.y1 = rect.y1-1;
238 | boxes[ind][pid] = rect;
239 |
240 | var size = (rect.y2-rect.y1)*rect.ratio;
241 | updateSize(true,size,ind);
242 | return false;
243 |
244 | }
245 |
246 | function decrHeight() {
247 | var ind = getIndx();
248 | var pid = identities[rectsID[chosen_rect]];
249 | var rect = boxes[ind][pid];
250 | rect.y1 = rect.y1+1;
251 | if(rect.y2 - rect.y1 < 1) {
252 | rect.y1 = rect.y2-1;
253 | }
254 | boxes[ind][pid] = rect;
255 |
256 | var size = (rect.y2-rect.y1)*rect.ratio;
257 | updateSize(true,size,ind);
258 | return false;
259 | }
260 |
261 | function getIndx() {
262 | var h = -1;
263 | var retInd = -1;
264 | var pid = identities[rectsID[chosen_rect]];
265 | for (var i = 0; i < cameras; i++) {
266 | r = boxes[i][pid];
267 | tpH = Math.abs(r.y1 - r.y2);
268 |
269 | if(tpH > h) {
270 | h = tpH;
271 | retInd = i;
272 | }
273 | }
274 | return retInd;
275 | }
276 |
277 | function updateSize(height,size,ind) {
278 | var r = rectsID[chosen_rect];
279 | var pid = identities[r];
280 | for (var i = 0; i < cameras; i++) {
281 | rect = boxes[i][pid];
282 | if(i != ind && rect.y1 != 0) {
283 | if(height) {
284 | var b = Math.round(rect.y2 - size/rect.ratio);
285 | if(rect.y2 - b < 1)
286 | b = rect.y2 - 1;
287 | rect.y1 = b;
288 | } else {
289 | var delta = size/(2*rect.ratio);
290 | var c = Math.round(rect.xMid + delta);
291 | var a = Math.round(rect.xMid - delta);
292 | if(c - a < 1)
293 | a = c - 1;
294 | rect.x1 = a;
295 | rect.x2 = c;
296 | }
297 | }
298 | boxes[i][pid] = rect;
299 | }
300 | update()
301 | }
302 |
303 | function save() {
304 | var dims = {};
305 | var k = 0;
306 | for (var i = 0; i < rectsID.length; i++) {
307 | var rid = rectsID[i];
308 | var pid = identities[rid];
309 | dims[rid] = [];
310 | dims[rid].push(pid);
311 | dims[rid].push(validation[pid]);
312 | }
313 |
314 | for (var i = 0; i < cameras; i++) {
315 | for (var j = 0; j < rectsID.length; j++) {
316 | var rid = rectsID[j];
317 | var pid = identities[rid];
318 |
319 | var field = boxes[i][pid];
320 | if(field.x2 != 0){
321 | dims[rid].push(field.x1);
322 | dims[rid].push(field.y1);
323 | dims[rid].push(field.x2);
324 | dims[rid].push(field.y2);
325 | } else {
326 | dims[rid].push(-1);
327 | dims[rid].push(-1);
328 | dims[rid].push(-1);
329 | dims[rid].push(-1);
330 | }
331 | }
332 | }
333 | $.ajax({
334 | method: "POST",
335 | url: 'save',
336 | data: {
337 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
338 | data: JSON.stringify(dims),
339 | ID: frame_str,
340 | workerID: workerID
341 | },
342 | success: function(msg) {
343 | console.log(msg);
344 | }
345 | });
346 |
347 | }
348 |
349 | function load() {
350 | loader('load');
351 | }
352 |
353 | function load_prev() {
354 | loader('loadprev');
355 |
356 | }
357 |
358 | function loader(uri) {
359 |
360 | $.ajax({
361 | method: "POST",
362 | url: uri,
363 | data: {
364 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
365 | ID: frame_str,
366 | workerID: workerID
367 | },
368 | dataType: 'json',
369 | success: function(msg) {
370 | clean();
371 | var maxID = 0;
372 | for (var i = 0; i < msg.length; i++) {
373 | var rid = msg[i][0].rectangleID;
374 | var indof = rectsID.indexOf(rid);
375 | if(indof == -1) {
376 | rectsID.push(rid);
377 | saveRectLoad(msg[i]);
378 | chosen_rect = rectsID.length-1;
379 | identities[rid] = msg[i][7];
380 | var pid = msg[i][7];
381 | if(pid > maxID)
382 | maxID = pid;
383 | if(uri == "loadprev")
384 | validation[pid] = false;
385 | else
386 | validation[pid] = msg[i][8];
387 | }
388 | }
389 | personID = maxID + 1;
390 | update();
391 |
392 | }
393 | });
394 | }
395 | function clean() {
396 | for (var i = 0; i < cameras; i++) {
397 | boxes[i] = {};
398 | rectsID = [];
399 | validation = {};
400 | identities = {};
401 | personID = 0;
402 | chosen_rect = 0;
403 | }
404 | update();
405 | }
406 |
407 | function changeFrame(order,increment) {
408 | save();
409 | if(nblabeled >= to_label) {
410 | return true;
411 | }
412 | $.ajax({
413 | method: "POST",
414 | url: 'changeframe',
415 | data: {
416 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
417 | order: order,
418 | frameID: frame_str,
419 | incr: increment,
420 | workerID: workerID
421 | },
422 | dataType: "json",
423 | success: function(msg) {
424 | frame_str = msg['frame'];
425 | nblabeled = msg['nblabeled'];
426 | if(nblabeled >= to_label) {
427 | var button = document.getElementById("changeF");
428 | button.href="/gtm_hit/" + workerID + "/processFrame";
429 | button.text = "Finish";
430 | }
431 | loadcount = 0;
432 | $("#loader").show();
433 | fstr = frame_str;
434 | fstr = fstr.replace(/^0*/, "");
435 | $("#frameID").html("Frame ID: " + fstr +" ");
436 | for (var i = 0; i < cameras; i++)
437 | imgArray[i].src = '../../static/gtm_hit/day_2/annotation_final/'+ camName[i]+ '/begin/'+frame_str+'.png'; // change 00..0 by a frame variable
438 | //imgArray[i].src = '../../static/gtm_hit/frames/'+ camName[i]+frame_str+'.png'; // change 00..0 by a frame variable
439 |
440 | },
441 | complete: function() {
442 | load_prev();
443 | }
444 | });
445 |
446 | }
447 |
448 | function next() {
449 | changeFrame('next',1);
450 | }
451 |
452 | function prev() {
453 | changeFrame('prev',1);
454 | }
455 |
456 | function nextI() {
457 | changeFrame('next',10);
458 | }
459 |
460 | function prevI() {
461 | changeFrame('prev',10);
462 | }
463 |
464 | function validate() {
465 | var rid = rectsID[chosen_rect];
466 | var idPers = identities[rid];
467 | validation[idPers] = true;
468 | return false;
469 | }
470 |
471 | function changeID() {
472 | var newID = parseInt($("#pID").val());
473 | if (rectsID.length > 0 && newID >= 0) {
474 | var rid = rectsID[chosen_rect];
475 | var pid = identities[rid];
476 | var match = false;
477 | for (key in identities) {
478 | if (identities[key] == newID)
479 | match = true;
480 | }
481 | if(!match) {
482 | validation[newID]= validation[pid];
483 | delete validation[pid];
484 | identities[rid] = newID;
485 | for(key in boxes){
486 | if(pid in boxes[key]){
487 | var args = boxes[key][pid];
488 | boxes[key][newID] = args;
489 | delete boxes[key][pid];
490 | }
491 | }
492 | $("#pID").val(newID);
493 | } else {
494 | $("#pID").val(pid);
495 | }
496 | }
497 | }
498 |
499 | function sendAJAX(uri,data,id,suc) {
500 | $.ajax({
501 | method: "POST",
502 | url: uri,
503 | data: {
504 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
505 | data: data,
506 | ID: id
507 | },
508 | dataType: "json",
509 | success: function(msg) {
510 | if(msg.length > 0)
511 | suc(msg,id);
512 | update();
513 | }
514 | });
515 | }
516 |
517 | function saveRect(msg,pid) {
518 | for (var i = 0; i < msg.length; i++) {
519 | var ind = msg[i].cameraID;
520 | boxes[ind][pid] = msg[i];
521 | }
522 | }
523 |
524 | function saveRectLoad(msg) {
525 | for (var i = 0; i < msg.length-2; i++) {
526 | var ind = msg[i].cameraID;
527 | boxes[ind][msg[7]] = msg[i];
528 | }
529 | }
530 |
531 | function moveRect(msg,id) {
532 | var pid = identities[id];
533 | if(typeof boxes[0][pid] == "undefined") {
534 | return false;
535 | }
536 | var index = rectsID.indexOf(id);
537 | var nextRect = msg[0].rectangleID;
538 | rectsID.splice(index,1);
539 | rectsID.push(nextRect);
540 | chosen_rect = rectsID.length-1;
541 | identities[nextRect] = pid;
542 | delete identities[id];
543 | validation[pid] = true;
544 |
545 | for (var i = 0; i < msg.length; i++) {
546 | var f = msg[i];
547 | var ind = f.cameraID;
548 | var oldRect = boxes[ind][pid];
549 |
550 | var newRect = msg[i];
551 | var heightR = Math.abs(oldRect.y1-oldRect.y2)*oldRect.ratio;
552 | var widthR = Math.abs(oldRect.x1-oldRect.x2)*oldRect.ratio;
553 |
554 | if(newRect.ratio > 0){
555 | newRect.y1 = Math.round(newRect.y2 - (heightR/newRect.ratio));
556 | var delta = widthR/(2*newRect.ratio);
557 | newRect.x2 = Math.round(newRect.xMid + delta);
558 | newRect.x1 = Math.round(newRect.xMid - delta);
559 | }
560 | boxes[ind][pid] = newRect;
561 | }
562 | }
563 |
564 | function update() {
565 | chosen_rect = ((chosen_rect % rectsID.length) + rectsID.length) % rectsID.length;
566 | $("#pID").val(identities[rectsID[chosen_rect]]);
567 |
568 | drawRect();
569 | if(toggle_ground)
570 | drawGround();
571 |
572 | var d = document.getElementById("changeF");
573 | if(d!=null) {
574 | if (rectsID.length > 1) {
575 | if(checkRects())
576 | d.className = d.className.replace(" disabled","");
577 | else if(d.className.indexOf("disabled") == -1)
578 | d.className = d.className + " disabled";
579 | } else if(d.className.indexOf("disabled") == -1) {
580 | d.className = d.className + " disabled";
581 | }
582 | }
583 | }
584 |
585 | function drawRect() {
586 | for (var i = 0; i < cameras; i++) {
587 | var c = document.getElementById("canv"+(i+1));
588 | var ctx=c.getContext("2d");
589 | ctx.clearRect(0, 0, c.width, c.height);
590 | ctx.drawImage(imgArray[i],0,0);
591 | if(toggle_orientation)
592 | drawArrows(ctx,i);
593 | }
594 | var heightR = 0;
595 | var widthR = 0;
596 | var sumH = 0;
597 | for (key in boxes) {
598 | for (var r = 0; r < rectsID.length; r++) {
599 | var field = boxes[key][identities[rectsID[r]]];
600 | if(field.y1 != -1 && field.y2 != -1 && field.x1 != -1) {
601 | var c = document.getElementById("canv"+(field.cameraID+1));
602 | var ctx=c.getContext("2d");
603 | var w = field.x2 - field.x1;
604 | var h = field.y2 - field.y1;
605 | if(r == chosen_rect) {
606 | ctx.strokeStyle="cyan";
607 | ctx.lineWidth="7";
608 | heightR += (field.y2-field.y1)*field.ratio;
609 | widthR += (field.x2-field.x1)*field.ratio;
610 | sumH += 1;
611 | } else {
612 | var pid = identities[field.rectangleID];
613 | if(validation[pid])
614 | ctx.strokeStyle="white";
615 | else
616 | ctx.strokeStyle="yellow";
617 | ctx.lineWidth="4";
618 | }
619 | ctx.beginPath();
620 | ctx.rect(field.x1,field.y1,w,h);
621 | ctx.stroke();
622 | ctx.closePath();
623 |
624 | ctx.beginPath();
625 | ctx.fillStyle = "red";
626 | ctx.fillRect(field.xMid-5,field.y2-5,10,10);
627 | ctx.stroke();
628 | ctx.closePath();
629 |
630 | }
631 | }
632 | }
633 | if(chosen_rect >= 0) {
634 | $("#pHeight").text(Math.round(heightR/sumH));
635 | $("#pWidth").text(Math.round(widthR/sumH));
636 | } else {
637 | $("#pHeight").text(-1);
638 | $("#pWidth").text(-1);
639 | }
640 |
641 | }
642 |
643 | function drawGround() {
644 | for (var i = 0; i < cameras; i++) {
645 | var c = document.getElementById("canv"+(i+1));
646 | var ctx=c.getContext("2d");
647 | ctx.strokeStyle="chartreuse";
648 | ctx.lineWidth="2";
649 | ctx.beginPath();
650 |
651 | ctx.moveTo(bounds[i][0], bounds[i][1]);
652 | for (var j = 2; j < bounds[i].length; j=j+2) {
653 | if(bounds[i][j] >= 0) {
654 | ctx.lineTo(bounds[i][j], bounds[i][j+1]);
655 | }
656 | }
657 | ctx.stroke();
658 | ctx.closePath();
659 |
660 | }
661 | }
662 |
663 | function drawArrows(ctx, idx) {
664 | ctx.drawImage(arrArray[idx],0,0);
665 | }
666 |
667 | function zoomControl() {
668 | if(rectsID.length > 0){
669 | if(!zoomOn) {
670 | zoomIn();
671 | } else {
672 | zoomOut();
673 | }
674 |
675 | }
676 | update();
677 | }
678 |
679 | function zoomIn() {
680 | for (var i = 0; i < cameras; i++) {
681 | var pid = identities[rectsID[chosen_rect]];
682 | var r = boxes[i][pid];
683 |
684 | var c = document.getElementById("canv"+(i+1));
685 |
686 | zoomratio[i] = c.height*60/(100*(r.y2-r.y1));
687 | if(zoomratio[i] != Infinity) {
688 |
689 | var ctx = c.getContext('2d');
690 | c.width=c.width/zoomratio[i];
691 | c.height=c.height/zoomratio[i];
692 | var originx = r.xMid - c.width/2;
693 | // var originx = r.xMid;
694 | var originy = r.y1-12.5*c.clientHeight/100;
695 | // ctx.scale(1.75,1.75);
696 | ctx.translate(-originx, -originy);
697 |
698 | }
699 | }
700 | zoomOn = true;
701 | return false;
702 |
703 | }
704 |
705 | function zoomOut() {
706 | for (var i = 0; i < cameras; i++) {
707 | var c = document.getElementById("canv"+(i+1));
708 | if(zoomratio[i] != Infinity) {
709 | c.width=c.width*zoomratio[i];
710 | c.height=c.height*zoomratio[i];
711 | }
712 | }
713 | zoomOn = false;
714 | return false;
715 | }
716 |
717 | function toggleGround() {
718 | if(toggle_ground == false)
719 | toggle_ground = true;
720 | else
721 | toggle_ground=false;
722 | update();
723 | return false;
724 | }
725 |
726 | function toggleOrientation() {
727 | if(toggle_orientation == false)
728 | toggle_orientation = true;
729 | else
730 | toggle_orientation=false;
731 | update();
732 | return false;
733 | }
734 |
735 | function checkRects() {
736 | var c = 0;
737 | for (var i = 0; i < rectsID.length; i++) {
738 | var personID = identities[rectsID[i]];
739 | if(validation[personID])
740 | c++;
741 | }
742 | if(c > 1)
743 | return true;
744 | else
745 | return false;
746 | }
747 |
--------------------------------------------------------------------------------
/gtm_hit/static/gtm_hit/tuto.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Start Bootstrap - Landing Page (http://startbootstrap.com/)
3 | * Copyright 2013-2016 Start Bootstrap
4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
5 | */
6 |
7 | body,
8 | html {
9 | width: 100%;
10 | height: 100%;
11 | }
12 |
13 | body {
14 | font-family: "Lato","Helvetica Neue",Arial,sans-serif;
15 | font-weight: 500;
16 | }
17 | h1,
18 | h2,
19 | h3,
20 | h4,
21 | h5,
22 | h6 {
23 | font-family: "Lato","Helvetica Neue",Arial,sans-serif;
24 | font-weight: 600;
25 | }
26 |
27 | .nav-tabs > li, .nav-pills > li {
28 | float:none;
29 | display:inline-block;
30 | }
31 |
32 | .nav-tabs, .nav-pills {
33 | text-align:center;
34 | }
35 | .intro-header {
36 | text-align: center;
37 | }
38 |
39 | .intro-message {
40 | position: relative;
41 | padding-top: 5%;
42 | padding-bottom: 2%;
43 | }
44 |
45 | .intro-message > h1 {
46 | margin: 0;
47 | font-size: 5em;
48 | }
49 |
50 | .intro-divider {
51 | width: 400px;
52 | border-top: 1px solid #f8f8f8;
53 | border-bottom: 1px solid rgba(0,0,0,0.2);
54 | }
55 |
56 | .button-name {
57 | text-transform: uppercase;
58 | font-size: 14px;
59 | font-weight: 400;
60 | letter-spacing: 2px;
61 | }
62 |
63 | .footer {
64 | position: relative;
65 | bottom: 0;
66 | width: 100%;
67 | }
68 |
69 | .top5 { margin-top:5px; }
70 | .top7 { margin-top:7px; }
71 | .top10 { margin-top:10px; }
72 | .top15 { margin-top:15px; }
73 | .top17 { margin-top:17px; }
74 | .top30 { margin-top:30px; }
75 |
76 | .big {
77 | line-height: 150%;
78 | }
79 |
80 | #my-row {
81 | display: table;
82 | }
83 |
84 | #my-row .panel {
85 | float: none;
86 | display: table-cell;
87 | vertical-align: top;
88 | }
89 |
--------------------------------------------------------------------------------
/gtm_hit/templates/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/templates/.DS_Store
--------------------------------------------------------------------------------
/gtm_hit/templates/gtm_hit/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/templates/gtm_hit/.DS_Store
--------------------------------------------------------------------------------
/gtm_hit/templates/gtm_hit/finish.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
31 |
32 |
33 | {% include "includes_hit/navbar.html" %}
34 | {% csrf_token %}
35 |
55 | {% include "includes_hit/footer.html" %}
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/gtm_hit/templates/gtm_hit/frame.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
23 |
24 |
25 | {% include "includes_hit/navbar.html" %}
26 |
27 | {% csrf_token %}
28 |
29 |
30 |
31 |
32 |
33 |
Loading ... please wait until this text disappear
34 |
35 | Frame ID: {{frame_number}}
36 | Next frame
37 |
38 |
39 |
40 |
41 |
54 |
55 |
56 |
57 | {% include "includes_hit/side_menu.html" %}
58 | {% include "includes_hit/controller.html" %}
59 |
60 |
61 |
62 | {% include "includes_hit/footer.html" %}
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/gtm_hit/templates/gtm_hit/index.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 | {% include "includes_hit/navbar.html" %}
18 | {% csrf_token %}
19 |
43 | {% include "includes_hit/footer.html" %}
44 |
45 | {% include "includes_hit/help.html" %}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/gtm_hit/templates/gtm_hit/requestID.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {% include "includes_hit/navbar.html" %}
14 | {% csrf_token %}
15 |
44 | {% include "includes_hit/footer.html" %}
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/gtm_hit/templates/gtm_hit/tuto.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
56 |
57 |
58 | {% include "includes_hit/navbar.html" %}
59 | {% csrf_token %}
60 |
142 | {% include "includes_hit/footer.html" %}
143 |
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/gtm_hit/templates/includes_hit/controller.html:
--------------------------------------------------------------------------------
1 | {% load marker_extra%}
2 |
3 |
4 |
5 |
6 |
Selection
7 |
8 |
9 | Next
10 | Previous
11 |
12 |
Remove
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Position
20 |
21 |
22 | Up
23 | Down
24 |
25 |
26 | Right
27 | Left
28 |
29 |
30 |
31 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/gtm_hit/templates/includes_hit/footer.html:
--------------------------------------------------------------------------------
1 |
8 |
12 |
--------------------------------------------------------------------------------
/gtm_hit/templates/includes_hit/help.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
Your task
24 |
As previously mentionned, you will be asked to label images, i.e. to place bounding boxes around people. You will see 7 images at the same time which corresponds to multiple views of a scene.
25 | Try to put bounding boxes around all the people you can (some of them are not in the ground area, don't worry about them).
26 | After having labeled a frame, the bounding boxes you placed will stay on the next frame and turn yellow.
27 | Since the people do not move a lot between two consecutive frames, you will only have to switch between the bounding boxes ( with tab ) and adjust their position using the arrow keys.
28 | The task will end once you have labeled 10 frames.
29 | Use your left click to place a bounding box on an image. The bottom of the bounding box will be centered on the point you click on, so aim at the feets.
30 | The red dot at the bottom of the bouding box corresponds to a point on the ground. To correctly place a bounding box, this point should be placed at the center of the person, on the ground. (See Example 1 )
31 | Use the arrow keys to move a bounding box on the images. Each view has a different orientation. Look at the small keys on the top left of each image to know in which direction goes each arrow. (See Example 2 )
32 | Take a look at all the tutorial tabs before starting. The second example contains and summarizes everyting you need to know
33 |
Note: Since accuracy is very important, do not hesitate to use the z key to zoom on the selected bounding box.
34 |
35 |
36 |
37 |
38 |
39 | Left click (on an image) : place a bounding box.
40 | Arrows : move the selected bounding box.
41 | z : zoom on the selected bounding box (press again to zoom out).
42 | Backspace : remove the selected bounding box.
43 | Space / Tab : select the next/previous the bounding box.
44 | e : validate the placement of a yellow bounding box.
45 | h : hide/show the orientation helper.
46 | t : hide/show the ground area limits.
47 | Cyan box : selected bounding box
48 | White box : standard bounding box
49 | Yellow box : Unvalidated bounding box
50 | The bounding box should surround the person on all images it appears. (see Example 1 tab)
51 |
52 |
53 |
54 |
55 |
56 |
The bounding box should surround the person on all images it appears.
57 |
58 | Good
59 | All the bounding boxes sourround the lady
60 |
61 | Bad
62 | The box seems correctly placed on the top right image, but not in the other images.
63 | In this case, you have to adjust the position using the arrows to obtain the results seen on the "Good" example
64 |
65 |
66 |
67 |
68 |
69 |
70 |
The bounding box should surround the person on all images it appears.
71 |
72 | Note that the orientation helper and the blue arrows have another orientation on every frame since the angle changes.
73 |
74 |
75 |
76 |
77 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/gtm_hit/templates/includes_hit/navbar.html:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 | {% if user.is_authenticated %}
11 | Logout
12 | {% endif %}
13 | Help
14 |
15 |
16 |
17 | {% include "includes_hit/help.html" %}
18 |
--------------------------------------------------------------------------------
/gtm_hit/templates/includes_hit/side_menu.html:
--------------------------------------------------------------------------------
1 | {% load gtm_hit_extra%}
2 |
3 |
4 |
5 |
Infos
6 |
7 |
Person height:
8 |
-1
9 |
10 |
11 |
12 |
Person width:
13 |
-1
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/gtm_hit/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtm_hit/templatetags/__init__.py
--------------------------------------------------------------------------------
/gtm_hit/templatetags/gtm_hit_extra.py:
--------------------------------------------------------------------------------
1 | from django import template
2 | from marker.models import *
3 | from django.utils import timezone
4 | import json
5 | from django.core import serializers
6 |
7 | register = template.Library()
8 |
9 | @register.filter(name='next')
10 | def next(value):
11 | return int(value)+1
12 |
13 | @register.filter(name='prev')
14 | def prev(value):
15 | f = int(value)
16 | if f > 0:
17 | return f-1
18 | else:
19 | return f
20 |
21 | @register.filter(name='toJSON')
22 | def toJSON(value):
23 | return serializers.serialize("json",value)
24 |
--------------------------------------------------------------------------------
/gtm_hit/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/gtm_hit/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | url(r'^&MID=(?P
[A-Z0-9]+)$', views.index, name="index"),
7 | url(r'^$', views.requestID, name="requestID"),
8 | url(r'^(?P[A-Z0-9]+)/processInit$', views.processInit, name="processInit"),
9 | url(r'^(?P[A-Z0-9]+)/processIndex$', views.processIndex, name="processIndex"),
10 | url(r'^(?P[A-Z0-9]+)/processTuto$', views.processTuto, name="processTuto"),
11 | url(r'^(?P[A-Z0-9]+)$', views.dispatch, name="dispatch"),
12 | url(r'^(?P[A-Z0-9]+)/index$', views.index, name="index"),
13 | url(r'^(?P[A-Z0-9]+)/tuto$', views.tuto, name="tuto"),
14 | url(r'^(?P[A-Z0-9]+)/frame$', views.frame, name='frame'),
15 | url(r'^(?P[A-Z0-9]+)/processFrame$', views.processFrame, name="processFrame"),
16 | url(r'^.*click',views.click,name="click"),
17 | url(r'^.*move',views.move,name="move"),
18 | url(r'^.*changeframe$', views.changeframe, name='changeframe'),
19 | url(r'^.*save$',views.save,name='save'),
20 | url(r'^.*load$',views.load,name='load'),
21 | url(r'^.*loadprev$',views.load_previous,name='loadprev'),
22 | url(r'^.*processFinish$',views.processFinish,name='processFinish'),
23 |
24 | url(r'^(?P[A-Z0-9]+)/finish$',views.finish,name='finish'),
25 | ]
26 |
--------------------------------------------------------------------------------
/gtm_hit/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from django.shortcuts import get_object_or_404,render, redirect
3 | from django.contrib.auth import authenticate, login, logout
4 | from django.template.loader import render_to_string
5 | from django.contrib.auth.decorators import login_required
6 | from django.http import HttpResponseRedirect, HttpResponse
7 | from django.core import serializers
8 | from django.core.urlresolvers import reverse
9 | from django.views import generic
10 | from django.utils import timezone
11 | from django.conf import settings
12 | from .models import Worker, ValidationCode
13 | from django.template import RequestContext
14 | import re
15 | import json
16 | import os
17 | import random as rand
18 | from threading import Thread
19 |
20 | def requestID(request):
21 | context = RequestContext(request)
22 | if request.method == "POST":
23 | if 'wID' in request.POST:
24 | workerID = request.POST['wID']
25 | pattern = re.compile("^[A-Z0-9]+$")
26 | if pattern.match(workerID):
27 | return redirect("/gtm_hit/"+workerID+"/processInit")
28 | return render(request, 'gtm_hit/requestID.html',{},context)
29 |
30 | def processInit(request, workerID):
31 | context = RequestContext(request)
32 | try:
33 | w = Worker.objects.get(pk = workerID)
34 | if w.state == -1:
35 | w.state = 0
36 | w.save()
37 | return redirect("/gtm_hit/"+workerID)
38 | except Worker.DoesNotExist:
39 | return redirect("/gtm_hit/"+workerID)
40 |
41 | def index(request,workerID):
42 | context = RequestContext(request)
43 | try:
44 | w = Worker.objects.get(pk = workerID)
45 | if w.state != 0:
46 | return redirect("/gtm_hit/"+workerID)
47 | return render(request, 'gtm_hit/index.html',{'workerID' : workerID},context)
48 |
49 | except Worker.DoesNotExist:
50 | return redirect("/gtm_hit/"+workerID)
51 |
52 | def processIndex(request, workerID):
53 | context = RequestContext(request)
54 | try:
55 | w = Worker.objects.get(pk = workerID)
56 | if w.state == 0:
57 | w.state = 3
58 | w.save()
59 | except Worker.DoesNotExist:
60 | return redirect("/gtm_hit/"+workerID)
61 | return redirect("/gtm_hit/"+workerID)
62 |
63 | def dispatch(request,workerID):
64 | context = RequestContext(request)
65 | try:
66 | w = Worker.objects.get(pk = workerID)
67 | try:
68 | code = ValidationCode.objects.get(worker_id = w)
69 | stop = False
70 | i = 2
71 | while not stop:
72 | try:
73 | w2 = Worker.objects.get(pk = workerID+str(i))
74 | c2 = ValidationCode.objects.get(worker_id = w2)
75 | i = i + 1
76 | except Worker.DoesNotExist:
77 | stop = True
78 | except ValidationCode.DoesNotExist:
79 | return redirect("/gtm_hit/"+workerID+str(i))
80 | return redirect("/gtm_hit/"+workerID+str(i))
81 | except ValidationCode.DoesNotExist:
82 | pass
83 | except Worker.DoesNotExist:
84 | w = registerWorker(workerID)
85 |
86 | state = w.state
87 | if state == 0:
88 | return redirect(workerID+'/index')
89 | #return render(request, 'gtm_hit/frame.html',{'frame_number': frame_number, 'workerID' : workerID},context)
90 | elif state == 1:
91 | return redirect(workerID+'/frame')
92 | # return render(request, 'gtm_hit/finish.html',{'workerID' : workerID, 'validation_code' : validation_code},context)
93 | elif state == 2:
94 | return redirect(workerID+'/finish')
95 | # return render(request, 'gtm_hit/finish.html',{'workerID' : workerID, 'validation_code' : validation_code},context)
96 | elif state == 3:
97 | return redirect(workerID+'/tuto')
98 | elif state == -1:
99 | return redirect(workerID+'/processInit')
100 | #return render(request, 'gtm_hit/index.html',{'workerID' : workerID},context)
101 | else:
102 | return redirect(workerID+'/index')
103 | #return render(request, 'gtm_hit/index.html',{'workerID' : workerID},context)
104 |
105 | def frame(request,workerID):
106 | context = RequestContext(request)
107 | try:
108 | w = Worker.objects.get(pk = workerID)
109 | if w.state != 1:
110 | return redirect("/gtm_hit/"+workerID)
111 | if w.frameNB < 0:
112 | w.frameNB = settings.STARTFRAME
113 | w.save()
114 | frame_number = w.frameNB
115 | nblabeled = w.frame_labeled
116 | return render(request, 'gtm_hit/frame.html',{'frame_number': frame_number, 'workerID': workerID,'cams': settings.CAMS, 'path': settings.SERVER_PATH, 'nblabeled' : nblabeled},context)
117 | except Worker.DoesNotExist:
118 | return redirect("/gtm_hit/"+workerID)
119 |
120 | def processFrame(request,workerID):
121 | context = RequestContext(request)
122 | try:
123 | w = Worker.objects.get(pk = workerID)
124 | if w.state == 1 and w.frame_labeled >= 9:
125 | w.state = 2
126 | timelist = w.getTimeList()
127 | timelist.append(timezone.now().isoformat())
128 | w.setTimeList(timelist)
129 | w.save()
130 | return redirect("/gtm_hit/"+workerID)
131 | except Worker.DoesNotExist:
132 | return redirect("/gtm_hit/"+workerID)
133 |
134 | def finish(request,workerID):
135 | context = RequestContext(request)
136 | try:
137 | w = Worker.objects.get(pk = workerID)
138 | if w.state == 2:
139 | validation_code = generate_code(w)
140 | startframe = w.frameNB - (w.frame_labeled*5)
141 | try:
142 | settings.UNLABELED.remove(startframe)
143 | except ValueError:
144 | pass
145 | return render(request, 'gtm_hit/finish.html',{'workerID': workerID, 'validation_code': validation_code},context)
146 | except Worker.DoesNotExist:
147 | return redirect("/gtm_hit/"+workerID)
148 | return redirect("/gtm_hit/"+workerID)
149 |
150 | def click(request):
151 | if request.is_ajax():
152 | try:
153 | x = int(request.POST['x'])
154 | y = int(request.POST['y'])
155 | cam = request.POST['canv']
156 | cam = int(re.findall('\d+',cam)[0]) - 1
157 | if 0 <= cam < settings.NB_CAMS:
158 | closest = -1
159 | vbest = 1000
160 | for y_temp in range(y - settings.DELTA_SEARCH, y + settings.DELTA_SEARCH):
161 | if 0 <= y_temp < 1080:
162 | for x_temp in settings.FIND_RECT[cam][y_temp]:
163 | vtemp = abs(y - y_temp) + abs(x - x_temp)
164 | if vtemp < vbest:
165 | vbest, closest = vtemp, settings.FIND_RECT[cam][y_temp][x_temp]
166 | if closest != -1:
167 | rects = get_rect(closest)
168 | rect_json = json.dumps(rects)
169 | return HttpResponse(rect_json,content_type="application/json")
170 |
171 | return HttpResponse("OK")
172 | except KeyError:
173 | return HttpResponse("Error")
174 | return HttpResponse("No")
175 |
176 | def move(request):
177 | if request.is_ajax():
178 | try:
179 | if request.POST['data'] == "down":
180 | rectID = request.POST['ID']
181 | if int(rectID) // settings.NB_WIDTH > 0:
182 | nextID = int(rectID) - settings.NB_WIDTH
183 | else:
184 | return HttpResponse(json.dumps([]),content_type="application/json")
185 |
186 | elif request.POST['data'] == "up":
187 | rectID = request.POST['ID']
188 | if int(rectID) // settings.NB_WIDTH < settings.NB_HEIGHT - 1:
189 | nextID = int(rectID) + settings.NB_WIDTH
190 | else:
191 | return HttpResponse(json.dumps([]),content_type="application/json")
192 |
193 | elif request.POST['data'] == "right":
194 | rectID = request.POST['ID']
195 | if int(rectID) % settings.NB_WIDTH < settings.NB_WIDTH - 1:
196 | nextID = int(rectID) + 1
197 | else:
198 | return HttpResponse(json.dumps([]),content_type="application/json")
199 |
200 | elif request.POST['data'] == "left":
201 | rectID = request.POST['ID']
202 | if int(rectID) % settings.NB_WIDTH > 0:
203 | nextID = int(rectID) - 1
204 | else:
205 | return HttpResponse(json.dumps([]),content_type="application/json")
206 |
207 | else:
208 | return HttpResponse("Error")
209 | next_rect = get_rect(nextID)
210 | next_rect_json = json.dumps(next_rect)
211 | return HttpResponse(next_rect_json,content_type="application/json")
212 |
213 | except KeyError:
214 | return HttpResponse("Error")
215 | return HttpResponse("Error")
216 |
217 | def save(request):
218 | if request.is_ajax():
219 | try:
220 | data = json.loads(request.POST['data'])
221 | frameID = request.POST['ID']
222 | wid = request.POST['workerID']
223 | annotations = []
224 | cols = ["rectID","personID","modified","a1","b1","c1","d1","a2","b2","c2","d2","a3","b3","c3","d3","a4","b4","c4","d4","a5","b5","c5","d5","a6","b6","c6","d6","a7","b7","c7","d7"]
225 | annotations.append(cols)
226 | for r in data:
227 | row = data[r]
228 | row.insert(0,int(r))
229 | annotations.append(row)
230 | with open("gtm_hit/labels/"+ wid + "_" + frameID + '.json', 'w') as outFile:
231 | json.dump(annotations, outFile, sort_keys=True, indent=4, separators=(',', ': '))
232 | with open("gtm_hit/static/gtm_hit/day_2/annotation_final/labels/"+ wid + "_" + frameID + '.json', 'w') as outFile:
233 | json.dump(annotations, outFile, sort_keys=True, indent=4, separators=(',', ': '))
234 | return HttpResponse("Saved")
235 | except KeyError:
236 | return HttpResponse("Error")
237 | else:
238 | return("Error")
239 |
240 | def load(request):
241 | if request.is_ajax():
242 | try:
243 | frameID = request.POST['ID']
244 | wid = request.POST['workerID']
245 | rect_json = read_save(frameID,wid)
246 | return HttpResponse(rect_json,content_type="application/json")
247 | except (FileNotFoundError, KeyError):
248 | return HttpResponse("Error")
249 | return HttpResponse("Error")
250 |
251 | def load_previous(request):
252 | if request.is_ajax():
253 | try:
254 |
255 | frameID = request.POST['ID']
256 | wid = request.POST['workerID']
257 | current_frame = int(frameID)
258 | closest = float('inf')
259 | diff = float('inf')
260 |
261 | for f in os.listdir("gtm_hit/labels/"):
262 | if f.endswith(".json"):
263 | nb_frame = int((f.split('.')[0]).split('_')[1])
264 | if nb_frame < current_frame:
265 | if current_frame - nb_frame < diff:
266 | diff = current_frame - nb_frame
267 | closest = nb_frame
268 | if closest != float('inf'):
269 | frame = "0" * (8 - len(str(closest))) + str(closest)
270 | rect_json = read_save(frame,wid)
271 | return HttpResponse(rect_json,content_type="application/json")
272 | except (FileNotFoundError, KeyError):
273 | return HttpResponse("Error")
274 | return HttpResponse("Error")
275 |
276 | def read_save(frameID,workerID):
277 | with open("gtm_hit/labels/"+ workerID + "_" + frameID + '.json','r') as loadFile:
278 | annotations = json.load(loadFile)
279 | rects = []
280 | for i in annotations[1:]:
281 | r = get_rect(i[0])
282 | for j in range(settings.NB_CAMS):
283 | r[j]['x1'] = i[j*4+3]
284 | r[j]['y1'] = i[j*4+4]
285 | r[j]['x2'] = i[j*4+5]
286 | r[j]['y2'] = i[j*4+6]
287 | r.append(i[1])
288 | r.append(i[2])
289 | rects.append(r)
290 | return json.dumps(rects)
291 |
292 | def changeframe(request):
293 | context = RequestContext(request)
294 | if request.is_ajax():
295 | frame = 0
296 | try:
297 | wID = request.POST['workerID']
298 | order = request.POST['order']
299 | frame_number = request.POST['frameID']
300 | increment = request.POST['incr']
301 |
302 | worker = Worker.objects.get(pk = wID)
303 | worker.increaseFrame(1)
304 | worker.save()
305 | timelist = worker.getTimeList()
306 | timelist.append(timezone.now().isoformat())
307 | worker.setTimeList(timelist)
308 | #validation_code = generate_code()
309 | #return render(request, 'gtm_hit/finish.html',{'workerID' : wID, 'validation_code': validation_code},context)
310 | if order == "next":
311 | frame = int(frame_number) + int(increment)
312 | elif order == "prev" and (int(frame_number) - int(increment)) >= 0:
313 | frame = int(frame_number) - int(increment)
314 | else:
315 | return HttpResponse("Requested frame not existing")
316 | frame = "0" * (8 - len(str(frame))) + str(frame)
317 | response = {}
318 | response['frame'] = frame
319 | response['nblabeled'] = worker.frame_labeled
320 | worker.frameNB = frame
321 | worker.save()
322 | return HttpResponse(json.dumps(response))
323 | except KeyError:
324 | return HttpResponse("Error")
325 | else:
326 | return HttpResponse("Error")
327 |
328 | def get_rect(closest):
329 | rects = []
330 | for i in range(settings.NB_CAMS):
331 | rdic = {}
332 | rdic['rectangleID'] = closest
333 | if closest in settings.RECT[i]:
334 | a,b,c,d,ratio = settings.RECT[i][closest]
335 | else:
336 | a,b,c,d,ratio = 0,0,0,0,0
337 | rdic['x1'] = a
338 | rdic['y1'] = b
339 | rdic['x2'] = c
340 | rdic['y2'] = d
341 | rdic['cameraID'] = i
342 | rdic['ratio'] = ratio
343 | rdic['xMid'] = (a + c) // 2
344 | rects.append(rdic)
345 | return rects
346 |
347 | def registerWorker(workerID):
348 | w = Worker()
349 | w.workerID = workerID
350 | w.frameNB = settings.STARTFRAME % settings.NBFRAMES
351 | settings.STARTFRAME = settings.STARTFRAME + 50
352 | w.save()
353 | return w
354 |
355 | def updateWorker(workerID, state):
356 | w = Worker.objects.get(pk = workerID)
357 |
358 | def generate_code(worker):
359 | try:
360 | code = ValidationCode.objects.get(worker_id = worker)
361 | except ValidationCode.DoesNotExist:
362 | random_code = int(16777215 * rand.random())
363 | random_code = "{0:0>8}".format(random_code)
364 | while(random_code in settings.VALIDATIONCODES):
365 | random_code = int(16777215 * rand.random())
366 | random_code = "{0:0>8}".format(random_code)
367 | settings.VALIDATIONCODES.append(random_code)
368 | code = ValidationCode()
369 | code.validationCode = random_code
370 | code.worker = worker
371 | code.save()
372 | return code.validationCode
373 |
374 | def tuto(request,workerID):
375 | context = RequestContext(request)
376 | try:
377 | w = Worker.objects.get(pk = workerID)
378 | if w.state != 3:
379 | return redirect("/gtm_hit/"+workerID)
380 | return render(request, 'gtm_hit/tuto.html',{'workerID' : workerID},context)
381 |
382 | except Worker.DoesNotExist:
383 | return redirect("/gtm_hit/"+workerID)
384 |
385 | def processTuto(request, workerID):
386 | context = RequestContext(request)
387 | try:
388 | w = Worker.objects.get(pk = workerID)
389 | if w.state == 3:
390 | w.state = 1
391 | timelist = [timezone.now().isoformat()]
392 | w.setTimeList(timelist)
393 | w.save()
394 | except Worker.DoesNotExist:
395 | return redirect("/gtm_hit/"+workerID)
396 | return redirect("/gtm_hit/"+workerID)
397 |
398 | def processFinish(request):
399 | context = RequestContext(request)
400 | if request.is_ajax():
401 | try:
402 | wID = request.POST['workerID']
403 |
404 | w = Worker.objects.get(pk = wID)
405 | startframe = w.frameNB - w.frame_labeled
406 | #delete_and_load(startframe)
407 | return HttpResponse("ok")
408 | except KeyError:
409 | return HttpResponse("Error")
410 | else:
411 | return HttpResponse("Error")
412 |
413 |
414 |
415 | def delete_and_load(startframe):
416 | toload = settings.LASTLOADED + 10
417 | #1. remove frames
418 | sframe = startframe
419 | #2. copy next frames
420 | for i in range(10):
421 | rm_frame = "0" * (8 - len(str(sframe))) + str(sframe)
422 | cp_frame = "0" * (8 - len(str(toload))) + str(toload)
423 | sframe = sframe + 1
424 | toload = toload + 1
425 | for j in range(settings.NB_CAMS):
426 | command = os.system("rm gtm_hit/static/gtm_hit/frames/"+ settings.CAMS[j] + "/" + rm_frame + ".png")
427 | command = os.system("cp gtm_hit/static/gtm_hit/day_2/annotation_final/"+ settings.CAMS[j] + "/begin/" + cp_frame + ".png gtm_hit/static/gtm_hit/frames/"+ settings.CAMS[j] + "/")
428 |
429 | settings.LASTLOADED = settings.LASTLOADED + 10
430 |
--------------------------------------------------------------------------------
/gtmarker/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtmarker/.DS_Store
--------------------------------------------------------------------------------
/gtmarker/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtmarker/__init__.py
--------------------------------------------------------------------------------
/gtmarker/dump.rdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/gtmarker/dump.rdb
--------------------------------------------------------------------------------
/gtmarker/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for gtmarker project.
3 |
4 | Generated by 'django-admin startproject' using Django 1.10.2.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.10/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/1.10/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '%z1g%^3%nf-k3sf$i^qra_d*0m4745c57f&(su(2=&nuwt#=z1'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = False
27 |
28 | #ALLOWED_HOSTS = ['127.0.0.1']
29 | ALLOWED_HOSTS = ['pedestriantag.epfl.ch']
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'marker.apps.MarkerConfig',
35 | 'gtm_hit.apps.Gtm_hitConfig',
36 | 'home',
37 | 'django.contrib.admin',
38 | 'django.contrib.auth',
39 | 'django.contrib.contenttypes',
40 | 'django.contrib.sessions',
41 | 'django.contrib.messages',
42 | 'django.contrib.staticfiles',
43 | 'bootstrapform',
44 | ]
45 |
46 | MIDDLEWARE_CLASSES = [
47 | 'django.middleware.security.SecurityMiddleware',
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'django.middleware.common.CommonMiddleware',
50 | 'django.middleware.csrf.CsrfViewMiddleware',
51 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 |
55 | 'marker.middleware.RequireLoginMiddleware',
56 | ]
57 | LOGIN_REQUIRED_URLS = (
58 | r'/marker/(.*)$',
59 | )
60 | LOGIN_REQUIRED_URLS_EXCEPTIONS = (
61 | r'/marker/login(.*)$',
62 | r'/marker/logout(.*)$',
63 | )
64 |
65 | LOGIN_URL = '/login/'
66 |
67 | ROOT_URLCONF = 'gtmarker.urls'
68 |
69 | TEMPLATES = [
70 | {
71 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
72 | 'DIRS': [],
73 | 'APP_DIRS': True,
74 | 'OPTIONS': {
75 | 'context_processors': [
76 | 'django.template.context_processors.debug',
77 | 'django.template.context_processors.request',
78 | 'django.contrib.auth.context_processors.auth',
79 | 'django.contrib.messages.context_processors.messages',
80 | ],
81 | },
82 | },
83 | ]
84 |
85 | WSGI_APPLICATION = 'gtmarker.wsgi.application'
86 |
87 |
88 | # Database
89 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
90 |
91 | # DATABASES = {
92 | # 'default': {
93 | # 'ENGINE': 'django.db.backends.sqlite3',
94 | # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
95 | # }
96 | # }
97 | #
98 | # DATABASES = {
99 | # 'default': {
100 | # 'ENGINE': 'django.db.backends.postgresql_psycopg2',
101 | # 'NAME': 'gtmarker',
102 | # 'USER': 'admin',
103 | # 'PASSWORD': '',
104 | # 'HOST': 'localhost',
105 | # 'PORT': '',
106 | # }
107 | # }
108 |
109 | DATABASES = {
110 | 'default': {
111 | 'ENGINE': 'django.db.backends.postgresql_psycopg2',
112 | 'NAME': 'pedestriantag',
113 | 'USER': 'pedestriantag',
114 | 'PASSWORD': 'lAzyLift96',
115 | 'HOST': 'localhost',
116 | 'PORT': '',
117 | }
118 | }
119 |
120 | # Password validation
121 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
122 |
123 | AUTH_PASSWORD_VALIDATORS = [
124 | {
125 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
126 | },
127 | {
128 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
129 | },
130 | {
131 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
132 | },
133 | {
134 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
135 | },
136 | ]
137 |
138 |
139 | # Internationalization
140 | # https://docs.djangoproject.com/en/1.10/topics/i18n/
141 |
142 | LANGUAGE_CODE = 'en-us'
143 |
144 | TIME_ZONE = 'UTC'
145 |
146 | USE_I18N = True
147 |
148 | USE_L10N = True
149 |
150 | USE_TZ = True
151 |
152 |
153 | # Static files (CSS, JavaScript, Images)
154 | # https://docs.djangoproject.com/en/1.10/howto/static-files/
155 |
156 | STATIC_URL = '/static/'
157 |
158 | SAVES = '/labels/'
159 |
160 | # Constants
161 | #
162 | # f_rect = open('./marker/static/marker/cst.txt', 'r')
163 | # lines = f_rect.readlines()
164 | # f_rect.close()
165 | # NB_WIDTH = int(lines[2].split()[1])
166 | # NB_HEIGHT = int(lines[3].split()[1])
167 | # NB_RECT = NB_WIDTH * NB_HEIGHT
168 | # MAN_RAY = float(lines[4].split()[1])
169 | # MAN_HEIGHT = float(lines[5].split()[1])
170 | # REDUCTION = float(lines[6].split()[1])
171 | # NB_CAMS = int(lines[9].split()[1])
172 |
173 | DELTA_SEARCH = 5
174 |
175 | #TEMPLATES[0]['OPTIONS']['context_processors'].append("marker.context_processors.rectangles_processor")
176 |
177 | try:
178 | rectangles_file = './marker/static/marker/rectangles.pom'#480x1440.pom'
179 | f_rect = open(rectangles_file, 'r')
180 | lines = f_rect.readlines()
181 | f_rect.close()
182 | if lines[0].split()[0] != "WIDTH":
183 | messagebox.showerror("Error","Incorrect file header")
184 | else:
185 | NB_WIDTH = int(lines[2].split()[1])
186 | NB_HEIGHT = int(lines[3].split()[1])
187 | NB_RECT = NB_WIDTH * NB_HEIGHT
188 | MAN_RAY = float(lines[4].split()[1])
189 | MAN_HEIGHT = float(lines[5].split()[1])
190 | REDUCTION = float(lines[6].split()[1])
191 | NB_CAMS = int(lines[9].split()[1])
192 | incr = 0
193 | test = []
194 | FIND_RECT = [[{} for _ in range(2913)] for _ in range(NB_CAMS)]
195 | RECT = [{} for _ in range(NB_CAMS)]
196 | for line in lines[10:]:
197 | l = line.split()
198 | cam = int(l[1])
199 | id_rect = int(l[2])
200 | if l[3] != "notvisible":
201 | a, b, c, d = l[3:]
202 | a = int(a)
203 | b = int(b)
204 | c = int(c)
205 | d = int(d)
206 | ratio = 180/(d-b)
207 | if d < 5000:
208 | if abs(c - a) < abs(d - b):
209 | RECT[cam][id_rect] = (a, b, c, d,ratio)
210 | FIND_RECT[cam][d][(a + c) // 2] = id_rect
211 | except FileNotFoundError:
212 | print("Error: Rectangle file not found")
213 |
214 | VALIDATIONCODES = []
215 | STARTFRAME = 550
216 | NBFRAMES = 18000
217 | UNLABELED = list(range(0,NBFRAMES,10))
218 | LASTLOADED = 990
219 |
220 | SERVER_PATH = "/Volumes/cvlabdata1/cvlab/datasets_people_tracking/ETH/day_2/"
221 | CAMS = []
222 | for i in range(4):
223 | CAMS.append("cvlab_camera" + str(i+1))
224 | for i in range(3):
225 | CAMS.append("idiap_camera" + str(i+1))
226 |
--------------------------------------------------------------------------------
/gtmarker/urls.py:
--------------------------------------------------------------------------------
1 | """gtmarker URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.conf.urls import url, include
14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15 | """
16 | from django.conf.urls import include, url, handler404, handler403, handler400,handler500
17 | from django.contrib import admin
18 | from home import views as v
19 |
20 | urlpatterns = [
21 | url(r'^$', v.index),
22 | url(r'^marker/', include('marker.urls')),
23 | url(r'^admin/', admin.site.urls),
24 | url(r'^gtm_hit/', include('gtm_hit.urls')),
25 | url(r'^login/$', v.login),
26 | ]
27 |
28 | handler400 = 'home.views.bad_request'
29 | handler403 = 'home.views.permission_denied'
30 | handler404 = 'home.views.page_not_found'
31 | handler500 = 'home.views.server_error'
32 |
--------------------------------------------------------------------------------
/gtmarker/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for gtmarker project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gtmarker.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/home/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/home/__init__.py
--------------------------------------------------------------------------------
/home/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/home/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class HomeConfig(AppConfig):
5 | name = 'home'
6 |
--------------------------------------------------------------------------------
/home/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/home/migrations/__init__.py
--------------------------------------------------------------------------------
/home/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/home/static/epfl_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/home/static/epfl_logo.png
--------------------------------------------------------------------------------
/home/static/fns_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/home/static/fns_logo.png
--------------------------------------------------------------------------------
/home/static/idiap_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/home/static/idiap_logo.png
--------------------------------------------------------------------------------
/home/templates/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/home/templates/.DS_Store
--------------------------------------------------------------------------------
/home/templates/home/error.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 | {% include "includes_home/navbar.html" %}
17 |
31 | {% include "includes_hit/footer.html" %}
32 |
33 | {% include "includes_hit/tuto.html" %}
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/home/templates/home/index.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 | {% include "includes_home/navbar.html" %}
17 |
41 | {% include "includes_hit/footer.html" %}
42 |
43 | {% include "includes_hit/tuto.html" %}
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/home/templates/home/login.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 | {% include "includes/navbar.html" %}
18 | {% csrf_token %}
19 |
44 | {% include "includes/footer.html" %}
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/home/templates/includes_home/footer.html:
--------------------------------------------------------------------------------
1 |
8 |
12 |
--------------------------------------------------------------------------------
/home/templates/includes_home/navbar.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | {% if user.is_authenticated %}
7 | Logout
8 | {% endif %}
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/home/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/home/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 | from django.template import RequestContext
3 | from django.contrib.auth.decorators import login_required
4 |
5 | def index(request):
6 | context = RequestContext(request)
7 | return render(request, 'home/index.html',{},context)
8 |
9 | def page_not_found(request):
10 | context = RequestContext(request)
11 | return render(request, 'home/error.html',{'error': 'Page Not Found'},context,status=404)
12 |
13 | def bad_request(request):
14 | return render(request, 'home/error.html',{'error': 'Bad Request'},status=400)
15 |
16 | def permission_denied(request):
17 | context = RequestContext(request)
18 | return render(request, 'home/error.html',{'error': 'Permission Denied'},context,status=403)
19 |
20 | def server_error(request):
21 | context = RequestContext(request)
22 | return render(request, 'home/error.html',{'error': 'Server Error'},context,status=500)
23 |
24 | def login(request):
25 | context = RequestContext(request)
26 | error = False
27 | active = True
28 | if request.method == 'POST':
29 | username = request.POST['username']
30 | password = request.POST['password']
31 |
32 | user = authenticate(username=username, password=password)
33 |
34 | if user:
35 | if user.is_active:
36 | login(request, user)
37 | return HttpResponseRedirect('/')
38 | else:
39 | active = False
40 | else:
41 | error = True
42 |
43 | return render(request,'home/login.html', {'error': error, 'active':active}, context)
44 |
45 | @login_required
46 | def logout(request):
47 | logout(request)
48 | return HttpResponseRedirect('/')
49 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gtmarker.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError:
10 | # The above import may fail for some other reason. Ensure that the
11 | # issue is really that Django is missing to avoid masking other
12 | # exceptions on Python 2.
13 | try:
14 | import django
15 | except ImportError:
16 | raise ImportError(
17 | "Couldn't import Django. Are you sure it's installed and "
18 | "available on your PYTHONPATH environment variable? Did you "
19 | "forget to activate a virtual environment?"
20 | )
21 | raise
22 | execute_from_command_line(sys.argv)
23 |
--------------------------------------------------------------------------------
/marker/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/.DS_Store
--------------------------------------------------------------------------------
/marker/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/__init__.py
--------------------------------------------------------------------------------
/marker/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import *
3 |
--------------------------------------------------------------------------------
/marker/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class MarkerConfig(AppConfig):
5 | name = 'marker'
6 |
--------------------------------------------------------------------------------
/marker/context_processors.py:
--------------------------------------------------------------------------------
1 | from .models import Annotation,Rectangle
2 | from django.core import serializers
3 | import json
4 |
5 | def rectangles_processor(request):
6 | rectangles = Rectangle.objects.filter(x1__gt = 0, y1__gt = 0, x2__gt = 0)
7 | return {'rectangles': rectangles}
8 |
--------------------------------------------------------------------------------
/marker/management/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/management/.DS_Store
--------------------------------------------------------------------------------
/marker/management/commands/add_data.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand, CommandError
2 | from marker.models import Rectangle
3 | import pandas as pd
4 | import json
5 | import os
6 | class Command(BaseCommand):
7 | help = 'Populate database'
8 |
9 | def handle(self, *args, **options):
10 | rect = open('../data/rectangles480x1280.pom', 'r')
11 | lines = rect.readlines()
12 | rect.close()
13 | total = len(lines)
14 | i = 0
15 | j = 1
16 | for line in lines:
17 | box = Rectangle()
18 | l = line.split()
19 | box.cameraID = int(l[1])
20 | box.rectangleID = int(l[2])
21 | if l[3] != "notvisible":
22 | a, b, c, d = l[3:]
23 | else:
24 | a = b = c = d = 0
25 | box.x1 = int(a)
26 | box.y1 = int(b)
27 | box.x2 = int(c)
28 | box.y2 = int(d)
29 | box.xMid = (int(a)+int(c))//2
30 | box.save()
31 | i = i + 1
32 | if i % round(total/10) == 0:
33 | print(j*10,'%')
34 | j = j + 1
35 | print("Done")
36 |
--------------------------------------------------------------------------------
/marker/management/commands/set_data.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand, CommandError
2 | from marker.models import Rectangle
3 |
4 | class Command(BaseCommand):
5 | help = 'Populate database'
6 |
7 | def handle(self, *args, **options):
8 | candidates = Rectangle.objects.all()
9 | total = len(candidates)
10 | i = 0
11 | j = 1
12 | for c in candidates:
13 | c.xMid = (c.x1 + c.x2) // 2
14 | c.save()
15 | i = i + 1
16 | if i % round(total/10) == 0:
17 | print(j*10,'%')
18 | j = j + 1
19 | print("Done")
20 |
--------------------------------------------------------------------------------
/marker/middleware.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from django.conf import settings
4 | from django.contrib.auth.decorators import login_required
5 |
6 | class RequireLoginMiddleware(object):
7 | """
8 | Middleware component that wraps the login_required decorator around
9 | matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and
10 | define LOGIN_REQUIRED_URLS and LOGIN_REQUIRED_URLS_EXCEPTIONS in your
11 | settings.py. For example:
12 | ------
13 | LOGIN_REQUIRED_URLS = (
14 | r'/topsecret/(.*)$',
15 | )
16 | LOGIN_REQUIRED_URLS_EXCEPTIONS = (
17 | r'/topsecret/login(.*)$',
18 | r'/topsecret/logout(.*)$',
19 | )
20 | ------
21 | LOGIN_REQUIRED_URLS is where you define URL patterns; each pattern must
22 | be a valid regex.
23 |
24 | LOGIN_REQUIRED_URLS_EXCEPTIONS is, conversely, where you explicitly
25 | define any exceptions (like login and logout URLs).
26 | """
27 | def __init__(self):
28 | self.required = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS)
29 | self.exceptions = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)
30 |
31 | def process_view(self, request, view_func, view_args, view_kwargs):
32 | # No need to process URLs if user already logged in
33 | if request.user.is_authenticated():
34 | return None
35 |
36 | # An exception match should immediately return None
37 | for url in self.exceptions:
38 | if url.match(request.path):
39 | return None
40 |
41 | # Requests matching a restricted URL pattern are returned
42 | # wrapped with the login_required decorator
43 | for url in self.required:
44 | if url.match(request.path):
45 | return login_required(view_func)(request, *view_args, **view_kwargs)
46 |
47 | # Explicitly return None for all non-matching requests
48 | return None
49 |
--------------------------------------------------------------------------------
/marker/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-13 14:50
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='Annotation',
18 | fields=[
19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20 | ('pom_file', models.CharField(max_length=30)),
21 | ('frame_number', models.PositiveIntegerField(default=0)),
22 | ('rectangleID', models.PositiveIntegerField(default=0)),
23 | ('personID', models.PositiveSmallIntegerField(default=0)),
24 | ('modified_flag', models.BooleanField(default=False)),
25 | ('coordinates', models.CommaSeparatedIntegerField(max_length=180)),
26 | ],
27 | ),
28 | ]
29 |
--------------------------------------------------------------------------------
/marker/migrations/0002_auto_20161013_1455.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-13 14:55
3 | from __future__ import unicode_literals
4 |
5 | import django.core.validators
6 | from django.db import migrations, models
7 | import re
8 |
9 |
10 | class Migration(migrations.Migration):
11 |
12 | dependencies = [
13 | ('marker', '0001_initial'),
14 | ]
15 |
16 | operations = [
17 | migrations.AlterField(
18 | model_name='annotation',
19 | name='coordinates',
20 | field=models.CharField(max_length=180, validators=[django.core.validators.RegexValidator(re.compile('^\\d+(?:\\,\\d+)*\\Z', 32), code='invalid', message='Enter only digits separated by commas.')]),
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/marker/migrations/0003_rectanges.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-18 13:04
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0002_auto_20161013_1455'),
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Rectanges',
17 | fields=[
18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('cameraID', models.PositiveSmallIntegerField(default=0)),
20 | ('rectangleID', models.PositiveIntegerField(default=0)),
21 | ('x1', models.PositiveSmallIntegerField(default=0)),
22 | ('y1', models.PositiveSmallIntegerField(default=0)),
23 | ('x2', models.PositiveSmallIntegerField(default=0)),
24 | ('y2', models.PositiveSmallIntegerField(default=0)),
25 | ],
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/marker/migrations/0004_auto_20161018_1310.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-18 13:10
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0003_rectanges'),
12 | ]
13 |
14 | operations = [
15 | migrations.RenameModel(
16 | old_name='Rectanges',
17 | new_name='Rectangles',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/marker/migrations/0005_auto_20161018_1341.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-18 13:41
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0004_auto_20161018_1310'),
12 | ]
13 |
14 | operations = [
15 | migrations.RenameModel(
16 | old_name='Rectangles',
17 | new_name='Rectangle',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/marker/migrations/0006_rectangle_xmid.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-19 12:53
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0005_auto_20161018_1341'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='rectangle',
17 | name='xMid',
18 | field=models.PositiveSmallIntegerField(default=0),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/marker/migrations/0007_remove_annotation_pom_file.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-21 13:21
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0006_rectangle_xmid'),
12 | ]
13 |
14 | operations = [
15 | migrations.RemoveField(
16 | model_name='annotation',
17 | name='pom_file',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/marker/migrations/0008_delete_rectangle.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-10-26 10:02
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0007_remove_annotation_pom_file'),
12 | ]
13 |
14 | operations = [
15 | migrations.DeleteModel(
16 | name='Rectangle',
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/marker/migrations/0009_worker.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-04 14:23
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0008_delete_rectangle'),
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='Worker',
17 | fields=[
18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19 | ('workerID', models.PositiveIntegerField(default=0)),
20 | ('frameNB', models.PositiveSmallIntegerField(default=0)),
21 | ('validationoCode', models.PositiveIntegerField(default=0)),
22 | ('finished', models.BooleanField(default=False)),
23 | ('state', models.IntegerField(default=-1)),
24 | ],
25 | ),
26 | ]
27 |
--------------------------------------------------------------------------------
/marker/migrations/0010_auto_20161110_1512.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-11-10 15:12
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('marker', '0009_worker'),
12 | ]
13 |
14 | operations = [
15 | migrations.DeleteModel(
16 | name='Annotation',
17 | ),
18 | migrations.DeleteModel(
19 | name='Worker',
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/marker/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/migrations/__init__.py
--------------------------------------------------------------------------------
/marker/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.core.validators import validate_comma_separated_integer_list
3 |
4 | # class Annotation(models.Model):
5 | #
6 | # frame_number = models.PositiveIntegerField(default=0)
7 | # rectangleID = models.PositiveIntegerField(default=0)
8 | # personID = models.PositiveSmallIntegerField(default=0)
9 | # modified_flag = models.BooleanField(default=False)
10 | # coordinates = models.CharField(max_length=180,validators=[validate_comma_separated_integer_list])
11 | #
12 | # # class Rectangle(models.Model):
13 | # # cameraID = models.PositiveSmallIntegerField(default=0)
14 | # # rectangleID = models.PositiveIntegerField(default=0)
15 | # # x1 = models.PositiveSmallIntegerField(default=0)
16 | # # y1 = models.PositiveSmallIntegerField(default=0)
17 | # # x2 = models.PositiveSmallIntegerField(default=0)
18 | # # y2 = models.PositiveSmallIntegerField(default=0)
19 | # # xMid = models.PositiveSmallIntegerField(default=0)
20 | #
21 | #
22 | # class Worker(models.Model):
23 | #
24 | # workerID = models.PositiveIntegerField(primary_key=True)
25 | # frameNB = models.PositiveSmallIntegerField(default=0)
26 | # #validationoCode = models.PositiveIntegerField(default=0)
27 | # finished = models.BooleanField(default=False)
28 | # state = models.IntegerField(default=-1)
29 | #
30 | # def increaseFrame(self,val):
31 | # frameNB = frameNB + val
32 | #
33 | # def decreaseFrame(self,val):
34 | # frameNB = frameNB - val
35 | #
36 | # class ValidationCode(models.Model):
37 | # validationCode = models.PositiveIntegerField(primary_key=True)
38 | # workerID = models.ForeignKey('Worker', on_delete=models.CASCADE)
39 |
--------------------------------------------------------------------------------
/marker/static/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/.DS_Store
--------------------------------------------------------------------------------
/marker/static/marker/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/.DS_Store
--------------------------------------------------------------------------------
/marker/static/marker/arrows.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/arrows.gif
--------------------------------------------------------------------------------
/marker/static/marker/arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/arrows.png
--------------------------------------------------------------------------------
/marker/static/marker/cst.txt:
--------------------------------------------------------------------------------
1 | WIDTH 12
2 | HEIGHT 32
3 | NB_WIDTH 480
4 | NB_HEIGHT 1280
5 | MAN_RAY 0.16
6 | MAN_HEIGHT 1.8
7 | REDUCTION 1
8 | ORIGINE_X -3.0
9 | ORIGINE_Y -6.0
10 | NB_CAMERA 7
--------------------------------------------------------------------------------
/marker/static/marker/day_2:
--------------------------------------------------------------------------------
1 | /cvlabdata1/cvlab/datasets_people_tracking/ETH/day_2/
--------------------------------------------------------------------------------
/marker/static/marker/find_rect.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/find_rect.pickle
--------------------------------------------------------------------------------
/marker/static/marker/frame.css:
--------------------------------------------------------------------------------
1 | .top5 { margin-top:5px; }
2 | .top7 { margin-top:7px; }
3 | .top10 { margin-top:10px; }
4 | .top15 { margin-top:15px; }
5 | .top17 { margin-top:17px; }
6 | .top30 { margin-top:30px; }
7 |
8 | .loadersmall {
9 | border: 5px solid #f3f3f3;
10 | -webkit-animation: spin 1s linear infinite;
11 | animation: spin 1s linear infinite;
12 | border-top: 5px solid #555;
13 | border-radius: 50%;
14 | width: 30px;
15 | height: 30px;
16 | }
17 |
18 | @-webkit-keyframes spin {
19 | 0% { -webkit-transform: rotate(0deg); }
20 | 100% { -webkit-transform: rotate(360deg); }
21 | }
22 |
23 | @keyframes spin {
24 | 0% { transform: rotate(0deg); }
25 | 100% { transform: rotate(360deg); }
26 | }
27 |
28 | .big {
29 | line-height: 150%;
30 | }
31 |
32 | body {
33 | font-family: "Lato","Helvetica Neue",Arial,sans-serif;
34 | font-weight: 500;
35 | }
36 |
--------------------------------------------------------------------------------
/marker/static/marker/images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/.DS_Store
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows0_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows0_3D.png
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows1_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows1_3D.png
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows2_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows2_3D.png
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows3_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows3_3D.png
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows4_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows4_3D.png
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows5_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows5_3D.png
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows6_3D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows6_3D.png
--------------------------------------------------------------------------------
/marker/static/marker/images/arrows_plane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/arrows_plane.png
--------------------------------------------------------------------------------
/marker/static/marker/images/bad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/bad.png
--------------------------------------------------------------------------------
/marker/static/marker/images/epfl_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/epfl_logo.png
--------------------------------------------------------------------------------
/marker/static/marker/images/ex2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/ex2.png
--------------------------------------------------------------------------------
/marker/static/marker/images/fns_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/fns_logo.png
--------------------------------------------------------------------------------
/marker/static/marker/images/good.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/good.png
--------------------------------------------------------------------------------
/marker/static/marker/images/idiap_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/images/idiap_logo.png
--------------------------------------------------------------------------------
/marker/static/marker/index.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Start Bootstrap - Landing Page (http://startbootstrap.com/)
3 | * Copyright 2013-2016 Start Bootstrap
4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
5 | */
6 |
7 | body,
8 | html {
9 | width: 100%;
10 | height: 100%;
11 | }
12 |
13 | body {
14 | font-family: "Lato","Helvetica Neue",Arial,sans-serif;
15 | font-weight: 500;
16 | }
17 | h1,
18 | h2,
19 | h3,
20 | h4,
21 | h5,
22 | h6 {
23 | font-family: "Lato","Helvetica Neue",Arial,sans-serif;
24 | font-weight: 700;
25 | }
26 |
27 |
28 | .intro-header {
29 | text-align: center;
30 | }
31 |
32 | .intro-message {
33 | position: relative;
34 | padding-top: 10%;
35 | padding-bottom: 10%;
36 | }
37 |
38 | .intro-message > h1 {
39 | margin: 0;
40 | font-size: 5em;
41 | }
42 |
43 | .intro-divider {
44 | width: 400px;
45 | border-top: 1px solid #f8f8f8;
46 | border-bottom: 1px solid rgba(0,0,0,0.2);
47 | }
48 |
49 | .button-name {
50 | text-transform: uppercase;
51 | font-size: 14px;
52 | font-weight: 400;
53 | letter-spacing: 2px;
54 | }
55 |
56 | .footer {
57 | position: relative;
58 | bottom: 0;
59 | width: 100%;
60 | }
61 |
62 | .top5 { margin-top:5px; }
63 | .top7 { margin-top:7px; }
64 | .top10 { margin-top:10px; }
65 | .top15 { margin-top:15px; }
66 | .top17 { margin-top:17px; }
67 | .top30 { margin-top:30px; }
68 |
69 | .big {
70 | line-height: 150%;
71 | }
72 |
73 | #my-row {
74 | display: table;
75 | }
76 |
77 | #my-row .panel {
78 | float: none;
79 | display: table-cell;
80 | vertical-align: top;
81 | }
82 |
--------------------------------------------------------------------------------
/marker/static/marker/jquery.hotkeys.js:
--------------------------------------------------------------------------------
1 | /*jslint browser: true*/
2 | /*jslint jquery: true*/
3 |
4 | /*
5 | * jQuery Hotkeys Plugin
6 | * Copyright 2010, John Resig
7 | * Dual licensed under the MIT or GPL Version 2 licenses.
8 | *
9 | * Based upon the plugin by Tzury Bar Yochay:
10 | * https://github.com/tzuryby/jquery.hotkeys
11 | *
12 | * Original idea by:
13 | * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
14 | */
15 |
16 | /*
17 | * One small change is: now keys are passed by object { keys: '...' }
18 | * Might be useful, when you want to pass some other data to your handler
19 | */
20 |
21 | (function(jQuery) {
22 |
23 | jQuery.hotkeys = {
24 | version: "0.2.0",
25 |
26 | specialKeys: {
27 | 8: "backspace",
28 | 9: "tab",
29 | 10: "return",
30 | 13: "return",
31 | 16: "shift",
32 | 17: "ctrl",
33 | 18: "alt",
34 | 19: "pause",
35 | 20: "capslock",
36 | 27: "esc",
37 | 32: "space",
38 | 33: "pageup",
39 | 34: "pagedown",
40 | 35: "end",
41 | 36: "home",
42 | 37: "left",
43 | 38: "up",
44 | 39: "right",
45 | 40: "down",
46 | 45: "insert",
47 | 46: "del",
48 | 59: ";",
49 | 61: "=",
50 | 96: "0",
51 | 97: "1",
52 | 98: "2",
53 | 99: "3",
54 | 100: "4",
55 | 101: "5",
56 | 102: "6",
57 | 103: "7",
58 | 104: "8",
59 | 105: "9",
60 | 106: "*",
61 | 107: "+",
62 | 109: "-",
63 | 110: ".",
64 | 111: "/",
65 | 112: "f1",
66 | 113: "f2",
67 | 114: "f3",
68 | 115: "f4",
69 | 116: "f5",
70 | 117: "f6",
71 | 118: "f7",
72 | 119: "f8",
73 | 120: "f9",
74 | 121: "f10",
75 | 122: "f11",
76 | 123: "f12",
77 | 144: "numlock",
78 | 145: "scroll",
79 | 173: "-",
80 | 186: ";",
81 | 187: "=",
82 | 188: ",",
83 | 189: "-",
84 | 190: ".",
85 | 191: "/",
86 | 192: "`",
87 | 219: "[",
88 | 220: "\\",
89 | 221: "]",
90 | 222: "'"
91 | },
92 |
93 | shiftNums: {
94 | "`": "~",
95 | "1": "!",
96 | "2": "@",
97 | "3": "#",
98 | "4": "$",
99 | "5": "%",
100 | "6": "^",
101 | "7": "&",
102 | "8": "*",
103 | "9": "(",
104 | "0": ")",
105 | "-": "_",
106 | "=": "+",
107 | ";": ": ",
108 | "'": "\"",
109 | ",": "<",
110 | ".": ">",
111 | "/": "?",
112 | "\\": "|"
113 | },
114 |
115 | // excludes: button, checkbox, file, hidden, image, password, radio, reset, search, submit, url
116 | textAcceptingInputTypes: [
117 | "text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime",
118 | "datetime-local", "search", "color", "tel"],
119 |
120 | // default input types not to bind to unless bound directly
121 | textInputTypes: /textarea|input|select/i,
122 |
123 | options: {
124 | filterInputAcceptingElements: true,
125 | filterTextInputs: true,
126 | filterContentEditable: true
127 | }
128 | };
129 |
130 | function keyHandler(handleObj) {
131 | if (typeof handleObj.data === "string") {
132 | handleObj.data = {
133 | keys: handleObj.data
134 | };
135 | }
136 |
137 | // Only care when a possible input has been specified
138 | if (!handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== "string") {
139 | return;
140 | }
141 |
142 | var origHandler = handleObj.handler,
143 | keys = handleObj.data.keys.toLowerCase().split(" ");
144 |
145 | handleObj.handler = function(event) {
146 | // Don't fire in text-accepting inputs that we didn't directly bind to
147 | if (this !== event.target &&
148 | (jQuery.hotkeys.options.filterInputAcceptingElements &&
149 | jQuery.hotkeys.textInputTypes.test(event.target.nodeName) ||
150 | (jQuery.hotkeys.options.filterContentEditable && jQuery(event.target).attr('contenteditable')) ||
151 | (jQuery.hotkeys.options.filterTextInputs &&
152 | jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1))) {
153 | return;
154 | }
155 |
156 | var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[event.which],
157 | character = String.fromCharCode(event.which).toLowerCase(),
158 | modif = "",
159 | possible = {};
160 |
161 | jQuery.each(["alt", "ctrl", "shift"], function(index, specialKey) {
162 |
163 | if (event[specialKey + 'Key'] && special !== specialKey) {
164 | modif += specialKey + '+';
165 | }
166 | });
167 |
168 | // metaKey is triggered off ctrlKey erronously
169 | if (event.metaKey && !event.ctrlKey && special !== "meta") {
170 | modif += "meta+";
171 | }
172 |
173 | if (event.metaKey && special !== "meta" && modif.indexOf("alt+ctrl+shift+") > -1) {
174 | modif = modif.replace("alt+ctrl+shift+", "hyper+");
175 | }
176 |
177 | if (special) {
178 | possible[modif + special] = true;
179 | }
180 | else {
181 | possible[modif + character] = true;
182 | possible[modif + jQuery.hotkeys.shiftNums[character]] = true;
183 |
184 | // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
185 | if (modif === "shift+") {
186 | possible[jQuery.hotkeys.shiftNums[character]] = true;
187 | }
188 | }
189 |
190 | for (var i = 0, l = keys.length; i < l; i++) {
191 | if (possible[keys[i]]) {
192 | return origHandler.apply(this, arguments);
193 | }
194 | }
195 | };
196 | }
197 |
198 | jQuery.each(["keydown", "keyup", "keypress"], function() {
199 | jQuery.event.special[this] = {
200 | add: keyHandler
201 | };
202 | });
203 |
204 | })(jQuery || this.jQuery || window.jQuery);
205 |
--------------------------------------------------------------------------------
/marker/static/marker/marker.js:
--------------------------------------------------------------------------------
1 | var rectsID = [];
2 | var boxes = {};
3 | var chosen_rect;
4 | var imgArray = [];
5 | var arrArray = [];
6 | var validation = {};
7 | var identities = {};
8 | var personID = 0;
9 | var cameras = 7;
10 | var camName = '';
11 | var loadcount = 0;
12 | var zoomOn = false;
13 | var zoomratio = [];
14 | var rotation = [50,230,150,75,265,340,80];
15 | var bounds = [[0,396,1193,180,1883,228,1750,1080],[0,344,1467,77,1920,82,-1,-1],
16 | [97,1080,73,273,864,202,1920,362],[0,444,1920,261,-1,-1,-1,-1],
17 | [0,435,1920,403,-1,-1,-1,-1],[0,243,29,203,656,191,1920,442],
18 | [0,244,1920,162,-1,-1,-1,-1]];
19 | var toggle_ground;
20 | var toggle_orientation;
21 | // hashsets --> rect per camera ? rect -> id to coordinates?
22 | // store variables here? in db ? (reupload db?)
23 | window.onload = function() {
24 | toggle_ground = true;
25 | toggle_orientation = true;
26 | camName = cams.substring(2,cams.length-2).split("', '");
27 | for (var i = 0; i < cameras; i++) {
28 | boxes[i] = {};
29 |
30 | arrArray[i] = new Image();
31 | arrArray[i].id=("arrows"+i);
32 | arrArray[i].src = '../../static/gtm_hit/images/arrows'+i+'_3D.png';
33 |
34 | imgArray[i] = new Image();
35 | imgArray[i].id=(i+1);
36 | imgArray[i].onload = function() {
37 | var c = document.getElementById("canv"+this.id);
38 | var ctx = c.getContext('2d');
39 |
40 | ctx.drawImage(this,0,0);
41 | if(toggle_orientation)
42 | drawArrows(ctx,this.id-1);
43 | c.addEventListener('click',mainClick);
44 | loadcount++;
45 | if(loadcount == 7) {
46 | $("#loader").hide();
47 | }
48 | update();
49 | }
50 |
51 | loadcount = 0;
52 | $("#loader").show();
53 | imgArray[i].src = '../../static/marker/day_2/annotation_final/'+ camName[i]+ '/begin/'+frame_str+'.png'; // change 00..0 by a frame variable
54 | //imgArray[i].src = '../../static/gtm_hit/frames/'+ camName[i]+frame_str+'.png'; // change 00..0 by a frame variable
55 | }
56 | $(document).bind('keydown', "backspace",backSpace);
57 | $(document).bind('keydown', "left",left);
58 | $(document).bind('keydown', "right",right);
59 | $(document).bind('keydown', "up",up);
60 | $(document).bind('keydown', "down",down);
61 | $(document).bind('keydown', "tab",tab);
62 | $(document).bind('keydown', "space",space);
63 | $(document).bind('keydown', "Shift+right",incrWidth);
64 | $(document).bind('keydown', "Shift+left",decrWidth);
65 | $(document).bind('keydown', "Shift+up",incrHeight);
66 | $(document).bind('keydown', "Shift+down",decrHeight);
67 | $(document).bind('keydown', "s",save);
68 | $(document).bind('keydown', "l",load);
69 | $(document).bind('keydown', "n",next);
70 | $(document).bind('keydown', "p",prev);
71 | $(document).bind( "keydown", "z",zoomControl);
72 | $(document).bind( "keydown", "t",toggleGround);
73 | $(document).bind( "keydown", "h",toggleOrientation);
74 | $(document).bind('keydown', "Shift+n",nextI);
75 | $(document).bind('keydown', "Shift+p",prevI);
76 | $(document).bind( "keydown", "e",validate);
77 | $("#pID").bind( "keydown", "return",changeID);
78 | $("#pID").val(-1);
79 | $("#pHeight").val(-1);
80 | $("#pWidth").val(-1);
81 | };
82 |
83 | function mainClick(e) {
84 | var canv = this;
85 | var offset = $(this).offset();
86 | var relativeX = (e.pageX - offset.left)-15;
87 | var relativeY = (e.pageY - offset.top);
88 | var xCorr = Math.round(relativeX*1920/(this.clientWidth-30));
89 | var yCorr = Math.round(relativeY*1080/this.clientHeight);
90 | if(relativeX >=0 && relativeX<=(this.clientWidth - 29)) {
91 | if(zoomOn)
92 | zoomOut();
93 | //post
94 | $.ajax({
95 | method: "POST",
96 | url: "click",
97 | data: {
98 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
99 | x: xCorr,
100 | y: yCorr,
101 | canv: this.id
102 | },
103 | dataType: "json",
104 | success: function(msg) {
105 | var rid = msg[0].rectangleID;
106 | var indof = rectsID.indexOf(rid);
107 | if(indof == -1) {
108 | rectsID.push(rid);
109 | chosen_rect = rectsID.length-1;
110 | while(personID in validation)
111 | personID++;
112 | identities[rid] = personID;
113 | validation[personID] = true;
114 | saveRect(msg,personID);
115 | } else {
116 | chosen_rect = indof;
117 | }
118 | update();
119 | }
120 | });
121 |
122 | }
123 | }
124 |
125 | function backSpace() {
126 | if (rectsID.length > 0){
127 | var rid = rectsID[chosen_rect];
128 | rectsID.splice(chosen_rect,1);
129 | var idPers = identities[rid];
130 | delete validation[idPers];
131 | delete identities[rid];
132 | //validation_dict.pop(idPers)
133 | //identities.pop(idRect)
134 | //for i in range(NB_PICTURES):
135 | // if idPers in person_rect[i]:
136 | // person_rect[i].pop(idPers)
137 | if (chosen_rect == rectsID.length) {
138 | chosen_rect--;
139 | }
140 | if(zoomOn) {
141 | zoomOut();
142 | }
143 | update();
144 | }
145 | return false;
146 | }
147 |
148 | function space() {
149 | if (rectsID.length <= 1)
150 | return false;
151 |
152 | chosen_rect--;
153 | if(zoomOn)
154 | zoomOut();
155 | update();
156 | return false;
157 |
158 | }
159 |
160 | function tab() {
161 | if (rectsID.length <= 1)
162 | return false;
163 |
164 | chosen_rect++;
165 | if(zoomOn)
166 | zoomOut();
167 | update();
168 | return false;
169 | }
170 |
171 | function left() {
172 | sendAJAX("move","left",rectsID[chosen_rect],moveRect);
173 | update();
174 | return false;
175 | }
176 |
177 | function right() {
178 | sendAJAX("move","right",rectsID[chosen_rect],moveRect);
179 | update();
180 | return false;
181 | }
182 |
183 | function up() {
184 | sendAJAX("move","up",rectsID[chosen_rect],moveRect);
185 | update();
186 | return false;
187 | }
188 |
189 | function down() {
190 | sendAJAX("move","down",rectsID[chosen_rect],moveRect);
191 | update()
192 | return false;
193 | }
194 |
195 | function incrWidth() {
196 | var ind = getIndx();
197 | var pid = identities[rectsID[chosen_rect]];
198 | var rect = boxes[ind][pid];
199 | rect.x1 = rect.x1-1;
200 | rect.x2 = rect.x2+1;
201 | boxes[ind][pid] = rect;
202 |
203 | var size = (rect.x2-rect.x1)*rect.ratio;
204 | updateSize(false,size,ind);
205 | return false;
206 |
207 | }
208 |
209 | function decrWidth() {
210 | var ind = getIndx();
211 | var pid = identities[rectsID[chosen_rect]];
212 | var rect = boxes[ind][pid];
213 | rect.x1 = rect.x1+1;
214 | if(rect.x2 - rect.x1 < 1) {
215 | rect.x1 = rect.x2 -1;
216 | } else {
217 | rect.x2 = rect.x2-1;
218 | }
219 | boxes[ind][pid] = rect;
220 | var size = (rect.x2-rect.x1)*rect.ratio;
221 | updateSize(false,size,ind);
222 | return false;
223 |
224 | }
225 |
226 | function incrHeight() {
227 |
228 | var ind = getIndx();
229 | var pid = identities[rectsID[chosen_rect]];
230 | var rect = boxes[ind][pid];
231 | rect.y1 = rect.y1-1;
232 | boxes[ind][pid] = rect;
233 |
234 | var size = (rect.y2-rect.y1)*rect.ratio;
235 | updateSize(true,size,ind);
236 | return false;
237 |
238 | }
239 |
240 | function decrHeight() {
241 | var ind = getIndx();
242 | var pid = identities[rectsID[chosen_rect]];
243 | var rect = boxes[ind][pid];
244 | rect.y1 = rect.y1+1;
245 | if(rect.y2 - rect.y1 < 1) {
246 | rect.y1 = rect.y2-1;
247 | }
248 | boxes[ind][pid] = rect;
249 |
250 | var size = (rect.y2-rect.y1)*rect.ratio;
251 | updateSize(true,size,ind);
252 | return false;
253 |
254 | }
255 |
256 | function getIndx() {
257 | var h = -1;
258 | var retInd = -1;
259 | var pid = identities[rectsID[chosen_rect]];
260 | for (var i = 0; i < cameras; i++) {
261 | r = boxes[i][pid];
262 | tpH = Math.abs(r.y1 - r.y2);
263 |
264 | if(tpH > h) {
265 | h = tpH;
266 | retInd = i;
267 | }
268 | }
269 | return retInd;
270 | }
271 |
272 | function updateSize(height,size,ind) {
273 | var r = rectsID[chosen_rect];
274 | var pid = identities[r];
275 | for (var i = 0; i < cameras; i++) {
276 | rect = boxes[i][pid];
277 | if(i != ind && rect.y1 != 0) {
278 | if(height) {
279 | var b = Math.round(rect.y2 - size/rect.ratio);
280 | if(rect.y2 - b < 1)
281 | b = rect.y2 - 1;
282 | rect.y1 = b;
283 | } else {
284 | var delta = size/(2*rect.ratio);
285 | var c = Math.round(rect.xMid + delta);
286 | var a = Math.round(rect.xMid - delta);
287 | if(c - a < 1)
288 | a = c - 1;
289 | rect.x1 = a;
290 | rect.x2 = c;
291 | }
292 | }
293 | boxes[i][pid] = rect;
294 | }
295 | update()
296 | }
297 |
298 | function save() {
299 | var dims = {};
300 | var k = 0;
301 | for (var i = 0; i < rectsID.length; i++) {
302 | var rid = rectsID[i];
303 | var pid = identities[rid];
304 | dims[rid] = [];
305 | dims[rid].push(pid);
306 | dims[rid].push(validation[pid]);
307 | }
308 |
309 | for (var i = 0; i < cameras; i++) {
310 | for (var j = 0; j < rectsID.length; j++) {
311 | var rid = rectsID[j];
312 | var pid = identities[rid];
313 |
314 | var field = boxes[i][pid];
315 | if(field.x2 != 0){
316 | dims[rid].push(field.x1);
317 | dims[rid].push(field.y1);
318 | dims[rid].push(field.x2);
319 | dims[rid].push(field.y2);
320 | } else {
321 | dims[rid].push(-1);
322 | dims[rid].push(-1);
323 | dims[rid].push(-1);
324 | dims[rid].push(-1);
325 | }
326 | }
327 | }
328 | $.ajax({
329 | method: "POST",
330 | url: 'save',
331 | data: {
332 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
333 | data: JSON.stringify(dims),
334 | ID: frame_str
335 | },
336 | success: function(msg) {
337 | console.log(msg);
338 | }
339 | });
340 |
341 | }
342 |
343 | function load() {
344 | loader('load');
345 | }
346 |
347 | function load_prev() {
348 | loader('loadprev')
349 | }
350 |
351 | function loader(uri) {
352 | $.ajax({
353 | method: "POST",
354 | url: uri,
355 | data: {
356 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
357 | ID: frame_str
358 | },
359 | dataType: 'json',
360 | success: function(msg) {
361 | clean();
362 | var maxID = 0;
363 | for (var i = 0; i < msg.length; i++) {
364 | var rid = msg[i][0].rectangleID;
365 | var indof = rectsID.indexOf(rid);
366 | if(indof == -1) {
367 | rectsID.push(rid);
368 | saveRectLoad(msg[i]);
369 | chosen_rect = rectsID.length-1;
370 | identities[rid] = msg[i][7];
371 | var pid = msg[i][7];
372 | if(pid > maxID)
373 | maxID = pid;
374 | if(uri == "loadprev")
375 | validation[pid] = false;
376 | else
377 | validation[pid] = msg[i][8];
378 | }
379 | personID = maxID + 1;
380 | update();
381 | }
382 | }
383 | });
384 | }
385 | function clean() {
386 | for (var i = 0; i < cameras; i++) {
387 | boxes[i] = {};
388 | rectsID = [];
389 | validation = {};
390 | identities = {};
391 | personID = 0;
392 | chosen_rect = 0;
393 | }
394 | update();
395 | }
396 |
397 | function changeFrame(order,increment) {
398 | $.ajax({
399 | method: "POST",
400 | url: 'changeframe',
401 | data: {
402 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
403 | order: order,
404 | frameID: frame_str,
405 | incr: increment,
406 | },
407 | dataType: "json",
408 | success: function(msg) {
409 | frame_str = msg;
410 | loadcount = 0;
411 | $("#loader").show();
412 | fstr = frame_str;
413 | fstr = fstr.replace(/^0*/, "");
414 | $("#frameID").html("Frame ID: " + fstr +" ");
415 | for (var i = 0; i < cameras; i++)
416 | imgArray[i].src = '../../static/marker/day_2/annotation_final/'+ camName[i]+ '/begin/'+frame_str+'.png'; // change 00..0 by a frame variable
417 | clean();
418 | update();
419 | }
420 | });
421 |
422 | }
423 |
424 | function next() {
425 | changeFrame('next',1);
426 | }
427 |
428 | function prev() {
429 | changeFrame('prev',1);
430 | }
431 |
432 | function nextI() {
433 | changeFrame('next',10);
434 | }
435 |
436 | function prevI() {
437 | changeFrame('prev',10);
438 | }
439 |
440 | function validate() {
441 | var rid = rectsID[chosen_rect];
442 | var idPers = identities[rid];
443 | validation[idPers] = true;
444 | return false;
445 | }
446 |
447 | function changeID() {
448 | var newID = parseInt($("#pID").val());
449 | if (rectsID.length > 0 && newID >= 0) {
450 | var rid = rectsID[chosen_rect];
451 | var pid = identities[rid];
452 | var match = false;
453 | for (key in identities) {
454 | if (identities[key] == newID)
455 | match = true;
456 | }
457 | if(!match) {
458 | validation[newID]= validation[pid];
459 | delete validation[pid];
460 | identities[rid] = newID;
461 | for(key in boxes){
462 | if(pid in boxes[key]){
463 | var args = boxes[key][pid];
464 | boxes[key][newID] = args;
465 | delete boxes[key][pid];
466 | }
467 | }
468 | $("#pID").val(newID);
469 | } else {
470 | $("#pID").val(pid);
471 | }
472 | }
473 | }
474 |
475 |
476 | function sendAJAX(uri,data,id,suc) {
477 | $.ajax({
478 | method: "POST",
479 | url: uri,
480 | data: {
481 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
482 | data: data,
483 | ID: id
484 | },
485 | dataType: "json",
486 | success: function(msg) {
487 | if(msg.length > 0)
488 | suc(msg,id);
489 | update();
490 | }
491 | });
492 | }
493 |
494 | function saveRect(msg,pid) {
495 | for (var i = 0; i < msg.length; i++) {
496 | var ind = msg[i].cameraID;
497 | boxes[ind][pid] = msg[i];
498 | }
499 | }
500 |
501 | function saveRectLoad(msg) {
502 | for (var i = 0; i < msg.length-2; i++) {
503 | var ind = msg[i].cameraID;
504 | boxes[ind][msg[7]] = msg[i];
505 | }
506 | }
507 |
508 | function moveRect(msg,id) {
509 | var pid = identities[id];
510 | if(typeof boxes[0][pid] == "undefined") {
511 | return false;
512 | }
513 | var index = rectsID.indexOf(id);
514 | var nextRect = msg[0].rectangleID;
515 | rectsID.splice(index,1);
516 | rectsID.push(nextRect);
517 | chosen_rect = rectsID.length-1;
518 | identities[nextRect] = pid;
519 | delete identities[id];
520 | validation[pid] = true;
521 |
522 | for (var i = 0; i < msg.length; i++) {
523 | var f = msg[i];
524 | var ind = f.cameraID;
525 | var oldRect = boxes[ind][pid];
526 |
527 | var newRect = msg[i];
528 | if(oldRect.y1 != 0) {
529 | var heightR = Math.abs(oldRect.y1-oldRect.y2)*oldRect.ratio;
530 | var widthR = Math.abs(oldRect.x1-oldRect.x2)*oldRect.ratio;
531 | } else {
532 | var heightR = parseInt($("#pHeight").text());
533 | var widthR = parseInt($("#pWidth").text());
534 | }
535 | if(newRect.ratio > 0){
536 | newRect.y1 = Math.round(newRect.y2 - (heightR/newRect.ratio));
537 | var delta = widthR/(2*newRect.ratio);
538 | newRect.x2 = Math.round(newRect.xMid + delta);
539 | newRect.x1 = Math.round(newRect.xMid - delta);
540 | }
541 | boxes[ind][pid] = newRect;
542 | }
543 | }
544 |
545 | function update() {
546 | chosen_rect = ((chosen_rect % rectsID.length) + rectsID.length) % rectsID.length;
547 | $("#pID").val(identities[rectsID[chosen_rect]]);
548 | drawRect();
549 | if(toggle_ground)
550 | drawGround();
551 |
552 | }
553 |
554 | function drawRect() {
555 | for (var i = 0; i < cameras; i++) {
556 | var c = document.getElementById("canv"+(i+1));
557 | var ctx=c.getContext("2d");
558 | ctx.clearRect(0, 0, c.width, c.height);
559 | ctx.drawImage(imgArray[i],0,0);
560 | if(toggle_orientation)
561 | drawArrows(ctx,i);
562 | }
563 | var heightR = 0;
564 | var widthR = 0;
565 | var sumH = 0;
566 | for (key in boxes) {
567 | for (var r = 0; r < rectsID.length; r++) {
568 | var field = boxes[key][identities[rectsID[r]]];
569 | if(field.y1 > 0) {
570 | var c = document.getElementById("canv"+(field.cameraID+1));
571 | var ctx=c.getContext("2d");
572 | var w = field.x2 - field.x1;
573 | var h = field.y2 - field.y1;
574 | if(r == chosen_rect) {
575 | ctx.strokeStyle="cyan";
576 | ctx.lineWidth="7";
577 | heightR += (field.y2-field.y1)*field.ratio;
578 | widthR += (field.x2-field.x1)*field.ratio;
579 | sumH += 1;
580 | } else {
581 | var pid = identities[field.rectangleID];
582 | if(validation[pid])
583 | ctx.strokeStyle="white";
584 | else
585 | ctx.strokeStyle="yellow";
586 |
587 | ctx.lineWidth="4";
588 |
589 | }
590 |
591 |
592 | ctx.beginPath();
593 | ctx.rect(field.x1,field.y1,w,h);
594 | ctx.stroke();
595 | ctx.closePath();
596 |
597 | ctx.beginPath();
598 | ctx.fillStyle = "red";
599 | ctx.fillRect(field.xMid-5,field.y2-5,10,10);
600 | ctx.stroke();
601 | ctx.closePath();
602 | }
603 | }
604 | }
605 | if(chosen_rect >= 0) {
606 | $("#pHeight").text(Math.round(heightR/sumH));
607 | $("#pWidth").text(Math.round(widthR/sumH));
608 | } else {
609 | $("#pHeight").text(-1);
610 | $("#pWidth").text(-1);
611 | }
612 | }
613 |
614 | function drawGround() {
615 | for (var i = 0; i < cameras; i++) {
616 | var c = document.getElementById("canv"+(i+1));
617 | var ctx=c.getContext("2d");
618 | ctx.strokeStyle="chartreuse";
619 | ctx.lineWidth="2";
620 | ctx.beginPath();
621 |
622 | ctx.moveTo(bounds[i][0], bounds[i][1]);
623 | for (var j = 2; j < bounds[i].length; j=j+2) {
624 | if(bounds[i][j] >= 0) {
625 | ctx.lineTo(bounds[i][j], bounds[i][j+1]);
626 | }
627 | }
628 | ctx.stroke();
629 | ctx.closePath();
630 |
631 | }
632 | }
633 |
634 | function drawArrows(ctx, idx) {
635 | ctx.drawImage(arrArray[idx],0,0);
636 | }
637 |
638 | function zoomControl() {
639 | if(rectsID.length > 0){
640 | if(!zoomOn) {
641 | zoomIn();
642 | } else {
643 | zoomOut();
644 | }
645 |
646 | }
647 | update();
648 | }
649 |
650 | function zoomIn() {
651 | for (var i = 0; i < cameras; i++) {
652 | var pid = identities[rectsID[chosen_rect]];
653 | var r = boxes[i][pid];
654 |
655 | var c = document.getElementById("canv"+(i+1));
656 |
657 | zoomratio[i] = c.height*60/(100*(r.y2-r.y1));
658 | if(zoomratio[i] != Infinity) {
659 |
660 | var ctx = c.getContext('2d');
661 | c.width=c.width/zoomratio[i];
662 | c.height=c.height/zoomratio[i];
663 | var originx = r.xMid - c.width/2;
664 | // var originx = r.xMid;
665 | var originy = r.y1-12.5*c.clientHeight/100;
666 | // ctx.scale(1.75,1.75);
667 | ctx.translate(-originx, -originy);
668 |
669 | }
670 | }
671 | zoomOn = true;
672 | return false;
673 |
674 | }
675 |
676 |
677 | function zoomOut() {
678 | for (var i = 0; i < cameras; i++) {
679 | var c = document.getElementById("canv"+(i+1));
680 | if(zoomratio[i] != Infinity) {
681 | c.width=c.width*zoomratio[i];
682 | c.height=c.height*zoomratio[i];
683 | }
684 | }
685 | zoomOn = false;
686 | return false;
687 |
688 | }
689 |
690 |
691 | function toggleGround() {
692 | if(toggle_ground == false)
693 | toggle_ground = true;
694 | else
695 | toggle_ground=false;
696 | update();
697 | return false;
698 | }
699 |
700 | function toggleOrientation() {
701 | if(toggle_orientation == false)
702 | toggle_orientation = true;
703 | else
704 | toggle_orientation=false;
705 | update();
706 | return false;
707 | }
708 |
709 | function load_file(f){
710 | var re = f.match(/_(.*)\./);
711 | if(re == null)
712 | var frame_string = f.split(".")[0];
713 | else
714 | var frame_string = f.match(/_(.*)\./).pop();
715 | $.ajax({
716 | method: "POST",
717 | url: "loadfile",
718 | data: {
719 | csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
720 | ID: f
721 | },
722 | dataType: 'json',
723 | success: function(msg) {
724 | clean();
725 | load_frame(frame_string);
726 | var maxID = 0;
727 | for (var i = 0; i < msg.length; i++) {
728 | var rid = msg[i][0].rectangleID;
729 | var indof = rectsID.indexOf(rid);
730 | if(indof == -1) {
731 | rectsID.push(rid);
732 | saveRectLoad(msg[i]);
733 | chosen_rect = rectsID.length-1;
734 | identities[rid] = msg[i][7];
735 | var pid = msg[i][7];
736 | if(pid > maxID)
737 | maxID = pid;
738 |
739 | validation[pid] = msg[i][8];
740 | }
741 | personID = maxID + 1;
742 | update();
743 | }
744 | }
745 | });
746 |
747 | }
748 |
749 | function load_frame(frame_string) {
750 | loadcount = 0;
751 | $("#loader").show();
752 | fstr = frame_string;
753 | fstr = fstr.replace(/^0*/, "");
754 | frame_str = frame_string;
755 | $("#frameID").html("Frame ID: " + fstr +" ");
756 | for (var i = 0; i < cameras; i++)
757 | imgArray[i].src = '../../static/marker/day_2/annotation_final/'+ camName[i]+ '/begin/'+frame_string+'.png'; // change 00..0 by a frame variable
758 | clean();
759 | update();
760 | }
761 |
--------------------------------------------------------------------------------
/marker/static/marker/rect.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/static/marker/rect.pickle
--------------------------------------------------------------------------------
/marker/templates/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/templates/.DS_Store
--------------------------------------------------------------------------------
/marker/templates/includes/controller.html:
--------------------------------------------------------------------------------
1 | {% load marker_extra%}
2 |
3 |
4 |
5 |
6 |
Selection
7 |
8 | Next
9 | Previous
10 | Remove
11 |
12 |
13 |
14 |
15 |
Position
16 |
17 | Up
18 | Left
19 | Right
20 | Down
21 |
22 |
23 |
24 |
25 |
Size
26 |
27 |
28 |
Height
29 |
30 | +
31 | -
32 |
33 |
34 |
35 |
Width
36 |
37 | +
38 | -
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/marker/templates/includes/footer.html:
--------------------------------------------------------------------------------
1 |
8 |
12 |
--------------------------------------------------------------------------------
/marker/templates/includes/help.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
25 | Left click (on an image) : place a bounding box.
26 | Arrows : move the selected bounding box.
27 | Shift + Arrows : resize the selected bounding box.
28 | z : zoom on the selected bounding box (press again to zoom out).
29 | Backspace : remove the selected bounding box.
30 | Space / Tab : select the next/previous the bounding box.
31 | e : validate the placement of a yellow bounding box.
32 | h : hide/show the orientation helper.
33 | t : hide/show the ground area limits.
34 | Cyan box : selected bounding box
35 | White box : standard bounding box
36 | Yellow box : Unvalidated bounding box
37 | The bounding box should surround the person on all images it appears. (see Example 1 tab)
38 |
39 |
40 |
41 |
42 |
43 |
The bounding box should surround the person on all images it appears.
44 |
45 | Good
46 | All the bounding boxes sourround the lady
47 |
48 | Bad
49 | The box seems correctly placed on the top right image, but not in the other images.
50 | In this case, you have to adjust the position using the arrows to obtain the results seen on the "Good" example
51 |
52 |
53 |
54 |
55 |
56 |
57 |
The bounding box should surround the person on all images it appears.
58 |
59 | Note that the orientation helper and the blue arrows have another orientation on every frame since the angle changes.
60 |
61 |
62 |
63 |
64 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/marker/templates/includes/load.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load marker_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 | {% csrf_token %}
16 |
17 |
18 |
19 |
20 |
21 |
Saved files
22 |
23 |
24 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/marker/templates/includes/navbar.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
14 |
15 |
16 | {% if user.is_authenticated %}
17 | Logout
18 | {% endif %}
19 | Help
20 |
21 |
22 |
23 | {% include "includes/help.html" %}
24 |
--------------------------------------------------------------------------------
/marker/templates/includes/side_menu.html:
--------------------------------------------------------------------------------
1 | {% load marker_extra%}
2 |
3 |
4 |
5 |
Infos
6 |
7 |
Person height:
8 |
-1
9 |
10 |
11 |
12 |
Person width:
13 |
-1
14 |
15 |
16 |
17 |
18 |
Person ID:
19 |
20 |
21 |
Save ID
22 |
23 |
24 |
--------------------------------------------------------------------------------
/marker/templates/includes/tuto.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
Left click (on an image) : place a bounding box.
25 |
Arrows : move the selected bounding box.
26 |
Shift + Arrows : resize the selected bounding box.
27 |
z : zoom on the selected bounding box (press again to zoom out).
28 |
Backspace : remove the selected bounding box.
29 |
Space / Tab : select the next/previous the bounding box.
30 |
e : validate the placement of a yellow bounding box.
31 |
Cyan box : selected bounding box
32 |
White box : standard bounding box
33 |
Yellow box : Unvalidated bounding box
34 |
Be sure that the bounding box surrounds the person on all images. (see example tab)
35 |
36 |
37 |
38 |
39 |
Be sure that the bounding box surrounds the person on all images.
40 |
41 |
Good
42 |
All the bounding boxes sourround the lady
43 |
44 |
Bad
45 |
The box seems correctly placed on the top right image, but not in the other images.
46 | In this case, you have to adjust the position using the arrows to obtain the results seen on the "Good" example
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/marker/templates/marker/download.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load marker_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {% include "includes/navbar.html" %}
15 |
68 |
69 | {% include "includes/footer.html" %}
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/marker/templates/marker/download_worker.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load marker_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | {% include "includes/navbar.html" %}
15 |
68 |
69 | {% include "includes/footer.html" %}
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/marker/templates/marker/frame.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load marker_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 | {% include "includes/navbar.html" %}
23 |
24 | {% csrf_token %}
25 |
26 |
27 |
47 |
60 |
61 |
62 |
63 | {% include "includes/side_menu.html" %}
64 | {% include "includes/controller.html" %}
65 |
66 |
67 |
68 | {% include "includes/footer.html" %}
69 | {% include "includes/load.html" %}
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/marker/templates/marker/index.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 | {% include "includes/navbar.html" %}
18 | {% csrf_token %}
19 |
44 | {% include "includes/footer.html" %}
45 |
46 | {% include "includes/tuto.html" %}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/marker/templates/marker/login.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load gtm_hit_extra %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 | {% include "includes/navbar.html" %}
18 | {% csrf_token %}
19 |
44 | {% include "includes_home/footer.html" %}
45 |
46 | {% include "includes/tuto.html" %}
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/marker/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cvlab-epfl/multicam-gt/29486f0bc6bcbffa1924b4b53466a654093e38e8/marker/templatetags/__init__.py
--------------------------------------------------------------------------------
/marker/templatetags/marker_extra.py:
--------------------------------------------------------------------------------
1 | from django import template
2 | from marker.models import *
3 | from django.utils import timezone
4 | import json
5 | from django.core import serializers
6 |
7 | register = template.Library()
8 |
9 | @register.filter(name='next')
10 | def next(value):
11 | return int(value)+1
12 |
13 | @register.filter(name='prev')
14 | def prev(value):
15 | f = int(value)
16 | if f > 0:
17 | return f-1
18 | else:
19 | return f
20 |
21 | @register.filter(name='toJSON')
22 | def toJSON(value):
23 | return serializers.serialize("json",value)
24 |
25 |
26 | @register.filter(name='rows')
27 | def rows(thelist, n):
28 | try:
29 | n = int(n)
30 | thelist = list(thelist)
31 | except (ValueError, TypeError):
32 | return [thelist]
33 | list_len = len(thelist)
34 | split = list_len // n
35 |
36 | if list_len % n != 0:
37 | split += 1
38 | return [thelist[split*i:split*(i+1)] for i in range(n)]
39 |
40 | @register.filter(name='rows_distributed')
41 | def rows_distributed(thelist, n):
42 |
43 | try:
44 | n = int(n)
45 | thelist = list(thelist)
46 | except (ValueError, TypeError):
47 | return [thelist]
48 | list_len = len(thelist)
49 | split = list_len // n
50 |
51 | remainder = list_len % n
52 | offset = 0
53 | rows = []
54 | for i in range(n):
55 | if remainder:
56 | start, end = (split+1)*i, (split+1)*(i+1)
57 | else:
58 | start, end = split*i+offset, split*(i+1)+offset
59 | rows.append(thelist[start:end])
60 | if remainder:
61 | remainder -= 1
62 | offset += 1
63 | return rows
64 |
65 | @register.filter(name='columns')
66 | def columns(thelist, n):
67 | """
68 | Break a list into ``n`` columns, filling up each column to the maximum equal
69 | length possible. For example::
70 |
71 | >>> from pprint import pprint
72 | >>> for i in range(7, 11):
73 | ... print '%sx%s:' % (i, 3)
74 | ... pprint(columns(range(i), 3), width=20)
75 | 7x3:
76 | [[0, 3, 6],
77 | [1, 4],
78 | [2, 5]]
79 | 8x3:
80 | [[0, 3, 6],
81 | [1, 4, 7],
82 | [2, 5]]
83 | 9x3:
84 | [[0, 3, 6],
85 | [1, 4, 7],
86 | [2, 5, 8]]
87 | 10x3:
88 | [[0, 4, 8],
89 | [1, 5, 9],
90 | [2, 6],
91 | [3, 7]]
92 |
93 | # Note that this filter does not guarantee that `n` columns will be
94 | # present:
95 | >>> pprint(columns(range(4), 3), width=10)
96 | [[0, 2],
97 | [1, 3]]
98 | """
99 | try:
100 | n = int(n)
101 | thelist = list(thelist)
102 | except (ValueError, TypeError):
103 | return [thelist]
104 | list_len = len(thelist)
105 | split = list_len // n
106 | if list_len % n != 0:
107 | split += 1
108 | return [thelist[i::split] for i in range(split)]
109 |
110 | register.filter(rows)
111 | register.filter(rows_distributed)
112 | register.filter(columns)
113 |
114 | def _test():
115 | import doctest
116 | doctest.testmod()
117 |
118 | if __name__ == "__main__":
119 | _test()
120 |
--------------------------------------------------------------------------------
/marker/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/marker/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | url(r'^$', views.index, name="index"),
7 | url(r'^frame$', views.frame, name='frame'),
8 | url(r'^frame/(?P[0-9]+)$', views.framenb, name='framenb'),
9 | url(r'^download$',views.download,name='download'),
10 | url(r'^downloadwk$',views.download_worker,name='downloadwk'),
11 | url(r'^.*click',views.click,name="click"),
12 | url(r'^.*move',views.move,name="move"),
13 | url(r'^.*changeframe$', views.changeframe, name='changeframe'),
14 | url(r'^.*save$',views.save,name='save'),
15 | url(r'^.*load$',views.load,name='load'),
16 | url(r'^.*loadfile$',views.loadfile,name='loadfile'),
17 | url(r'^.*loadprev$',views.load_previous,name='loadprev'),
18 | url(r'^login/$', views.user_login, name='login'),
19 | url(r'^logout/$', views.user_logout, name='logout'),
20 | ]
21 |
--------------------------------------------------------------------------------
/marker/views.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from django.shortcuts import get_object_or_404,render, redirect
3 | from django.contrib.auth import authenticate, login, logout
4 | from django.contrib.auth.decorators import login_required
5 | from django.http import HttpResponseRedirect, HttpResponse
6 | from django.core import serializers
7 | from django.core.urlresolvers import reverse
8 | from django.views import generic
9 | from django.utils import timezone
10 | from django.conf import settings
11 | from django.template import RequestContext
12 | import re
13 | import json
14 | import os
15 | import zipfile
16 | from io import BytesIO
17 |
18 |
19 | def index(request):
20 | context = RequestContext(request)
21 | return render(request, 'marker/index.html',{},context)
22 |
23 | def framenb(request,frame_number):
24 | context = RequestContext(request)
25 | files = list_files()
26 | return render(request, 'marker/frame.html',{'frame_number': frame_number,'cams': settings.CAMS, 'files':files},context)
27 |
28 | def frame(request):
29 | context = RequestContext(request)
30 | frame_number = 0
31 | files = list_files()
32 | return render(request, 'marker/frame.html',{'frame_number': frame_number,'cams': settings.CAMS,'files':files},context)
33 |
34 | def list_files():
35 | worker_p = "gtm_hit/labels"
36 | files = os.listdir(worker_p)
37 | marker_p = "marker/labels"
38 | files = files + os.listdir(marker_p)
39 | return files
40 | def click(request):
41 | if request.is_ajax():
42 | try:
43 | x = int(request.POST['x'])
44 | y = int(request.POST['y'])
45 | cam = request.POST['canv']
46 | cam = int(re.findall('\d+',cam)[0]) - 1
47 | if 0 <= cam < settings.NB_CAMS:
48 | closest = -1
49 | vbest = 1000
50 | for y_temp in range(y - settings.DELTA_SEARCH, y + settings.DELTA_SEARCH):
51 | if 0 <= y_temp < 1080:
52 | for x_temp in settings.FIND_RECT[cam][y_temp]:
53 | vtemp = abs(y - y_temp) + abs(x - x_temp)
54 | if vtemp < vbest:
55 | vbest, closest = vtemp, settings.FIND_RECT[cam][y_temp][x_temp]
56 | if closest != -1:
57 | rects = get_rect(closest)
58 | rect_json = json.dumps(rects)
59 | return HttpResponse(rect_json,content_type="application/json")
60 |
61 | return HttpResponse("OK")
62 | except KeyError:
63 | return HttpResponse("Error")
64 | return HttpResponse("No")
65 |
66 | def move(request):
67 | if request.is_ajax():
68 | try:
69 | if request.POST['data'] == "down":
70 | rectID = request.POST['ID']
71 | if int(rectID) // settings.NB_WIDTH > 0:
72 | nextID = int(rectID) - settings.NB_WIDTH
73 | else:
74 | return HttpResponse(json.dumps([]),content_type="application/json")
75 |
76 | elif request.POST['data'] == "up":
77 | rectID = request.POST['ID']
78 | if int(rectID) // settings.NB_WIDTH < settings.NB_HEIGHT - 1:
79 | nextID = int(rectID) + settings.NB_WIDTH
80 | else:
81 | return HttpResponse(json.dumps([]),content_type="application/json")
82 |
83 | elif request.POST['data'] == "right":
84 | rectID = request.POST['ID']
85 | if int(rectID) % settings.NB_WIDTH < settings.NB_WIDTH - 1:
86 | nextID = int(rectID) + 1
87 | else:
88 | return HttpResponse(json.dumps([]),content_type="application/json")
89 |
90 | elif request.POST['data'] == "left":
91 | rectID = request.POST['ID']
92 | if int(rectID) % settings.NB_WIDTH > 0:
93 | nextID = int(rectID) - 1
94 | else:
95 | return HttpResponse(json.dumps([]),content_type="application/json")
96 |
97 | else:
98 | return HttpResponse("Error")
99 | next_rect = get_rect(nextID)
100 | next_rect_json = json.dumps(next_rect)
101 | return HttpResponse(next_rect_json,content_type="application/json")
102 |
103 | except KeyError:
104 | return HttpResponse("Error")
105 | return HttpResponse("Error")
106 |
107 | def save(request):
108 | if request.is_ajax():
109 | try:
110 | data = json.loads(request.POST['data'])
111 | frameID = request.POST['ID']
112 | annotations = []
113 | cols = ["rectID","personID","modified","a1","b1","c1","d1","a2","b2","c2","d2","a3","b3","c3","d3","a4","b4","c4","d4","a5","b5","c5","d5","a6","b6","c6","d6","a7","b7","c7","d7"]
114 | annotations.append(cols)
115 | for r in data:
116 | row = data[r]
117 | row.insert(0,int(r))
118 | annotations.append(row)
119 | with open("marker/labels/"+frameID + '.json', 'w') as outFile:
120 | json.dump(annotations, outFile, sort_keys=True, indent=4, separators=(',', ': '))
121 | return HttpResponse("Saved")
122 | except KeyError:
123 | return HttpResponse("Error")
124 | else:
125 | return("Error")
126 |
127 | def load(request):
128 | if request.is_ajax():
129 | try:
130 | frameID = request.POST['ID']
131 | rect_json = read_save(frameID)
132 | return HttpResponse(rect_json,content_type="application/json")
133 | except (FileNotFoundError, KeyError):
134 | return HttpResponse("Error")
135 | return HttpResponse("Error")
136 |
137 | def load_previous(request):
138 | if request.is_ajax():
139 | try:
140 | frameID = request.POST['ID']
141 | current_frame = int(frameID)
142 | closest = float('inf')
143 | diff = float('inf')
144 |
145 | for f in os.listdir("marker/labels/"):
146 | if f.endswith(".json"):
147 | nb_frame = int(f.split('.')[0])
148 |
149 | if nb_frame < current_frame:
150 | if current_frame - nb_frame < diff:
151 | diff = current_frame - nb_frame
152 | closest = nb_frame
153 | if closest != float('inf'):
154 | frame = "0" * (8 - len(str(closest))) + str(closest)
155 | rect_json = read_save(frame)
156 | return HttpResponse(rect_json,content_type="application/json")
157 | except (FileNotFoundError, KeyError):
158 | return HttpResponse("Error")
159 | return HttpResponse("Error")
160 |
161 | def read_save(frameID,fullpath=False):
162 | if(fullpath):
163 | if frameID[0].isdecimal():
164 | filename = "marker/labels/" + frameID
165 | else:
166 | filename = "gtm_hit/labels/" + frameID
167 | else:
168 | filename = "marker/labels/"+ frameID + '.json'
169 | with open(filename,'r') as loadFile:
170 | annotations = json.load(loadFile)
171 | rects = []
172 | for i in annotations[1:]:
173 | r = get_rect(i[0])
174 | for j in range(settings.NB_CAMS):
175 | r[j]['x1'] = i[j*4+3]
176 | r[j]['y1'] = i[j*4+4]
177 | r[j]['x2'] = i[j*4+5]
178 | r[j]['y2'] = i[j*4+6]
179 | r.append(i[1])
180 | r.append(i[2])
181 | rects.append(r)
182 | return json.dumps(rects)
183 |
184 | def changeframe(request):
185 | if request.is_ajax():
186 | frame = 0
187 | try:
188 | order = request.POST['order']
189 | frame_number = request.POST['frameID']
190 | increment = request.POST['incr']
191 | if order == "next":
192 | frame = int(frame_number) + int(increment)
193 | elif order == "prev" and (int(frame_number) - int(increment)) >= 0:
194 | frame = int(frame_number) - int(increment)
195 | else:
196 | return HttpResponse("Requested frame not existing")
197 | frame = "0" * (8 - len(str(frame))) + str(frame)
198 | return HttpResponse(json.dumps(frame))
199 | except KeyError:
200 | return HttpResponse("Error")
201 | else:
202 | return HttpResponse("Error")
203 |
204 | def get_rect(closest):
205 | rects = []
206 | for i in range(settings.NB_CAMS):
207 | rdic = {}
208 | rdic['rectangleID'] = closest
209 | if closest in settings.RECT[i]:
210 | a,b,c,d,ratio = settings.RECT[i][closest]
211 | else:
212 | a,b,c,d,ratio = 0,0,0,0,0
213 | rdic['x1'] = a
214 | rdic['y1'] = b
215 | rdic['x2'] = c
216 | rdic['y2'] = d
217 | rdic['cameraID'] = i
218 | rdic['ratio'] = ratio
219 | rdic['xMid'] = (a + c) // 2
220 | rects.append(rdic)
221 | return rects
222 |
223 | def download(request):
224 | context = RequestContext(request)
225 | fpath = "marker/labels"
226 | files = os.listdir(fpath)
227 | todl = []
228 | if request.method == "POST":
229 |
230 | zip_dir = "annotations"
231 | zip_name = zip_dir + ".zip"
232 | s = BytesIO()
233 | zf = zipfile.ZipFile(s,"w")
234 |
235 | if 'dlselect' in request.POST:
236 | for r in request.POST:
237 | if r in files:
238 | zipath = os.path.join(zip_dir,r)
239 | zf.write(fpath + "/" + r,zipath)
240 | zf.close()
241 | resp = HttpResponse(s.getvalue(), content_type = "application/x-zip-compressed")
242 | resp['Content-Disposition'] = 'attachment; filename=' + zip_name
243 | return resp
244 |
245 | elif 'dlall' in request.POST:
246 | for r in files:
247 | zipath = os.path.join(zip_dir,r)
248 | zf.write(fpath + "/" + r,zipath)
249 | zf.close()
250 | resp = HttpResponse(s.getvalue(), content_type = "application/x-zip-compressed")
251 | resp['Content-Disposition'] = 'attachment; filename=' + zip_name
252 | return resp
253 |
254 | return render(request, 'marker/download.html',{'files': files},context)
255 |
256 | def download_worker(request):
257 | context = RequestContext(request)
258 | fpath = "gtm_hit/labels"
259 | files = os.listdir(fpath)
260 | todl = []
261 | if request.method == "POST":
262 |
263 | zip_dir = "annotations"
264 | zip_name = zip_dir + ".zip"
265 | s = BytesIO()
266 | zf = zipfile.ZipFile(s,"w")
267 |
268 | if 'dlselect' in request.POST:
269 | for r in request.POST:
270 | if r in files:
271 | zipath = os.path.join(zip_dir,r)
272 | zf.write(fpath + "/" + r,zipath)
273 | zf.close()
274 | resp = HttpResponse(s.getvalue(), content_type = "application/x-zip-compressed")
275 | resp['Content-Disposition'] = 'attachment; filename=' + zip_name
276 | return resp
277 |
278 | elif 'dlall' in request.POST:
279 | for r in files:
280 | zipath = os.path.join(zip_dir,r)
281 | zf.write(fpath + "/" + r,zipath)
282 | zf.close()
283 | resp = HttpResponse(s.getvalue(), content_type = "application/x-zip-compressed")
284 | resp['Content-Disposition'] = 'attachment; filename=' + zip_name
285 | return resp
286 |
287 | return render(request, 'marker/download.html',{'files': files},context)
288 |
289 |
290 | def user_login(request):
291 | context = RequestContext(request)
292 | error = False
293 | active = True
294 | if request.method == 'POST':
295 | username = request.POST['username']
296 | password = request.POST['password']
297 |
298 | user = authenticate(username=username, password=password)
299 |
300 | if user:
301 | if user.is_active:
302 | login(request, user)
303 | return HttpResponseRedirect('/marker/')
304 | else:
305 | active = False
306 | else:
307 | error = True
308 |
309 | return render(request,'marker/login.html', {'error': error, 'active':active}, context)
310 |
311 | @login_required
312 | def user_logout(request):
313 | logout(request)
314 | return HttpResponseRedirect('/')
315 |
316 |
317 | def loadfile(request):
318 | if request.is_ajax():
319 | try:
320 | fileID = request.POST['ID']
321 | rect_json = read_save(fileID,True)
322 | return HttpResponse(rect_json,content_type="application/json")
323 | except (FileNotFoundError, KeyError):
324 | return HttpResponse("Error")
325 | return HttpResponse("Error")
326 |
--------------------------------------------------------------------------------