Going somewhere with a coffee.
This commit is contained in:
1 parent
84b9c2674c
commit
f5b8e24e01
6 files changed
+191
-5
No files matched your search
@@ -161,3 +161,6 @@ env
|
|||||||
*.ipynb
|
*.ipynb
|
||||||
.direnv
|
.direnv
|
||||||
result
|
result
|
||||||
|
dodgeballtracker/runs
|
||||||
|
data
|
||||||
|
outputs
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import abc
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
from pathlib import Path
|
||||||
|
from dodgeballtracker.typing import TrackedDetectedObject, VideoTimestamp
|
||||||
|
from sqlite3 import Connection
|
||||||
|
|
||||||
|
import pandera as pa
|
||||||
|
|
||||||
|
|
||||||
|
class DataDumper(abc.ABC):
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def write_boxes(self, obj: list[TrackedDetectedObject], ts: VideoTimestamp,
|
||||||
|
frame_index: int) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def start(self, video_path: Path, hexa_hash: str) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SQLiteDataDumper(DataDumper):
|
||||||
|
def __init__(self, conn: Connection):
|
||||||
|
self._conn = conn
|
||||||
|
self._video_id = None
|
||||||
|
|
||||||
|
def _create_tables(self):
|
||||||
|
cur = self._conn.cursor()
|
||||||
|
|
||||||
|
cur.executescript('''
|
||||||
|
CREATE TABLE IF NOT EXISTS video (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
file_name TEXT NOT NULL,
|
||||||
|
file_sha256_hex TEXT NOT NULL,
|
||||||
|
|
||||||
|
UNIQUE(file_sha256_hex)
|
||||||
|
);
|
||||||
|
''')
|
||||||
|
|
||||||
|
cur.executescript('''
|
||||||
|
CREATE TABLE IF NOT EXISTS video_frame(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
timestamp_ DOUBLE PRECISION NOT NULL,
|
||||||
|
index_ INTEGER NOT NULL,
|
||||||
|
video_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(video_id) REFERENCES video(id),
|
||||||
|
UNIQUE(video_id, index_)
|
||||||
|
);
|
||||||
|
''')
|
||||||
|
|
||||||
|
cur.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS tracked_detected_object(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
xmin DOUBLE PRECISION NOT NULL,
|
||||||
|
ymin DOUBLE PRECISION NOT NULL,
|
||||||
|
xmax DOUBLE PRECISION NOT NULL,
|
||||||
|
ymax DOUBLE PRECISION NOT NULL,
|
||||||
|
score DOUBLE PRECISION NOT NULL,
|
||||||
|
category INTEGER NOT NULL,
|
||||||
|
video_frame_id INTEGER NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY(video_frame_id) REFERENCES video_frame(id)
|
||||||
|
);
|
||||||
|
''')
|
||||||
|
|
||||||
|
self._conn.commit()
|
||||||
|
|
||||||
|
def start(self, video_path: Path, hexa_hash: str) -> None:
|
||||||
|
self._create_tables()
|
||||||
|
cur = self._conn.cursor()
|
||||||
|
res = cur.execute("""
|
||||||
|
INSERT INTO video(file_name, file_sha256_hex)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON CONFLICT(file_sha256_hex) DO NOTHING
|
||||||
|
RETURNING id
|
||||||
|
""", (video_path.name, hexa_hash))
|
||||||
|
self._video_id = res.fetchone()[0]
|
||||||
|
self._conn.commit()
|
||||||
|
|
||||||
|
@pa.check_io(df=TrackedDetectedObject)
|
||||||
|
def write_boxes(self,
|
||||||
|
df: pd.DataFrame,
|
||||||
|
ts: VideoTimestamp,
|
||||||
|
frame_index: int) -> None:
|
||||||
|
cur = self._conn.cursor()
|
||||||
|
res = cur.execute('''
|
||||||
|
INSERT INTO video_frame(timestamp_, index_, video_id )
|
||||||
|
VALUES (?, ?, ?)
|
||||||
|
ON CONFLICT(video_id, index_) DO NOTHING
|
||||||
|
RETURNING id
|
||||||
|
''', (ts, frame_index, self._video_id))
|
||||||
|
frame_id = res.fetchone()[0]
|
||||||
|
cols = ['xmin', 'ymin', 'xmax', 'ymax', 'score', 'category']
|
||||||
|
cur.executemany('''
|
||||||
|
INSERT INTO tracked_detected_object(xmin, ymin, xmax, ymax, score, category, video_frame_id)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
''', (list(x[cols]) + [frame_id] for x in df.iloc))
|
||||||
|
self._conn.commit()
|
||||||
@@ -10,7 +10,7 @@ import numpy as np
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import pandera as pa
|
import pandera as pa
|
||||||
from boxmot import DeepOcSort as DeepOCSORT
|
from boxmot import DeepOcSort as DeepOCSORT
|
||||||
from .typing import VideoFrame, DetectedObject_, TrackedDetectedObject
|
from .typing import VideoFrame, DetectedObject, TrackedDetectedObject
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ class DodgeballTracker:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@pa.check_output(DetectedObject_)
|
@pa.check_output(DetectedObject)
|
||||||
def run_model_on_frame(self, model, frame: VideoFrame):
|
def run_model_on_frame(self, model, frame: VideoFrame):
|
||||||
model_outputs = model(frame)[0]
|
model_outputs = model(frame)[0]
|
||||||
boxes = model_outputs.boxes.data.cpu().numpy()
|
boxes = model_outputs.boxes.data.cpu().numpy()
|
||||||
@@ -134,7 +134,7 @@ class DodgeballTracker:
|
|||||||
'/home/didier/all-dressed-programming/dodgeball-tracker/dodgeballtracker/runs/detect/train31/weights/best.pt')
|
'/home/didier/all-dressed-programming/dodgeball-tracker/dodgeballtracker/runs/detect/train31/weights/best.pt')
|
||||||
return YOLO(my_model, verbose=False)
|
return YOLO(my_model, verbose=False)
|
||||||
|
|
||||||
@pa.check_io(detected_objs=DetectedObject_, out=TrackedDetectedObject)
|
@pa.check_io(detected_objs=DetectedObject, out=TrackedDetectedObject)
|
||||||
def update_tracker(self, tracker: DeepOCSORT, detected_objs: pd.DataFrame, frame: VideoFrame):
|
def update_tracker(self, tracker: DeepOCSORT, detected_objs: pd.DataFrame, frame: VideoFrame):
|
||||||
data = tracker.update(detected_objs.to_numpy(), frame)
|
data = tracker.update(detected_objs.to_numpy(), frame)
|
||||||
columns = ['xmin', 'ymin', 'xmax', 'ymax', 'object_id', 'score', 'category', 'index']
|
columns = ['xmin', 'ymin', 'xmax', 'ymax', 'object_id', 'score', 'category', 'index']
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import sqlite3
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from sqlite3 import Connection
|
||||||
|
from dodgeballtracker.typing import TrackedDetectedObject
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import pandera as pa
|
||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
from contextlib import closing, contextmanager
|
||||||
|
|
||||||
|
from dodgeballtracker.data_dumper import SQLiteDataDumper
|
||||||
|
|
||||||
|
|
||||||
|
def list_tables(conn: Connection) -> set[str]:
|
||||||
|
cur = conn.cursor()
|
||||||
|
res = cur.execute('''
|
||||||
|
SELECT
|
||||||
|
name
|
||||||
|
FROM
|
||||||
|
sqlite_schema
|
||||||
|
WHERE
|
||||||
|
type ='table' AND
|
||||||
|
name NOT LIKE 'sqlite_%';
|
||||||
|
''')
|
||||||
|
return {row[0] for row in res}
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tmp_dir():
|
||||||
|
with tempfile.TemporaryDirectory() as dir_:
|
||||||
|
yield Path(dir_)
|
||||||
|
|
||||||
|
|
||||||
|
def number_of_items_in_table(table: str, conn: Connection) -> int:
|
||||||
|
cur = conn.cursor()
|
||||||
|
res = cur.execute(f'SELECT COUNT(*) FROM {table}')
|
||||||
|
return res.fetchone()[0]
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.fixture
|
||||||
|
@contextmanager
|
||||||
|
def make_conn(tmp_dir: Path):
|
||||||
|
db_file= tmp_dir / 'db.sqlite'
|
||||||
|
conn_ = sqlite3.connect(db_file)
|
||||||
|
with closing(conn_) as open_conn:
|
||||||
|
open_conn.execute('PRAGMA foreign_keys = 1')
|
||||||
|
yield open_conn
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
@pa.check_output(TrackedDetectedObject)
|
||||||
|
def mock_tracked_detected_object():
|
||||||
|
rd = np.random.RandomState(seed=109)
|
||||||
|
data = rd.rand(10, len(TrackedDetectedObject.columns))
|
||||||
|
return pd.DataFrame(data, columns=TrackedDetectedObject.columns)
|
||||||
|
|
||||||
|
|
||||||
|
def test_start(tmp_dir: Path):
|
||||||
|
with make_conn(tmp_dir) as conn:
|
||||||
|
dumper = SQLiteDataDumper(conn)
|
||||||
|
dumper.start(Path('foo/bar.MOV'), 'aaabbb')
|
||||||
|
assert dumper._video_id == 1
|
||||||
|
|
||||||
|
with make_conn(tmp_dir) as conn:
|
||||||
|
expt = {
|
||||||
|
'tracked_detected_object',
|
||||||
|
'video',
|
||||||
|
'video_frame'
|
||||||
|
}
|
||||||
|
assert expt == list_tables(conn)
|
||||||
|
|
||||||
|
#
|
||||||
|
def test_write_boxes_simple(tmp_dir: Path, mock_tracked_detected_object: pd.DataFrame):
|
||||||
|
with make_conn(tmp_dir) as conn:
|
||||||
|
dumper = SQLiteDataDumper(conn)
|
||||||
|
dumper.start(Path('/foo/toto.MOV'), 'aabbcc')
|
||||||
|
dumper.write_boxes(mock_tracked_detected_object, 40018, 34)
|
||||||
|
|
||||||
|
with make_conn(tmp_dir) as conn:
|
||||||
|
assert 10 == number_of_items_in_table('tracked_detected_object', conn)
|
||||||
@@ -10,11 +10,11 @@ def tensor_of(data_type: pa.DataType, cols: list[str]) -> pa.DataFrameSchema:
|
|||||||
return pa.DataFrameSchema({col: pa.Column(data_type) for col in cols})
|
return pa.DataFrameSchema({col: pa.Column(data_type) for col in cols})
|
||||||
|
|
||||||
|
|
||||||
DetectedObject_ = tensor_of(Float32, ["xmin", "ymin", "xmax", "ymax", "score",
|
DetectedObject = tensor_of(Float32, ["xmin", "ymin", "xmax", "ymax", "score",
|
||||||
"category"])
|
"category"])
|
||||||
|
|
||||||
TrackedDetectedObject = tensor_of(Float64,
|
TrackedDetectedObject = tensor_of(Float64,
|
||||||
list(DetectedObject_.columns) + ["object_id", "index"])
|
list(DetectedObject.columns) + ["object_id", "index"])
|
||||||
|
|
||||||
|
|
||||||
Color = tuple[int, int, int]
|
Color = tuple[int, int, int]
|
||||||
Reference in new issue
Block a user