AndrewD123 commited on
Commit
547362d
·
verified ·
1 Parent(s): f210612

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +254 -0
  2. requirements.txt +7 -0
app.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from deepface import DeepFace
2
+ import pandas as pd
3
+ import numpy as np
4
+ import os
5
+ from pathlib import Path
6
+ import datetime as dt
7
+ from PIL import Image, ImageDraw, ImageFont
8
+ import matplotlib.pyplot as plt
9
+ import gradio as gr
10
+
11
+ from plotly.subplots import make_subplots
12
+ import plotly.graph_objects as go
13
+
14
+ def get_download_btn(inp_file=None, is_raw_file=True):
15
+ if is_raw_file:
16
+ label = 'Скачать полный результат в формате .csv'
17
+ else:
18
+ label = 'Скачать статистику в формате .csv'
19
+ download_btn = gr.DownloadButton(
20
+ label=label,
21
+ value=inp_file,
22
+ visible=inp_file is not None,
23
+ )
24
+ return download_btn
25
+
26
+ def print_faces(face_objs, image_path):
27
+ # открыть картинку и создать объект для рисования
28
+ pil_image = Image.open(image_path)
29
+ draw = ImageDraw.Draw(pil_image)
30
+
31
+ line_widht = int(max(pil_image.size) * 0.003)
32
+ font_size = int(max(pil_image.size) * 0.015)
33
+
34
+ # настройки отрисовки
35
+ color = 'red'
36
+ font_path = 'LiberationMono-Regular.ttf'
37
+ font = ImageFont.truetype(str(font_path), size=font_size)
38
+ big_font = ImageFont.truetype(str(font_path), size=2*font_size)
39
+
40
+ # итерация по словарям для каждого лица
41
+ for i, res_dict in enumerate(face_objs):
42
+ # извлечение артибутов
43
+ age = res_dict['age']
44
+ x, y, w, h, left_eye, right_eye = res_dict['region'].values()
45
+ gender = res_dict['dominant_gender']
46
+ race = res_dict['dominant_race']
47
+ emotion = res_dict['dominant_emotion']
48
+ text_age = f'Возраст:{age}'
49
+ text_gender = f'Пол:{gender}'
50
+ text_race = f'Раса:{race}'
51
+ text_emo = f'Эмоция:{emotion}'
52
+
53
+ # отрисовка боксов и надписей
54
+ draw.rectangle((x, y, x + w, y + h), outline=color, width=line_widht)
55
+ draw.text(xy=(x + 10, y + 2*font_size), text=str(i), font=big_font, fill=color, anchor="lb")
56
+ draw.text(xy=(x, y - font_size), text=text_gender, font=font, fill=color, anchor="lb")
57
+ draw.text(xy=(x, y), text=text_age, font=font, fill=color, anchor="lb")
58
+ draw.text(xy=(x, y + h + font_size), text=text_race, font=font, fill=color, anchor="lb")
59
+ draw.text(xy=(x, y + h + 2*font_size), text=text_emo, font=font, fill=color, anchor="lb")
60
+
61
+ return pil_image
62
+
63
+ def get_stat(images_path):
64
+ '''
65
+ Функция на вход принимает путь к файлам, а возвращает датафрейм
66
+ с результатом обработки изображений
67
+ '''
68
+ # создаем пустой список для запиcи результатов
69
+
70
+ result_lst = []
71
+ result_image = np.nan
72
+ # создаем список картинок
73
+ for image in images_path:
74
+ # получим дату из названия
75
+ datetime = image.split('/')[-1].split('.')[0]
76
+ # получим данные из изображений
77
+ try:
78
+ face_objs = DeepFace.analyze(
79
+ img_path = image,
80
+ actions = ['age', 'gender', 'race', 'emotion'],
81
+ detector_backend = 'retinaface',
82
+ silent = True
83
+ )
84
+ if pd.isna(result_image):
85
+ result_image = print_faces(face_objs, image)
86
+
87
+ except ValueError:
88
+ face_objs = [{'region':{'x': 0,
89
+ 'y': 0,
90
+ 'w': 0,
91
+ 'h': 0,
92
+ 'left_eye': 0,
93
+ 'right_eye': 0},
94
+ 'age': np.nan,
95
+ 'dominant_gender': np.nan,
96
+ 'dominant_race': np.nan,
97
+ 'dominant_emotion': np.nan}]
98
+ res_face_objs = []
99
+ needed_keys = ['region', 'age', 'dominant_gender', 'dominant_race', 'dominant_emotion']
100
+ for res_dict in face_objs:
101
+ new_dict = dict((k, res_dict[k]) for k in needed_keys if k in res_dict)
102
+ new_dict['img_name'] = image.split('/')[-1]
103
+ new_dict['img_path'] = image
104
+ new_dict['datetime'] = datetime
105
+ res_face_objs.append(new_dict)
106
+ del new_dict
107
+ del face_objs
108
+ # добавим результаты в список
109
+ result_lst.extend(res_face_objs)
110
+ del res_face_objs
111
+ df = pd.DataFrame(result_lst)
112
+
113
+ df = df.reset_index()
114
+ df = df.rename(columns={
115
+ 'dominant_gender': 'gender',
116
+ 'dominant_race': 'race',
117
+ 'dominant_emotion': 'emotion',
118
+ 'index': 'id'
119
+ })
120
+
121
+ answer = f'''Проанализировано изображений: {len(images_path)}.
122
+ Найдено людей: {len(df.dropna())}'''
123
+
124
+ df['datetime'] = pd.to_datetime(df['datetime'], errors='coerce')
125
+ df['date'] = df['datetime'].dt.round('h')
126
+ df['age'] = df['age'].astype('Int32')
127
+
128
+ df.to_csv('raw_result.csv', index=False)
129
+ df[['id', 'datetime', 'date', 'age', 'gender', 'race', 'emotion']].to_csv('clean_result.csv', index=False)
130
+
131
+
132
+
133
+ #=========Графики=======
134
+ data1 = df.groupby('date')['id'].count().reset_index()
135
+ data2 = df.groupby('gender')['id'].count().reset_index()
136
+ data4 = df.groupby('emotion')['id'].count().reset_index()
137
+ data5 = df.groupby('race')['id'].count().reset_index()
138
+ fig = make_subplots(
139
+ rows=3, cols=2,
140
+ specs=[[{"colspan": 2}, None],
141
+ [{}, {}],
142
+ [{}, {}]],
143
+ subplot_titles=('Количество людей',
144
+ 'Гистограмма возраста',
145
+ 'Пол',
146
+ 'Эмоции',
147
+ 'Расы'),
148
+ shared_xaxes=False,
149
+ vertical_spacing=0.1)
150
+ # Количество людей
151
+ fig.add_trace(go.Scatter(x=data1['date'], y=data1['id'],
152
+ mode='lines+markers',
153
+ name='Количество людей',
154
+ marker_color = 'indianred'), row=1, col=1)
155
+ fig.update_xaxes(title_text = "Дата", row=1, col=1)
156
+ fig.update_yaxes(title_text = "Количество", row=1, col=1)
157
+ # Гистограмма возраста
158
+ fig.add_trace(go.Histogram(x=df.loc[df['gender'] == 'Man', 'age'],
159
+ name='Мужчины',
160
+ marker_color='lightsalmon'),row=2, col=1)
161
+ fig.add_trace(go.Histogram(x=df.loc[df['gender'] == 'Woman', 'age'],
162
+ name='Женщины',
163
+ marker_color='indianred'), row=2, col=1)
164
+ fig.update_xaxes(title_text = "Возраст", row=2, col=1)
165
+ fig.update_yaxes(title_text = "Количество", row=2, col=1)
166
+ # Пол
167
+ fig.add_trace(go.Bar(x=data2['gender'],
168
+ y=data2['id'],
169
+ text=data2['id'],
170
+ textposition='auto',
171
+ marker_color='lightsalmon'), row=2, col=2)
172
+ fig.update_xaxes(title_text = "Пол", row=2, col=2)
173
+ fig.update_yaxes(title_text = "Количество", row=2, col=2)
174
+ # Эмоции
175
+ fig.add_trace(go.Bar(x=data4['emotion'],
176
+ y=data4['id'],
177
+ text=data4['id'],
178
+ textposition='auto',
179
+ marker_color='lightsalmon'), row=3, col=1)
180
+ fig.update_xaxes(title_text = "Эмоции", row=3, col=1)
181
+ fig.update_yaxes(title_text = "Количество", row=3, col=1)
182
+ # Расы
183
+ fig.add_trace(go.Bar(x=data5['race'],
184
+ y=data5['id'],
185
+ text=data5['id'],
186
+ textposition='auto',
187
+ marker_color='lightsalmon'), row=3, col=2)
188
+
189
+ fig.update_xaxes(title_text = "Расы", row=3, col=2)
190
+ fig.update_yaxes(title_text = "Количество", row=3, col=2)
191
+
192
+ fig.update_layout(
193
+ showlegend=False,
194
+ title_text='Графики атрибутов',
195
+ barmode='stack',
196
+ autosize=False,
197
+ width=1000,
198
+ height=1200
199
+ )
200
+
201
+ return df, answer, result_image, fig
202
+
203
+ with gr.Blocks(theme=gr.themes.Citrus()) as demo:
204
+ # состояние с путем до файла
205
+ raw_result_path = gr.State('raw_result.csv')
206
+ clean_result_path = gr.State('clean_result.csv')
207
+ is_raw_file = gr.State(False)
208
+ gr.Markdown(
209
+ """
210
+ # Определение количества людей на изображениях, их пола, возраста, расы и эмоций
211
+ Введите путь до ваших изображений и получите результат.
212
+ """
213
+ )
214
+ with gr.Tab('Обзор'):
215
+ inp = gr.Files(file_count='directory')
216
+ btn = gr.Button("Получить результат")
217
+ res_text = gr.Textbox(label="Результаты")
218
+ with gr.Row():
219
+ with gr.Column():
220
+ res_data = gr.Dataframe()
221
+ raw_download_btn = get_download_btn(inp_file=None)
222
+ clean_download_btn = get_download_btn(inp_file=None)
223
+ res_img = gr.Image(label='Пример изображения')
224
+
225
+ with gr.Tab('Графики атрибутов'):
226
+ plot = gr.Plot()
227
+
228
+ out = [res_data, res_text, res_img, plot]
229
+ clean_dbtn_inp = [clean_result_path, is_raw_file]
230
+ btn.click(
231
+ fn=get_stat,
232
+ inputs=inp,
233
+ outputs=out,
234
+ ).success(
235
+ fn=get_download_btn,
236
+ inputs=[raw_result_path],
237
+ outputs=raw_download_btn
238
+ ).success(
239
+ fn=get_download_btn,
240
+ inputs=clean_dbtn_inp,
241
+ outputs=clean_download_btn
242
+ )
243
+
244
+ raw_download_btn.click(
245
+ lambda path: None,
246
+ inputs=[raw_result_path],
247
+ outputs=None
248
+ )
249
+ clean_download_btn.click(
250
+ lambda path: None,
251
+ inputs=[clean_result_path],
252
+ outputs=None
253
+ )
254
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ pandas==2.2.2
2
+ numpy==1.26.4
3
+ deepface==0.0.93
4
+ gradio==5.4.0
5
+ plotly==5.24.1
6
+ matplotlib==3.7.1
7
+ pillow==10.4.0