Skip to content

Commit 2cc5902

Browse files
authored
Merge branch 'main' into main
2 parents aaf15d4 + 686b189 commit 2cc5902

23 files changed

+268
-154
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
__pycache__/
33
.idea/
44
.vscode/
5-
frontend/static/faculty_img/
5+
frontend/static/face_dataset/

README.md

+37-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,37 @@
1-
# 23TGHON
2-
23학년도 티지톤 깃허브입니다.</br>
3-
pretrained facenet model download : https://github.com/nyoki-mtl/keras-facenet</br>
4-
You can upload img at frontend/static/faculty_img
1+
# Find someone who looks like using facenet
2+
Facenet makes embedding vector and we compare between vectors to find a similar person</br>
3+
You can give a face iamge to web application, then web application shows someone who looks like face image
4+
# How to use?
5+
1. install
6+
```bash
7+
# clone this repo
8+
git clone https://github.com/leejeongwoo1/facenet-web-project.git
9+
```
10+
```
11+
check requirements.txt and install libraries(ex. facenet-pytorch, flask ...)
12+
```
13+
2. include dataset:
14+
```
15+
Add face image at frontend/static/face_dataset to compare with client image
16+
```
17+
3. make embedding vector (json) about face_dataset
18+
```
19+
Run embeddings.py to make json file which includes 512D embedding vector about dataset
20+
You can check json file at /model
21+
```
22+
4. Run flask web application
23+
```shell
24+
set FLASK_APP=frontend
25+
flask run
26+
```
27+
# reference
28+
[facenet-pytorch](https://github.com/timesler/facenet-pytorch)</br>
29+
[facenet](https://github.com/davidsandberg/facenet)</br>
30+
[lovelyzDetector using facenet](https://github.com/hayunjong83/lovelyzDetector)</br>
31+
# web preview
32+
main page
33+
<img src="./ref/main_page.png" style="zoom: 100%;"/>
34+
find similary person
35+
<img src="./ref/detect_face.png" style="zoom: 100%;">
36+
error page
37+
<img src="./ref/error_page.png" style="zoom: 100%;">

frontend/static/basic.jpg

-10.3 KB
Binary file not shown.
-172 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.

frontend/static/client_img/client_img.txt

Whitespace-only changes.

frontend/static/client_img/lee.jpg

-31.8 KB
Binary file not shown.
-5.3 KB
Binary file not shown.
-5.3 KB
Binary file not shown.
-5.73 KB
Binary file not shown.

frontend/static/css/styles.css

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
.title {
2+
line-height: 0.5;
3+
text-align: center;
4+
color: #35465d;
5+
}
6+
.subtitle{
7+
line-height: 0.4;
8+
text-align: center;
9+
color: #35465d;
10+
}
11+
.center_position
12+
{
13+
margin: 0 auto;
14+
}
15+
.base_image
16+
{
17+
margin:auto;
18+
display:block;
19+
height : 18rem;
20+
width : 18rem;
21+
}
22+
.bottom_text
23+
{
24+
text-align: center;
25+
line-height: 0.5;
26+
}
27+
.client_img
28+
{
29+
float: left;
30+
margin-left: 15%;
31+
text-align: center;
32+
}
33+
.faculty_img
34+
{
35+
float:left;
36+
margin-left:15%;
37+
text-align:center;
38+
font-size:1.4rem;
39+
}
40+
h1{
41+
font-size: 4.5rem;
42+
}
43+
h3{
44+
line-height:0.2;
45+
}
46+
h4{
47+
font-size: 2rem;
48+
}
49+
h5{
50+
font-size:1.4rem;
51+
}
52+
h6{
53+
font-size:2rem;
54+
line-height:0;
55+
}
56+
body{
57+
font-family: 'Nanum Pen Script', cursive;
58+
}
59+
60+
.filebox label {
61+
text-align: center;
62+
display: inline-block;
63+
padding: .5em .75em;
64+
color: #f00231;
65+
font-size: 2rem;
66+
line-height: normal;
67+
background-color: #eeeeee;
68+
cursor: pointer;
69+
border: 1px solid #ebebeb;
70+
border-bottom-color: #e2e2e2;
71+
border-radius: .25em;
72+
}
73+
.filebox input[type="file"] {
74+
position: relative;
75+
width: 1px;
76+
height: 1px;
77+
padding: 0;
78+
margin: -1px;
79+
overflow: hidden;
80+
clip:rect(0,0,0,0);
81+
border: 0;
82+
}
83+
.submitbox
84+
{
85+
margin-top: 0.4rem;
86+
display: inline-block;
87+
text-align: center;
88+
}

frontend/static/face-id.png

13.5 KB
Loading
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Error</title>
8+
</head>
9+
<body style="text-align:center;">
10+
<h1>Error!!!</h1>
11+
<h2>{{error_message}}</h2>
12+
<a href ="/">메인화면으로 돌아가기</a>
13+
</body>
14+
</html>

frontend/templates/main/main.html

+35-27
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,48 @@
11
<!DOCTYPE html>
2-
<html lang="en">
2+
<html lang="en">
33
<head>
44
<meta charset="UTF-8">
55
<title>닮은 교수님 찾기</title>
6+
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
7+
<style>
8+
@import url('https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap');
9+
</style>
610
</head>
7-
<body style="box-sizing: border-box; width:100%; height:100vh; margin:0px;">
8-
<div style="box-sizing: border-box; width:40%; height:70%; margin:20px; float:left">
9-
<h5>찾고자 하는 사진을 업로드 해주세요!</h5>
10-
<div style="width:100%; height: 100%; border: 1px solid red; box-sizing: border-box">
11+
<body>
12+
<h1 class="title">닮은 교수님 찾기</h1>
13+
<h4 class="subtitle">얼굴로 보는 인공지능 교수님테스트</h4>
14+
<div class="center_position">
1115
{% if client_img %}
12-
<img src={{client_img}} style="width:70%;">
16+
<span class="client_img">
17+
<img src={{client_img}} style="width:400px; height:500px;">
18+
<a href="/"><h6>메인화면으로 돌아가기</h6></a>
19+
</span>
1320
{% else %}
14-
<img src='./static/basic.jpg' style="width:50%;">
21+
<img src='./static/face-id.png' class="base_image">
22+
<h5 class="bottom_text">제출 버튼을 누르면 교수님 사진이 업로드 됩니다!</h5>
23+
<h4 class="bottom_text">어떤 교수님과 닮았을까요?</h4>
1524
{% endif %}
16-
</div>
17-
<form action="{{url_for('main.create')}}" method="post" enctype="multipart/form-data">
18-
<input type="file" name="file"/>
19-
<input type="submit"/>
20-
</form>
21-
</div>
22-
23-
<div style="box-sizing: border-box; width:40%; height:70%; margin:20px; float:left">
24-
<h5>교수님 사진이 업로드 됩니다!</h5>
25-
<div style="width:100%; height: 100%; border: 1px solid red; box-sizing: border-box">
26-
{% if faculty %}
27-
<img src={{faculty}} style="width:50%;">
28-
{% else %}
29-
<h3>어떤 교수님과 닮았을까요?</h3>
30-
{% endif %}
31-
</div>
32-
<div>
3325
{% if faculty %}
34-
<h3>학과: {{department}}</h3>
26+
<span class="faculty_img">
27+
<img src={{faculty}} style="width:400px; height:500px;">
28+
<h3>소속: {{department}}</h3>
3529
<h3>성함: {{name}}</h3>
36-
{% endif %}
30+
<h3>유사도 : {{similarity}}%</h3>
31+
</span>
32+
</div>
33+
{% endif %}
34+
<div>
35+
<form action="{{url_for('main.create')}}" method="post" enctype="multipart/form-data">
36+
{% if not client_img %}
37+
<div class="filebox" style="display: flex; justify-content: center;">
38+
<label for="ex_file">얼굴 사진 선택(png,jpeg,jpg파일만허용)</label>
39+
<input type="file" name="file" id="ex_file" accept=".png, .jpeg, .jpg" >
40+
</div>
41+
<div class="submitbox" style="display: flex; justify-content: center;">
42+
<input type="submit">
43+
</div>
44+
{% endif %}
45+
</form>
3746
</div>
38-
</div>
3947
</body>
4048
</html>

frontend/views/main_views.py

+47-31
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,64 @@
1-
from flask import Blueprint, render_template, request
1+
from flask import Flask, Blueprint, render_template, request, flash
22
import numpy as np
33
from facenet_pytorch import MTCNN, InceptionResnetV1
44
import json
55
import sys
6+
import os
67
from PIL import Image
78
import time
89
sys.path.append('../../')
9-
bp = Blueprint('main',__name__,url_prefix='/')
10+
import PIL
11+
bp = Blueprint('main', __name__, url_prefix='/')
1012

1113
mtcnn = MTCNN(image_size=160, margin=0)
1214
resnet = InceptionResnetV1(pretrained='vggface2').eval()
1315

1416
@bp.route('/')
1517
def main():
16-
return render_template('main/main.html',client_img=False,faculty=False)
18+
return render_template('main/main.html', client_img=False, faculty=False)
1719

18-
@bp.route('/',methods=('POST',))
20+
@bp.route('/', methods=('POST',))
1921
def create():
20-
start=time.time()
22+
try:
23+
folder = "./frontend/static/client_img"
24+
for i in os.listdir("./frontend/static/client_img"):
25+
if i != "client_img.txt":
26+
os.remove(os.path.join(folder,i))
2127

22-
file = request.files['file']
23-
path = "./frontend/static/client_img/"+(file.filename)
24-
path_ = "./static/client_img/"+(file.filename)
25-
file.save(path)
26-
img = Image.open(path)
27-
img_cropped = mtcnn(img)
28+
file = request.files['file']
29+
path = "./frontend/static/client_img/" + (file.filename)
30+
path_ = "./static/client_img/" + (file.filename)
31+
file.save(path)
32+
img = Image.open(path)
33+
img_cropped = mtcnn(img)
2834

29-
emb = resnet(img_cropped.unsqueeze(0))[0].detach().numpy()
30-
faculty_json = open('./model/faculty_emb.json',encoding='utf-8')
31-
faculty_dict = json.load(faculty_json)
32-
min_dist = 100
33-
name = ""
34-
for key in faculty_dict:
35-
print('faculty:',type(faculty_dict[key][0]))
36-
print('emb:',type(emb[0]))
37-
dist = np.linalg.norm(faculty_dict[key]-emb)
38-
if min_dist>dist:
39-
min_dist=dist
40-
name = key
41-
print(name, min_dist)
42-
department = name.split('_')[0]
43-
name_ = name.split('_')[1]
44-
faculty_path = "./static/faculty_img/"+name+".jpg"
45-
46-
end=time.time()
47-
print(f"전체 소요 시간 : {end-start:.5f}")
48-
return render_template('main/main.html', client_img=path_, faculty=faculty_path, department=department, name=name_)
35+
emb = resnet(img_cropped.unsqueeze(0))[0].detach().numpy()
36+
faculty_json = open('./model/dataset_emb.json', encoding='utf-8')
37+
faculty_dict = json.load(faculty_json)
38+
min_dist = 100
39+
name = ""
40+
for key in faculty_dict:
41+
#print('faculty:', type(faculty_dict[key][0]))
42+
#print('emb:', type(emb[0]))
43+
dist = np.linalg.norm(faculty_dict[key] - emb)
44+
print(key, dist)
45+
if min_dist > dist:
46+
min_dist = dist
47+
name = key
48+
#print(name, min_dist)
49+
similarity_ = ((2-min_dist)/2)*100
50+
similarity = round(similarity_,2)
51+
department = name.split('_')[0]
52+
name_ = name.split('_')[1]
53+
faculty_path = "./static/face_dataset/" + name + ".jpg"
54+
return render_template('main/main.html', client_img=path_, faculty=faculty_path, department=department, name=name_,similarity=similarity)
55+
except (RuntimeError, AttributeError):
56+
return render_template('main/error_message.html',error_message="얼굴을 인식하지 못했습니다")
57+
except PIL.UnidentifiedImageError:
58+
return render_template('main/error_message.html', error_message="올바른 형식이 아닙니다")
59+
except PermissionError:
60+
return render_template('main/error_message.html', error_message="입력된 이미지가 없습니다")
61+
except:
62+
exc_type, exc_value, exc_traceback = sys.exc_info()
63+
print(exc_type, exc_value, exc_traceback)
64+
return render_template('main/error_message.html',error_message="알 수 없는 에러")
File renamed without changes.

ref/detect_face.png

491 KB
Loading

ref/error_page.png

8.45 KB
Loading

ref/main_page.png

62.6 KB
Loading

0 commit comments

Comments
 (0)