Skip to content

Commit 3681fd0

Browse files
Merge pull request #36 from bassamadnan/main
Face recognition
2 parents c985eec + 8a3accd commit 3681fd0

36 files changed

+809
-249
lines changed

backend/app/config/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@
1212
ALBUM_DATABASE_PATH = "app/database/albums.db"
1313
MAPPINGS_DATABASE_PATH = "app/database/yolo_mapping.db"
1414
FACES_DATABASE_PATH = "app/database/faces.db"
15+
CLUSTERS_DATABASE_PATH = "app/database/clusters.db"

backend/app/database/albums.py

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,26 @@
33

44
from app.config.settings import ALBUM_DATABASE_PATH
55
from app.utils.wrappers import image_exists, album_exists
6-
from app.database.images import get_id_from_path, get_path_from_id
6+
from app.utils.path_id_mapping import get_id_from_path, get_path_from_id
7+
78

89
def create_albums_table():
910
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
1011
cursor = conn.cursor()
11-
cursor.execute("""
12+
cursor.execute(
13+
"""
1214
CREATE TABLE IF NOT EXISTS albums (
1315
album_name TEXT PRIMARY KEY,
1416
image_ids TEXT,
1517
description TEXT,
1618
date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
1719
)
18-
""")
20+
"""
21+
)
1922
conn.commit()
2023
conn.close()
2124

25+
2226
def create_album(album_name, description=None):
2327
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
2428
cursor = conn.cursor()
@@ -30,11 +34,14 @@ def create_album(album_name, description=None):
3034
conn.close()
3135
raise ValueError(f"Album '{album_name}' already exists")
3236

33-
cursor.execute("INSERT INTO albums (album_name, image_ids, description) VALUES (?, ?, ?)",
34-
(album_name, json.dumps([]), description))
37+
cursor.execute(
38+
"INSERT INTO albums (album_name, image_ids, description) VALUES (?, ?, ?)",
39+
(album_name, json.dumps([]), description),
40+
)
3541
conn.commit()
3642
conn.close()
3743

44+
3845
@album_exists
3946
def delete_album(album_name):
4047
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
@@ -43,13 +50,14 @@ def delete_album(album_name):
4350
conn.commit()
4451
conn.close()
4552

53+
4654
@album_exists
47-
@image_exists
4855
def add_photo_to_album(album_name, image_path):
4956
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
5057
cursor = conn.cursor()
5158

5259
image_id = get_id_from_path(image_path)
60+
# print("GOT IMAGE ID", image_id, flush=True)
5361
if image_id is None:
5462
conn.close()
5563
raise ValueError(f"Image '{image_path}' not found in the database")
@@ -59,28 +67,13 @@ def add_photo_to_album(album_name, image_path):
5967
image_ids = json.loads(result[0])
6068
if image_id not in image_ids:
6169
image_ids.append(image_id)
62-
cursor.execute("UPDATE albums SET image_ids = ? WHERE album_name = ?",
63-
(json.dumps(image_ids), album_name))
70+
cursor.execute(
71+
"UPDATE albums SET image_ids = ? WHERE album_name = ?",
72+
(json.dumps(image_ids), album_name),
73+
)
6474
conn.commit()
6575
conn.close()
6676

67-
@album_exists
68-
def add_photos_to_album(album_name, image_paths):
69-
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
70-
cursor = conn.cursor()
71-
72-
cursor.execute("SELECT image_ids FROM albums WHERE album_name = ?", (album_name,))
73-
result = cursor.fetchone()
74-
if result:
75-
existing_ids = json.loads(result[0])
76-
new_ids = [get_id_from_path(path) for path in image_paths if get_id_from_path(path) is not None]
77-
updated_ids = list(set(existing_ids + new_ids))
78-
79-
cursor.execute("UPDATE albums SET image_ids = ? WHERE album_name = ?",
80-
(json.dumps(updated_ids), album_name))
81-
82-
conn.commit()
83-
conn.close()
8477

8578
@album_exists
8679
def get_album_photos(album_name):
@@ -96,6 +89,7 @@ def get_album_photos(album_name):
9689
return [get_path_from_id(image_id) for image_id in image_ids]
9790
return None
9891

92+
9993
@album_exists
10094
@image_exists
10195
def remove_photo_from_album(album_name, image_path):
@@ -112,28 +106,60 @@ def remove_photo_from_album(album_name, image_path):
112106
image_ids = json.loads(result[0])
113107
if image_id in image_ids:
114108
image_ids.remove(image_id)
115-
cursor.execute("UPDATE albums SET image_ids = ? WHERE album_name = ?",
116-
(json.dumps(image_ids), album_name))
109+
cursor.execute(
110+
"UPDATE albums SET image_ids = ? WHERE album_name = ?",
111+
(json.dumps(image_ids), album_name),
112+
)
117113
conn.commit()
118114
conn.close()
119115

116+
120117
def get_all_albums():
121118
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
122119
cursor = conn.cursor()
123120

124121
cursor.execute("SELECT album_name, image_ids FROM albums")
125122
results = cursor.fetchall()
126-
albums = [{"album_name": name, "image_paths": [get_path_from_id(id) for id in json.loads(ids)]} for name, ids in results]
123+
albums = [
124+
{
125+
"album_name": name,
126+
"image_paths": [get_path_from_id(id) for id in json.loads(ids)],
127+
}
128+
for name, ids in results
129+
]
127130

128131
conn.close()
129132
return albums
130133

134+
131135
@album_exists
132136
def edit_album_description(album_name, new_description):
133137
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
134138
cursor = conn.cursor()
135-
136-
cursor.execute("UPDATE albums SET description = ? WHERE album_name = ?",
137-
(new_description, album_name))
139+
140+
cursor.execute(
141+
"UPDATE albums SET description = ? WHERE album_name = ?",
142+
(new_description, album_name),
143+
)
144+
conn.commit()
145+
conn.close()
146+
147+
148+
def remove_image_from_all_albums(image_id):
149+
conn = sqlite3.connect(ALBUM_DATABASE_PATH)
150+
cursor = conn.cursor()
151+
152+
cursor.execute("SELECT album_name, image_ids FROM albums")
153+
albums = cursor.fetchall()
154+
155+
for album_name, image_ids_json in albums:
156+
image_ids = json.loads(image_ids_json)
157+
if image_id in image_ids:
158+
image_ids.remove(image_id)
159+
cursor.execute(
160+
"UPDATE albums SET image_ids = ? WHERE album_name = ?",
161+
(json.dumps(image_ids), album_name),
162+
)
163+
138164
conn.commit()
139165
conn.close()

backend/app/database/faces.py

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,131 @@
11
import sqlite3
22
import json
33
import numpy as np
4-
from app.config.settings import FACES_DATABASE_PATH
5-
from app.database.images import get_id_from_path, get_path_from_id
4+
from app.config.settings import FACES_DATABASE_PATH, IMAGES_DATABASE_PATH
5+
66

77
def create_faces_table():
88
conn = sqlite3.connect(FACES_DATABASE_PATH)
99
cursor = conn.cursor()
10-
cursor.execute("""
10+
cursor.execute(
11+
"""
1112
CREATE TABLE IF NOT EXISTS faces (
1213
id INTEGER PRIMARY KEY AUTOINCREMENT,
1314
image_id INTEGER,
1415
embeddings TEXT,
15-
FOREIGN KEY (image_id) REFERENCES image_id_mapping(id)
16+
FOREIGN KEY (image_id) REFERENCES image_id_mapping(id) ON DELETE CASCADE
1617
)
17-
""")
18+
"""
19+
)
1820
conn.commit()
1921
conn.close()
2022

23+
2124
def insert_face_embeddings(image_path, embeddings):
25+
from app.database.images import get_id_from_path
26+
2227
conn = sqlite3.connect(FACES_DATABASE_PATH)
2328
cursor = conn.cursor()
24-
29+
2530
image_id = get_id_from_path(image_path)
2631
if image_id is None:
2732
conn.close()
2833
raise ValueError(f"Image '{image_path}' not found in the database")
29-
34+
3035
embeddings_json = json.dumps([emb.tolist() for emb in embeddings])
31-
32-
cursor.execute("""
36+
37+
cursor.execute(
38+
"""
3339
INSERT OR REPLACE INTO faces (image_id, embeddings)
3440
VALUES (?, ?)
35-
""", (image_id, embeddings_json))
36-
41+
""",
42+
(image_id, embeddings_json),
43+
)
44+
3745
conn.commit()
3846
conn.close()
3947

48+
4049
def get_face_embeddings(image_path):
50+
from app.database.images import get_id_from_path
51+
4152
conn = sqlite3.connect(FACES_DATABASE_PATH)
4253
cursor = conn.cursor()
43-
54+
4455
image_id = get_id_from_path(image_path)
4556
if image_id is None:
4657
conn.close()
4758
return None
48-
49-
cursor.execute("""
59+
60+
cursor.execute(
61+
"""
5062
SELECT embeddings FROM faces
5163
WHERE image_id = ?
52-
""", (image_id,))
53-
64+
""",
65+
(image_id,),
66+
)
67+
5468
result = cursor.fetchone()
5569
conn.close()
56-
70+
5771
if result:
5872
embeddings_json = result[0]
5973
embeddings = np.array(json.loads(embeddings_json))
6074
return embeddings
6175
else:
6276
return None
6377

78+
6479
def get_all_face_embeddings():
80+
from app.database.images import get_path_from_id
81+
6582
conn = sqlite3.connect(FACES_DATABASE_PATH)
6683
cursor = conn.cursor()
67-
68-
cursor.execute("""
84+
85+
cursor.execute(
86+
"""
6987
SELECT image_id, embeddings FROM faces
70-
""")
71-
88+
"""
89+
)
90+
7291
results = cursor.fetchall()
7392
all_embeddings = []
7493
for image_id, embeddings_json in results:
7594
image_path = get_path_from_id(image_id)
7695
embeddings = np.array(json.loads(embeddings_json))
7796
all_embeddings.append({"image_path": image_path, "embeddings": embeddings})
78-
97+
print("returning")
7998
conn.close()
8099
return all_embeddings
100+
101+
102+
def delete_face_embeddings(image_id):
103+
conn = sqlite3.connect(FACES_DATABASE_PATH)
104+
cursor = conn.cursor()
105+
106+
cursor.execute("DELETE FROM faces WHERE image_id = ?", (image_id,))
107+
108+
conn.commit()
109+
conn.close()
110+
111+
112+
def cleanup_face_embeddings():
113+
conn_images = sqlite3.connect(IMAGES_DATABASE_PATH)
114+
conn_faces = sqlite3.connect(FACES_DATABASE_PATH)
115+
cursor_images = conn_images.cursor()
116+
cursor_faces = conn_faces.cursor()
117+
118+
cursor_faces.execute("SELECT DISTINCT image_id FROM faces")
119+
face_image_ids = set(row[0] for row in cursor_faces.fetchall())
120+
121+
cursor_images.execute("SELECT id FROM image_id_mapping")
122+
valid_image_ids = set(row[0] for row in cursor_images.fetchall())
123+
124+
orphaned_ids = face_image_ids - valid_image_ids
125+
126+
for orphaned_id in orphaned_ids:
127+
cursor_faces.execute("DELETE FROM faces WHERE image_id = ?", (orphaned_id,))
128+
129+
conn_faces.commit()
130+
conn_images.close()
131+
conn_faces.close()

0 commit comments

Comments
 (0)