Spaces:
Runtime error
Runtime error
Lambang
commited on
Commit
•
364ca9d
1
Parent(s):
6caf9b5
up again
Browse files- crud.py +99 -0
- data_preprocess.py +110 -0
- file_processing.py +15 -0
- get_load_data.py +155 -0
- haarcascade_frontalface_alt2.xml +0 -0
- train_pred.py +269 -0
crud.py
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import cv2
|
3 |
+
from flask import Flask, request, jsonify
|
4 |
+
from werkzeug.utils import secure_filename
|
5 |
+
|
6 |
+
#-----------------------------------------------------
|
7 |
+
# Tempat setting server
|
8 |
+
UPLOAD_FOLDER = './upload'
|
9 |
+
UPLOAD_MODEL = './models'
|
10 |
+
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg','zip','h5'}
|
11 |
+
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
12 |
+
app.config['UPLOAD_MODEL'] = UPLOAD_MODEL
|
13 |
+
app.config['MAX_CONTENT_LENGTH'] = 500 * 1024 * 1024 # 500 MB
|
14 |
+
#-----------------------------------------------------
|
15 |
+
|
16 |
+
|
17 |
+
class FaceDetectionApp:
|
18 |
+
def __init__(self, upload_folder="./static", public_url="/"):
|
19 |
+
self.app = Flask(__name__)
|
20 |
+
self.app.config['UPLOAD_FOLDER'] = upload_folder
|
21 |
+
self.app.config['UPLOAD_MODEL'] = os.path.join(upload_folder, "model")
|
22 |
+
self.public_url = public_url
|
23 |
+
|
24 |
+
def delete_img():
|
25 |
+
for i in range (0,4):
|
26 |
+
if os.path.exists(f"./static/result_upload{i}.jpg"):
|
27 |
+
os.remove(f"./static/result_upload{i}.jpg")
|
28 |
+
print("File terhapus")
|
29 |
+
return jsonify({'message': 'Berhasil di hapus'}), 400
|
30 |
+
else:
|
31 |
+
print("File tidak ditemukan.")
|
32 |
+
return jsonify({'message': 'No file selected for uploading'}), 400
|
33 |
+
|
34 |
+
def upload_file():
|
35 |
+
if 'file' not in request.files:
|
36 |
+
return jsonify({'message': 'No file part in the request'}), 400
|
37 |
+
|
38 |
+
file = request.files['file']
|
39 |
+
|
40 |
+
if file.filename == '':
|
41 |
+
return jsonify({'message': 'No file selected for uploading'}), 400
|
42 |
+
|
43 |
+
filename = secure_filename(file.filename)
|
44 |
+
filepath = os.path.join(self.app.config['UPLOAD_FOLDER'], filename)
|
45 |
+
file.save(filepath)
|
46 |
+
img = cv2.imread(filepath)
|
47 |
+
# Detect Face
|
48 |
+
try:
|
49 |
+
self.preprocessing(img)
|
50 |
+
return jsonify({'message': 'File successfully uploaded'})
|
51 |
+
except:
|
52 |
+
path = "empty_image.png"
|
53 |
+
return jsonify({'message': 'File failed to uploaded'})
|
54 |
+
|
55 |
+
def upload_data():
|
56 |
+
if 'file' not in request.files:
|
57 |
+
return jsonify({'message': 'No file part in the request'}), 400
|
58 |
+
|
59 |
+
file = request.files['file']
|
60 |
+
|
61 |
+
if file.filename == '':
|
62 |
+
return jsonify({'message': 'No file selected for uploading'}), 400
|
63 |
+
|
64 |
+
if file and self.allowed_file(file.filename):
|
65 |
+
filename = secure_filename(file.filename)
|
66 |
+
filepath = os.path.join(self.app.config['UPLOAD_FOLDER'], filename)
|
67 |
+
file.save(filepath)
|
68 |
+
|
69 |
+
self.extract_zip(filepath)
|
70 |
+
return jsonify({'message': 'File successfully uploaded'})
|
71 |
+
|
72 |
+
return jsonify({'message': 'File failed to uploaded'})
|
73 |
+
|
74 |
+
|
75 |
+
def upload_model():
|
76 |
+
if 'file' not in request.files:
|
77 |
+
return jsonify({'message': 'No file part in the request'}), 400
|
78 |
+
|
79 |
+
file = request.files['file']
|
80 |
+
|
81 |
+
if file.filename == '':
|
82 |
+
return jsonify({'message': 'No file selected for uploading'}), 400
|
83 |
+
|
84 |
+
if file and self.allowed_file(file.filename):
|
85 |
+
filename = secure_filename(file.filename)
|
86 |
+
filepath = os.path.join(self.app.config['UPLOAD_MODEL'], filename)
|
87 |
+
file.save(filepath)
|
88 |
+
|
89 |
+
return jsonify({'message': 'File successfully uploaded'})
|
90 |
+
|
91 |
+
return jsonify({'message': 'File failed to uploaded'})
|
92 |
+
|
93 |
+
def get_total_files():
|
94 |
+
training_counts = self.get_training_file_counts()
|
95 |
+
testing_counts = self.get_testing_file_counts()
|
96 |
+
result = {}
|
97 |
+
result['training'] = training_counts.json
|
98 |
+
result['testing'] = testing_counts.json
|
99 |
+
return jsonify(result)
|
data_preprocess.py
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import cv2
|
3 |
+
import numpy as np
|
4 |
+
import mediapipe as mp
|
5 |
+
from deepface import DeepFace
|
6 |
+
|
7 |
+
class DataProcessing:
|
8 |
+
def __init__(self):
|
9 |
+
self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_alt2.xml')
|
10 |
+
self.mp_face_mesh = mp.solutions.face_mesh
|
11 |
+
self.mp_drawing = mp.solutions.drawing_utils
|
12 |
+
|
13 |
+
def enhance_contrast_histeq(self, image):
|
14 |
+
img = image.copy()
|
15 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
16 |
+
resized_gray = cv2.resize(gray, (250, 190))
|
17 |
+
enhanced_image = cv2.equalizeHist(resized_gray)
|
18 |
+
|
19 |
+
cv2.imwrite("./static/result_upload2.jpg", enhanced_image)
|
20 |
+
cv2.imwrite("./static/temporary/result_upload2.jpg", enhanced_image)
|
21 |
+
|
22 |
+
return enhanced_image
|
23 |
+
|
24 |
+
def face_cropping_pred(self, img):
|
25 |
+
for i in range(0, 4):
|
26 |
+
if os.path.exists(f"./static/result_upload{i}.jpg"):
|
27 |
+
os.remove(f"./static/result_upload{i}.jpg")
|
28 |
+
print("File terhapus")
|
29 |
+
else:
|
30 |
+
print("File tidak ditemukan.")
|
31 |
+
|
32 |
+
# img = cv2.imread(filepath)
|
33 |
+
cv2.imwrite("./static/result_upload0.jpg", img)
|
34 |
+
cv2.imwrite('./static/temporary/result_upload0.jpg', img)
|
35 |
+
try:
|
36 |
+
DeepFace.extract_faces("./static/result_upload0.jpg")
|
37 |
+
offset = 40
|
38 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
39 |
+
faces = self.face_cascade.detectMultiScale(gray, 1.1, 5)
|
40 |
+
|
41 |
+
for (x, y, w, h) in faces:
|
42 |
+
offset = 80
|
43 |
+
y_offset = 20
|
44 |
+
y1 = max(0, y - offset + y_offset)
|
45 |
+
y2 = min(y + h + offset + y_offset, img.shape[0])
|
46 |
+
x1 = max(0, x - offset)
|
47 |
+
x2 = min(x + w + offset, img.shape[1])
|
48 |
+
|
49 |
+
# Mengambil area sekitar wajah
|
50 |
+
faces = img[y1:y2, x1:x2]
|
51 |
+
|
52 |
+
cv2.imwrite("./static/result_upload1.jpg", faces)
|
53 |
+
cv2.imwrite('./static/temporary/result_upload1.jpg', faces)
|
54 |
+
|
55 |
+
return faces
|
56 |
+
except:
|
57 |
+
print("error")
|
58 |
+
|
59 |
+
def detect_landmark(self, img):
|
60 |
+
print("test")
|
61 |
+
image1 = img.copy()
|
62 |
+
image2 = img.copy()
|
63 |
+
|
64 |
+
with self.mp_face_mesh.FaceMesh(min_detection_confidence=0.1, min_tracking_confidence=0.6) as face_mesh:
|
65 |
+
image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2RGB)
|
66 |
+
image2.flags.writeable = False
|
67 |
+
results = face_mesh.process(image2)
|
68 |
+
image2.flags.writeable = True
|
69 |
+
image2 = cv2.cvtColor(image2, cv2.COLOR_RGB2BGR)
|
70 |
+
|
71 |
+
if results.multi_face_landmarks:
|
72 |
+
for face_landmarks in results.multi_face_landmarks:
|
73 |
+
self.mp_drawing.draw_landmarks(
|
74 |
+
image=image2,
|
75 |
+
landmark_list=face_landmarks,
|
76 |
+
connections=self.mp_face_mesh.FACEMESH_TESSELATION,
|
77 |
+
landmark_drawing_spec=self.mp_drawing.DrawingSpec(color=(0, 0, 0), thickness=0, circle_radius=0),
|
78 |
+
connection_drawing_spec=self.mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=1, circle_radius=0))
|
79 |
+
|
80 |
+
cv2.imwrite('./static/result_upload2.jpg', image2)
|
81 |
+
cv2.imwrite('./static/temporary/result_upload2.jpg', image2)
|
82 |
+
|
83 |
+
subtracted_img = np.zeros(image1.shape, np.uint8)
|
84 |
+
|
85 |
+
for i in range(image1.shape[0]):
|
86 |
+
for j in range(image1.shape[1]):
|
87 |
+
subtracted_img[i, j] = abs(int(image1[i, j][0]) - int(image2[i, j][0]))
|
88 |
+
|
89 |
+
cv2.imwrite('./static/result_upload3.jpg', subtracted_img)
|
90 |
+
cv2.imwrite('./static/temporary/result_upload3.jpg', subtracted_img)
|
91 |
+
|
92 |
+
def annotate_face_mesh(self, image):
|
93 |
+
with self.mp_face_mesh.FaceMesh(min_detection_confidence=0.1, min_tracking_confidence=0.6) as face_mesh:
|
94 |
+
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
95 |
+
image.flags.writeable = False
|
96 |
+
results = face_mesh.process(image)
|
97 |
+
image.flags.writeable = True
|
98 |
+
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
99 |
+
|
100 |
+
if results.multi_face_landmarks:
|
101 |
+
for face_landmarks in results.multi_face_landmarks:
|
102 |
+
self.mp_drawing.draw_landmarks(
|
103 |
+
image=image,
|
104 |
+
landmark_list=face_landmarks,
|
105 |
+
connections=self.mp_face_mesh.FACEMESH_TESSELATION,
|
106 |
+
landmark_drawing_spec=self.mp_drawing.DrawingSpec(color=(0, 0, 0), thickness=0, circle_radius=0),
|
107 |
+
connection_drawing_spec=self.mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=1, circle_radius=0))
|
108 |
+
return image
|
109 |
+
|
110 |
+
|
file_processing.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import zipfile
|
2 |
+
|
3 |
+
class FileProcess:
|
4 |
+
ALLOWED_EXTENSIONS = {'zip'}
|
5 |
+
|
6 |
+
@staticmethod
|
7 |
+
def allowed_file(filename):
|
8 |
+
return '.' in filename and \
|
9 |
+
filename.rsplit('.', 1)[1].lower() in FileProcess.ALLOWED_EXTENSIONS
|
10 |
+
|
11 |
+
@staticmethod
|
12 |
+
def extract_zip(filepath):
|
13 |
+
path_ke_folder = './static/dataset/'
|
14 |
+
with zipfile.ZipFile(filepath, 'r') as zip_ref:
|
15 |
+
zip_ref.extractall(path_ke_folder)
|
get_load_data.py
ADDED
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import random
|
3 |
+
import pandas as pd
|
4 |
+
from pathlib import Path
|
5 |
+
from flask import jsonify
|
6 |
+
|
7 |
+
list_class = ['Diamond','Oblong','Oval','Round','Square','Triangle']
|
8 |
+
|
9 |
+
# public_url = "https://yamanaka1.pagekite.me"
|
10 |
+
|
11 |
+
class GetLoadData:
|
12 |
+
@staticmethod
|
13 |
+
def get_training_file_counts():
|
14 |
+
path = "./static/dataset/Face Shape"
|
15 |
+
training_file_counts = []
|
16 |
+
|
17 |
+
# Loop melalui folder Training
|
18 |
+
for sub_folder in ["Diamond", "Oblong", "Oval", "Round", "Square", "Triangle"]:
|
19 |
+
# Tentukan path ke folder sub_folder dalam folder Training
|
20 |
+
sub_path = os.path.join(path, "Training", sub_folder)
|
21 |
+
|
22 |
+
# Gunakan fungsi listdir untuk membaca semua file dalam folder sub_folder
|
23 |
+
num_files = len([f for f in os.listdir(sub_path) if os.path.isfile(os.path.join(sub_path, f))])
|
24 |
+
|
25 |
+
# Tambahkan jumlah file ke dalam array training_file_counts
|
26 |
+
training_file_counts.append(num_files)
|
27 |
+
|
28 |
+
total_file = sum(training_file_counts)
|
29 |
+
training_file_counts.append(total_file)
|
30 |
+
|
31 |
+
# Return hasil dalam bentuk JSON
|
32 |
+
return jsonify(training_file_counts)
|
33 |
+
|
34 |
+
@staticmethod
|
35 |
+
def get_testing_file_counts():
|
36 |
+
path = "./static/dataset/Face Shape"
|
37 |
+
testing_file_counts = []
|
38 |
+
|
39 |
+
# Loop melalui folder Testing
|
40 |
+
for sub_folder in ["Diamond", "Oblong", "Oval", "Round", "Square", "Triangle"]:
|
41 |
+
# Tentukan path ke folder sub_folder dalam folder Testing
|
42 |
+
sub_path = os.path.join(path, "Testing", sub_folder)
|
43 |
+
|
44 |
+
# Gunakan fungsi listdir untuk membaca semua file dalam folder sub_folder
|
45 |
+
num_files = len([f for f in os.listdir(sub_path) if os.path.isfile(os.path.join(sub_path, f))])
|
46 |
+
|
47 |
+
# Tambahkan jumlah file ke dalam array testing_file_counts
|
48 |
+
testing_file_counts.append(num_files)
|
49 |
+
|
50 |
+
total_file = sum(testing_file_counts)
|
51 |
+
testing_file_counts.append(total_file)
|
52 |
+
|
53 |
+
# Return hasil dalam bentuk JSON
|
54 |
+
return jsonify(testing_file_counts)
|
55 |
+
|
56 |
+
@staticmethod
|
57 |
+
def folder_maker(preprocessing_name):
|
58 |
+
folder_path = f'./static/dataset/{preprocessing_name}'
|
59 |
+
training_path = f'./static/dataset/{preprocessing_name}/Training'
|
60 |
+
testing_path = f'./static/dataset/{preprocessing_name}/Testing'
|
61 |
+
|
62 |
+
# Membuat folder dataset/Landmark Face Shape jika belum ada
|
63 |
+
if not os.path.exists(folder_path):
|
64 |
+
os.makedirs(folder_path)
|
65 |
+
|
66 |
+
# Membuat folder dataset/Landmark Face Shape/Training jika belum ada
|
67 |
+
if not os.path.exists(training_path):
|
68 |
+
os.makedirs(training_path)
|
69 |
+
for i in range(0, len(list_class)):
|
70 |
+
os.mkdir(f'{training_path}/{list_class[i]}')
|
71 |
+
|
72 |
+
# Membuat folder dataset/Landmark Face Shape/Testing jika belum ada
|
73 |
+
if not os.path.exists(testing_path):
|
74 |
+
os.makedirs(testing_path)
|
75 |
+
for i in range(0, len(list_class)):
|
76 |
+
os.mkdir(f'{testing_path}/{list_class[i]}')
|
77 |
+
|
78 |
+
@staticmethod
|
79 |
+
def load_image_data(image_dir):
|
80 |
+
# Get file paths for all images in the directory
|
81 |
+
jpeg = list(image_dir.glob(r'**/*.jpeg'))
|
82 |
+
JPG = list(image_dir.glob(r'**/*.JPG'))
|
83 |
+
jpg = list(image_dir.glob(r'**/*.jpg'))
|
84 |
+
PNG = list(image_dir.glob(r'**/*.PNG'))
|
85 |
+
png = list(image_dir.glob(r'**/*.png'))
|
86 |
+
filepaths_ori = jpeg + JPG + jpg + PNG + png
|
87 |
+
|
88 |
+
# Get labels for each image
|
89 |
+
labels = list(map(lambda x: os.path.split(os.path.split(x)[0])[1], filepaths_ori))
|
90 |
+
|
91 |
+
# Convert filepaths and labels to Pandas series
|
92 |
+
filepaths_ori = pd.Series(filepaths_ori, name='Filepath').astype(str)
|
93 |
+
labels = pd.Series(labels, name='Label')
|
94 |
+
|
95 |
+
return filepaths_ori, labels
|
96 |
+
|
97 |
+
@staticmethod
|
98 |
+
def get_random_images(tahap, public_url):
|
99 |
+
root_path = f'./static/dataset/{tahap}/Training/'
|
100 |
+
num_images = 1
|
101 |
+
random_images = []
|
102 |
+
folder_count = 1
|
103 |
+
|
104 |
+
# Iterasi melalui folder di dalam folder "training"
|
105 |
+
for folder_name in os.listdir(root_path):
|
106 |
+
folder_path = os.path.join(root_path, folder_name)
|
107 |
+
|
108 |
+
print(folder_path)
|
109 |
+
|
110 |
+
# Jika folder_name bukan folder, skip
|
111 |
+
if not os.path.isdir(folder_path):
|
112 |
+
continue
|
113 |
+
|
114 |
+
# Mengambil daftar file di dalam folder dan mengacaknya
|
115 |
+
file_names = os.listdir(folder_path)
|
116 |
+
random.shuffle(file_names)
|
117 |
+
|
118 |
+
# Memilih 1 file pertama setelah diacak
|
119 |
+
for i in range(len(file_names)):
|
120 |
+
if i < num_images:
|
121 |
+
url = f'{public_url}/static/dataset/{tahap}/Training/{folder_name}'
|
122 |
+
print(url)
|
123 |
+
random_images.append(os.path.join(url, file_names[i]))
|
124 |
+
print(random_images)
|
125 |
+
|
126 |
+
# Hentikan loop setelah mengambil 5 gambar dari folder ke-5
|
127 |
+
if folder_count == 5:
|
128 |
+
break
|
129 |
+
|
130 |
+
folder_count += 1
|
131 |
+
|
132 |
+
# Mengirimkan daftar file acak sebagai respons ke Flutter
|
133 |
+
print(random_images)
|
134 |
+
return random_images
|
135 |
+
|
136 |
+
@staticmethod
|
137 |
+
def load_image_dataset(train_dataset_path, test_dataset_path):
|
138 |
+
list_data_path = [train_dataset_path, test_dataset_path]
|
139 |
+
|
140 |
+
# Get filepaths and labels
|
141 |
+
image_dir_train = Path(list_data_path[0])
|
142 |
+
filepaths_train, labels_train = GetLoadData.load_image_data(image_dir_train)
|
143 |
+
|
144 |
+
# Concatenate filepaths and labels
|
145 |
+
train_image_df = pd.concat([filepaths_train, labels_train], axis=1)
|
146 |
+
|
147 |
+
# Get filepaths and labels
|
148 |
+
image_dir_test = Path(list_data_path[1])
|
149 |
+
filepaths_test, labels_test = GetLoadData.load_image_data(image_dir_test)
|
150 |
+
|
151 |
+
# Concatenate filepaths and labels
|
152 |
+
test_image_df = pd.concat([filepaths_test, labels_test], axis=1)
|
153 |
+
|
154 |
+
# Return filepaths and labels
|
155 |
+
return train_image_df, test_image_df
|
haarcascade_frontalface_alt2.xml
ADDED
The diff for this file is too large to render.
See raw diff
|
|
train_pred.py
ADDED
@@ -0,0 +1,269 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import matplotlib
|
2 |
+
matplotlib.use('Agg')
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
import tensorflow as tf
|
5 |
+
from tensorflow.keras.preprocessing.image import load_img, img_to_array
|
6 |
+
from sklearn.metrics import confusion_matrix
|
7 |
+
import os
|
8 |
+
import cv2
|
9 |
+
import numpy as np
|
10 |
+
from tqdm import tqdm
|
11 |
+
from flask import jsonify, flash, redirect, url_for
|
12 |
+
from pathlib import Path
|
13 |
+
|
14 |
+
from get_load_data import GetLoadData
|
15 |
+
from data_preprocess import DataProcessing
|
16 |
+
|
17 |
+
|
18 |
+
list_folder = ['Training', 'Testing']
|
19 |
+
|
20 |
+
class TrainPred:
|
21 |
+
|
22 |
+
def __init__(self, batch_size=32):
|
23 |
+
self.batch_size = batch_size
|
24 |
+
self.list_class = ['Diamond', 'Oblong', 'Oval', 'Round', 'Square', 'Triangle']
|
25 |
+
self.face_crop_img = True
|
26 |
+
self.face_landmark_img = True
|
27 |
+
self.landmark_extraction_img = True
|
28 |
+
|
29 |
+
self.prepro_img = 0
|
30 |
+
self.prepro_img2 = 0
|
31 |
+
self.name = ""
|
32 |
+
self.progres = 0
|
33 |
+
|
34 |
+
self.data_processor = DataProcessing()
|
35 |
+
|
36 |
+
def train_model(self, model, train_generator, test_generator, epoch):
|
37 |
+
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
|
38 |
+
history = model.fit(train_generator, epochs=epoch, validation_data=test_generator)
|
39 |
+
return history
|
40 |
+
|
41 |
+
def prediction(self, model):
|
42 |
+
# img_width, img_height = 200, 200
|
43 |
+
# img = load_img("./static/result_upload2.jpg", target_size=(img_width, img_height))
|
44 |
+
img = load_img("./static/result_upload2.jpg")
|
45 |
+
|
46 |
+
img = img_to_array(img)
|
47 |
+
img = img/255.0
|
48 |
+
img = np.expand_dims(img, axis=0)
|
49 |
+
pred = model.predict(img)
|
50 |
+
pred_2 = model.predict_on_batch(img)
|
51 |
+
print(f"Pred :{pred}")
|
52 |
+
print(f"Pred 2 : {pred_2}")
|
53 |
+
|
54 |
+
# menghitung softmax
|
55 |
+
softmax_pred = np.exp(pred) / np.sum(np.exp(pred), axis=1, keepdims=True)
|
56 |
+
|
57 |
+
max_value = int(round(np.max(softmax_pred * 100)))
|
58 |
+
pred = np.argmax(pred, axis=1)
|
59 |
+
|
60 |
+
# Map the label
|
61 |
+
pred = [self.list_class[k] for k in pred]
|
62 |
+
|
63 |
+
return pred, max_value
|
64 |
+
|
65 |
+
def plot_accuracy(self, result, epoch):
|
66 |
+
train_acc_gr = result.history['accuracy']
|
67 |
+
val_acc_gr = result.history['val_accuracy']
|
68 |
+
epochs = range(1, epoch+1)
|
69 |
+
|
70 |
+
# Plot training accuracy
|
71 |
+
plt.plot(epochs, train_acc_gr, label='Training Accuracy')
|
72 |
+
plt.plot(epochs, val_acc_gr, label='Testing Accuracy')
|
73 |
+
|
74 |
+
# Set plot title and labels
|
75 |
+
plt.title('Model Accuracy')
|
76 |
+
plt.xlabel('Epoch')
|
77 |
+
plt.ylabel('Accuracy')
|
78 |
+
plt.legend(loc='best')
|
79 |
+
|
80 |
+
# Save plot as image file
|
81 |
+
plt.savefig('./static/accuracy_plot.png')
|
82 |
+
|
83 |
+
def plot_loss(self, result, epoch):
|
84 |
+
train_loss_gr = result.history['loss']
|
85 |
+
val_loss_gr = result.history['val_loss']
|
86 |
+
epochs = range(1, epoch+1)
|
87 |
+
|
88 |
+
# Plot training accuracy
|
89 |
+
plt.plot(epochs, train_loss_gr, label='Training Loss')
|
90 |
+
plt.plot(epochs, val_loss_gr, label='Testing Loss')
|
91 |
+
|
92 |
+
# Set plot title and labels
|
93 |
+
plt.title('Model Loss')
|
94 |
+
plt.xlabel('Epoch')
|
95 |
+
plt.ylabel('Loss')
|
96 |
+
plt.legend(loc='best')
|
97 |
+
|
98 |
+
# Save plot as image file
|
99 |
+
plt.savefig('./static/loss_plot.png')
|
100 |
+
|
101 |
+
def plot_confusion_matrix(self, model, test_generator):
|
102 |
+
# Get the predictions from the model
|
103 |
+
predictions = model.predict(test_generator, steps=len(test_generator), verbose=1)
|
104 |
+
y_pred = np.argmax(predictions, axis=1)
|
105 |
+
y_true = test_generator.classes
|
106 |
+
|
107 |
+
# Generate confusion matrix
|
108 |
+
cm = confusion_matrix(y_true, y_pred)
|
109 |
+
|
110 |
+
# Plot the confusion matrix
|
111 |
+
fig, ax = plt.subplots(figsize=(8, 8))
|
112 |
+
ax.imshow(cm, cmap='Blues')
|
113 |
+
ax.set_title('Confusion Matrix')
|
114 |
+
ax.set_xlabel('Predicted Labels')
|
115 |
+
ax.set_ylabel('True Labels')
|
116 |
+
ax.set_xticks(range(len(test_generator.class_indices)))
|
117 |
+
ax.set_xticklabels(test_generator.class_indices.keys(), rotation=90)
|
118 |
+
ax.set_yticks(range(len(test_generator.class_indices)))
|
119 |
+
ax.set_yticklabels(test_generator.class_indices.keys())
|
120 |
+
for i in range(len(test_generator.class_indices)):
|
121 |
+
for j in range(len(test_generator.class_indices)):
|
122 |
+
ax.text(j, i, str(cm[i, j]), ha='center', va='center', color='white')
|
123 |
+
fig.tight_layout()
|
124 |
+
|
125 |
+
filename = './static/confusion_matrix.png'
|
126 |
+
# Save the confusion matrix as an image file
|
127 |
+
fig.savefig(filename)
|
128 |
+
|
129 |
+
return filename
|
130 |
+
|
131 |
+
def data_configuration(self, train_image_df, test_image_df):
|
132 |
+
train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
|
133 |
+
test_datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
|
134 |
+
|
135 |
+
train_generator = train_datagen.flow_from_dataframe(
|
136 |
+
dataframe=train_image_df,
|
137 |
+
x_col='Filepath',
|
138 |
+
y_col='Label',
|
139 |
+
target_size=(220, 280),
|
140 |
+
color_mode='rgb',
|
141 |
+
class_mode='categorical',
|
142 |
+
batch_size=self.batch_size,
|
143 |
+
subset='training'
|
144 |
+
)
|
145 |
+
|
146 |
+
test_generator = test_datagen.flow_from_dataframe(
|
147 |
+
dataframe=test_image_df,
|
148 |
+
x_col='Filepath',
|
149 |
+
y_col='Label',
|
150 |
+
target_size=(220, 280),
|
151 |
+
color_mode='rgb',
|
152 |
+
class_mode='categorical',
|
153 |
+
batch_size=self.batch_size,
|
154 |
+
subset='training'
|
155 |
+
)
|
156 |
+
|
157 |
+
return train_generator, test_generator
|
158 |
+
|
159 |
+
def model_architecture(self):
|
160 |
+
model = tf.keras.models.Sequential()
|
161 |
+
|
162 |
+
# layers from the previous code
|
163 |
+
model.add(tf.keras.layers.Conv2D(64, (3, 3), activation='relu', input_shape=(220, 280, 3)))
|
164 |
+
model.add(tf.keras.layers.Conv2D(64, (3, 3), activation='relu'))
|
165 |
+
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
|
166 |
+
model.add(tf.keras.layers.Conv2D(128, (3, 3), activation='relu'))
|
167 |
+
model.add(tf.keras.layers.Conv2D(128, (3, 3), activation='relu'))
|
168 |
+
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
|
169 |
+
model.add(tf.keras.layers.Conv2D(256, (3, 3), activation='relu'))
|
170 |
+
model.add(tf.keras.layers.Conv2D(256, (3, 3), activation='relu'))
|
171 |
+
model.add(tf.keras.layers.MaxPooling2D((2, 2)))
|
172 |
+
|
173 |
+
model.add(tf.keras.layers.Flatten())
|
174 |
+
model.add(tf.keras.layers.Dense(6, activation='softmax'))
|
175 |
+
|
176 |
+
model.summary()
|
177 |
+
|
178 |
+
return model
|
179 |
+
|
180 |
+
# @staticmethod
|
181 |
+
def do_pre1(self,test):
|
182 |
+
global prepro_img
|
183 |
+
global face_landmark_img, landmark_extraction_img
|
184 |
+
self.prepro_img = 0
|
185 |
+
try:
|
186 |
+
if (self.face_landmark_img == True):
|
187 |
+
GetLoadData.folder_maker("Face Landmark")
|
188 |
+
|
189 |
+
for i in tqdm(range(0, len(list_folder)), desc=f"Processing {list_folder} images"):
|
190 |
+
for j in range(0, len(self.list_class)):
|
191 |
+
dataset = f"./static/dataset/Face Shape/{list_folder[i]}/{self.list_class[j]}"
|
192 |
+
len_dataset = os.listdir(f"./static/dataset/Face Shape/{list_folder[i]}/{self.list_class[j]}")
|
193 |
+
image_dir = Path(dataset)
|
194 |
+
for k in (range(0, len(len_dataset))):
|
195 |
+
filepaths, labels = GetLoadData.load_image_data(image_dir)
|
196 |
+
img = cv2.imread(filepaths[k])
|
197 |
+
img = self.data_processor.annotate_face_mesh(image=img)
|
198 |
+
# print("./static/dataset/Face Landmark/" + f"{list_folder[i]}/" + f"{list_class[j]}/" + f"{len_dataset[k]}")
|
199 |
+
cv2.imwrite(
|
200 |
+
"./static/dataset/Face Landmark/" + f"{list_folder[i]}/" + f"{self.list_class[j]}/" + f"{len_dataset[k]}",
|
201 |
+
img)
|
202 |
+
self.prepro_img += 1
|
203 |
+
|
204 |
+
return jsonify({'message': 'Preprocessing 1 sukses'}), 200
|
205 |
+
|
206 |
+
except Exception as e:
|
207 |
+
flash('Terjadi error: {}'.format(str(e)))
|
208 |
+
|
209 |
+
return redirect(url_for('index'))
|
210 |
+
|
211 |
+
def do_pre2(self,test):
|
212 |
+
global prepro_img2
|
213 |
+
global face_landmark_img, landmark_extraction_img
|
214 |
+
self.prepro_img2 = 0
|
215 |
+
try:
|
216 |
+
if (self.landmark_extraction_img == True):
|
217 |
+
GetLoadData.folder_maker("Landmark Extraction")
|
218 |
+
for i2 in tqdm(range(0, len(list_folder)), desc=f"Processing {list_folder} images"):
|
219 |
+
for j2 in range(0, len(self.list_class)):
|
220 |
+
new_dataset = f"./static/dataset/Face Landmark/{list_folder[i2]}/{self.list_class[j2]}"
|
221 |
+
len_new_dataset = os.listdir(
|
222 |
+
f"./static/dataset/Face Landmark/{list_folder[i2]}/{self.list_class[j2]}")
|
223 |
+
|
224 |
+
image_dir = Path(new_dataset)
|
225 |
+
for k in (range(0, len(len_new_dataset))):
|
226 |
+
filepaths, labels = GetLoadData.load_image_data(image_dir)
|
227 |
+
img = cv2.imread(filepaths[k])
|
228 |
+
|
229 |
+
subtracted_img = np.zeros(img.shape, np.uint8)
|
230 |
+
|
231 |
+
# ----------------------------------------------------------------------
|
232 |
+
img1 = cv2.imread(
|
233 |
+
f'./static/dataset/Face Landmark/{list_folder[i2]}/{self.list_class[j2]}/{len_new_dataset[k]}')
|
234 |
+
img2 = cv2.imread(
|
235 |
+
f'./static/dataset/Face Shape/{list_folder[i2]}/{self.list_class[j2]}/{len_new_dataset[k]}')
|
236 |
+
|
237 |
+
# Lakukan perhitungan pengurangan pixel secara manual
|
238 |
+
for l in range(img1.shape[0]):
|
239 |
+
for m in range(img1.shape[1]):
|
240 |
+
subtracted_img[l, m] = abs(int(img1[l, m][0]) - int(img2[l, m][0]))
|
241 |
+
|
242 |
+
# ----------------------------------------------------------------------
|
243 |
+
cv2.imwrite(
|
244 |
+
"./static/dataset/Landmark Extraction/" + f"{list_folder[i2]}/" + f"{self.list_class[j2]}/" + f"{len_new_dataset[k]}",
|
245 |
+
subtracted_img)
|
246 |
+
self.prepro_img2 += 1
|
247 |
+
|
248 |
+
# requests.get(url_for('get_progress_1', _external=True), params={'progress': prepro_img2})
|
249 |
+
|
250 |
+
# prepro_img = 0
|
251 |
+
# code preprocessing
|
252 |
+
return jsonify({'message': 'Preprocessing sukses'}), 200
|
253 |
+
except Exception as e:
|
254 |
+
flash('Terjadi error: {}'.format(str(e)))
|
255 |
+
return redirect(url_for('index'))
|
256 |
+
|
257 |
+
def get_progress_1(self):
|
258 |
+
|
259 |
+
if self.prepro_img > 0:
|
260 |
+
self.name = "Face Landmark"
|
261 |
+
self.progres = self.prepro_img
|
262 |
+
print(self.progres)
|
263 |
+
|
264 |
+
if self.prepro_img2 > 0:
|
265 |
+
self.name = "Landmark Extraction"
|
266 |
+
self.progres = self.prepro_img2
|
267 |
+
print(self.progres)
|
268 |
+
|
269 |
+
return self.progres, self.name
|