bram4627 commited on
Commit
17e462b
·
verified ·
1 Parent(s): d7c88b9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +199 -220
app.py CHANGED
@@ -1,220 +1,199 @@
1
- from flask import Flask, render_template, request, Response, jsonify, redirect, url_for
2
- import cv2
3
- import os
4
- import numpy as np
5
- import pickle
6
- import base64
7
- from datetime import datetime
8
-
9
- app = Flask(__name__)
10
-
11
- # Konfigurasi
12
- FACE_DATA_DIR = 'face_data'
13
- FACE_CASCADE_PATH = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
14
-
15
- # Pastikan direktori face_data ada
16
- if not os.path.exists(FACE_DATA_DIR):
17
- os.makedirs(FACE_DATA_DIR)
18
-
19
- # Load face cascade
20
- face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH)
21
-
22
- # Global variables
23
- camera = None
24
- face_recognizer = cv2.face.LBPHFaceRecognizer_create()
25
- is_trained = False
26
-
27
- def load_face_data():
28
- """Load data wajah yang sudah disimpan"""
29
- global is_trained
30
- faces = []
31
- labels = []
32
- names = []
33
-
34
- if os.path.exists(os.path.join(FACE_DATA_DIR, 'names.pkl')):
35
- with open(os.path.join(FACE_DATA_DIR, 'names.pkl'), 'rb') as f:
36
- names = pickle.load(f)
37
-
38
- for idx, name in enumerate(names):
39
- face_dir = os.path.join(FACE_DATA_DIR, name)
40
- if os.path.exists(face_dir):
41
- for filename in os.listdir(face_dir):
42
- if filename.endswith('.jpg'):
43
- img_path = os.path.join(face_dir, filename)
44
- img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
45
- faces.append(img)
46
- labels.append(idx)
47
-
48
- if faces:
49
- face_recognizer.train(faces, np.array(labels))
50
- is_trained = True
51
- return names
52
-
53
- return []
54
-
55
- def get_camera():
56
- """Inisialisasi kamera"""
57
- global camera
58
- if camera is None:
59
- camera = cv2.VideoCapture(0)
60
- return camera
61
-
62
- @app.route('/')
63
- def index():
64
- """Halaman utama"""
65
- names = load_face_data()
66
- return render_template('index.html', registered_faces=names)
67
-
68
- @app.route('/register')
69
- def register():
70
- """Halaman registrasi wajah baru"""
71
- return render_template('register.html')
72
-
73
- @app.route('/recognize')
74
- def recognize():
75
- """Halaman pengenalan wajah"""
76
- return render_template('recognize.html')
77
-
78
- @app.route('/video_feed')
79
- def video_feed():
80
- """Stream video untuk registrasi"""
81
- def generate():
82
- camera = get_camera()
83
- while True:
84
- success, frame = camera.read()
85
- if not success:
86
- break
87
-
88
- # Convert frame ke format yang bisa dikirim
89
- ret, buffer = cv2.imencode('.jpg', frame)
90
- frame = buffer.tobytes()
91
- yield (b'--frame\r\n'
92
- b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
93
-
94
- return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
95
-
96
- @app.route('/recognition_feed')
97
- def recognition_feed():
98
- """Stream video untuk pengenalan wajah"""
99
- def generate():
100
- camera = get_camera()
101
- names = load_face_data()
102
-
103
- while True:
104
- success, frame = camera.read()
105
- if not success:
106
- break
107
-
108
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
109
- faces = face_cascade.detectMultiScale(gray, 1.3, 5)
110
-
111
- for (x, y, w, h) in faces:
112
- cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
113
-
114
- if is_trained and names:
115
- roi_gray = gray[y:y+h, x:x+w]
116
- roi_gray = cv2.resize(roi_gray, (100, 100))
117
-
118
- id_, confidence = face_recognizer.predict(roi_gray)
119
-
120
- if confidence < 100: # Threshold untuk confidence
121
- name = names[id_]
122
- confidence_text = f"{name} ({round(100-confidence)}%)"
123
- else:
124
- confidence_text = "Unknown"
125
-
126
- cv2.putText(frame, confidence_text, (x, y-10),
127
- cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
128
-
129
- ret, buffer = cv2.imencode('.jpg', frame)
130
- frame = buffer.tobytes()
131
- yield (b'--frame\r\n'
132
- b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
133
-
134
- return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
135
-
136
- @app.route('/capture_face', methods=['POST'])
137
- def capture_face():
138
- """Capture wajah untuk registrasi"""
139
- name = request.json.get('name', '').strip()
140
-
141
- if not name:
142
- return jsonify({'error': 'Nama tidak boleh kosong'})
143
-
144
- camera = get_camera()
145
- success, frame = camera.read()
146
-
147
- if not success:
148
- return jsonify({'error': 'Gagal mengambil gambar dari kamera'})
149
-
150
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
151
- faces = face_cascade.detectMultiScale(gray, 1.3, 5)
152
-
153
- if len(faces) == 0:
154
- return jsonify({'error': 'Tidak ada wajah yang terdeteksi'})
155
-
156
- if len(faces) > 1:
157
- return jsonify({'error': 'Terdeteksi lebih dari satu wajah'})
158
-
159
- # Ambil wajah pertama
160
- (x, y, w, h) = faces[0]
161
- face_roi = gray[y:y+h, x:x+w]
162
- face_roi = cv2.resize(face_roi, (100, 100))
163
-
164
- # Buat direktori untuk nama ini
165
- person_dir = os.path.join(FACE_DATA_DIR, name)
166
- if not os.path.exists(person_dir):
167
- os.makedirs(person_dir)
168
-
169
- # Simpan gambar wajah
170
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
171
- filename = f"{timestamp}.jpg"
172
- cv2.imwrite(os.path.join(person_dir, filename), face_roi)
173
-
174
- # Update daftar nama
175
- names_file = os.path.join(FACE_DATA_DIR, 'names.pkl')
176
- if os.path.exists(names_file):
177
- with open(names_file, 'rb') as f:
178
- names = pickle.load(f)
179
- else:
180
- names = []
181
-
182
- if name not in names:
183
- names.append(name)
184
- with open(names_file, 'wb') as f:
185
- pickle.dump(names, f)
186
-
187
- # Retrain model
188
- load_face_data()
189
-
190
- return jsonify({'success': f'Wajah {name} berhasil didaftarkan'})
191
-
192
- @app.route('/delete_face/<name>')
193
- def delete_face(name):
194
- """Hapus data wajah"""
195
- person_dir = os.path.join(FACE_DATA_DIR, name)
196
-
197
- if os.path.exists(person_dir):
198
- # Hapus semua file di direktori
199
- for filename in os.listdir(person_dir):
200
- os.remove(os.path.join(person_dir, filename))
201
- os.rmdir(person_dir)
202
-
203
- # Update daftar nama
204
- names_file = os.path.join(FACE_DATA_DIR, 'names.pkl')
205
- if os.path.exists(names_file):
206
- with open(names_file, 'rb') as f:
207
- names = pickle.load(f)
208
-
209
- if name in names:
210
- names.remove(name)
211
- with open(names_file, 'wb') as f:
212
- pickle.dump(names, f)
213
-
214
- # Retrain model
215
- load_face_data()
216
-
217
- return redirect(url_for('index'))
218
-
219
- if __name__ == '__main__':
220
- app.run(debug=True, host='0.0.0.0', port=5000)
 
1
+ from flask import Flask, render_template, request, Response, jsonify, redirect, url_for
2
+ import cv2
3
+ import os
4
+ import numpy as np
5
+ import pickle
6
+ from datetime import datetime
7
+
8
+ # ==== Bagian Flask (kode kamu tetap) ====
9
+ flask_app = Flask(__name__)
10
+
11
+ FACE_DATA_DIR = 'face_data'
12
+ FACE_CASCADE_PATH = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
13
+
14
+ if not os.path.exists(FACE_DATA_DIR):
15
+ os.makedirs(FACE_DATA_DIR)
16
+
17
+ face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH)
18
+ camera = None
19
+ face_recognizer = cv2.face.LBPHFaceRecognizer_create()
20
+ is_trained = False
21
+
22
+ def load_face_data():
23
+ global is_trained
24
+ faces = []
25
+ labels = []
26
+ names = []
27
+
28
+ if os.path.exists(os.path.join(FACE_DATA_DIR, 'names.pkl')):
29
+ with open(os.path.join(FACE_DATA_DIR, 'names.pkl'), 'rb') as f:
30
+ names = pickle.load(f)
31
+
32
+ for idx, name in enumerate(names):
33
+ face_dir = os.path.join(FACE_DATA_DIR, name)
34
+ if os.path.exists(face_dir):
35
+ for filename in os.listdir(face_dir):
36
+ if filename.endswith('.jpg'):
37
+ img_path = os.path.join(face_dir, filename)
38
+ img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
39
+ faces.append(img)
40
+ labels.append(idx)
41
+
42
+ if faces:
43
+ face_recognizer.train(faces, np.array(labels))
44
+ is_trained = True
45
+ return names
46
+ return []
47
+
48
+ def get_camera():
49
+ global camera
50
+ if camera is None:
51
+ camera = cv2.VideoCapture(0)
52
+ return camera
53
+
54
+ @flask_app.route('/')
55
+ def index():
56
+ names = load_face_data()
57
+ return render_template('index.html', registered_faces=names)
58
+
59
+ @flask_app.route('/register')
60
+ def register():
61
+ return render_template('register.html')
62
+
63
+ @flask_app.route('/recognize')
64
+ def recognize():
65
+ return render_template('recognize.html')
66
+
67
+ @flask_app.route('/video_feed')
68
+ def video_feed():
69
+ def generate():
70
+ camera = get_camera()
71
+ while True:
72
+ success, frame = camera.read()
73
+ if not success:
74
+ break
75
+ ret, buffer = cv2.imencode('.jpg', frame)
76
+ frame = buffer.tobytes()
77
+ yield (b'--frame\r\n'
78
+ b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
79
+ return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
80
+
81
+ @flask_app.route('/recognition_feed')
82
+ def recognition_feed():
83
+ def generate():
84
+ camera = get_camera()
85
+ names = load_face_data()
86
+
87
+ while True:
88
+ success, frame = camera.read()
89
+ if not success:
90
+ break
91
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
92
+ faces = face_cascade.detectMultiScale(gray, 1.3, 5)
93
+
94
+ for (x, y, w, h) in faces:
95
+ cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
96
+
97
+ if is_trained and names:
98
+ roi_gray = gray[y:y+h, x:x+w]
99
+ roi_gray = cv2.resize(roi_gray, (100, 100))
100
+ id_, confidence = face_recognizer.predict(roi_gray)
101
+
102
+ if confidence < 100:
103
+ name = names[id_]
104
+ confidence_text = f"{name} ({round(100-confidence)}%)"
105
+ else:
106
+ confidence_text = "Unknown"
107
+
108
+ cv2.putText(frame, confidence_text, (x, y-10),
109
+ cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
110
+
111
+ ret, buffer = cv2.imencode('.jpg', frame)
112
+ frame = buffer.tobytes()
113
+ yield (b'--frame\r\n'
114
+ b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
115
+ return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
116
+
117
+ @flask_app.route('/capture_face', methods=['POST'])
118
+ def capture_face():
119
+ name = request.json.get('name', '').strip()
120
+ if not name:
121
+ return jsonify({'error': 'Nama tidak boleh kosong'})
122
+
123
+ camera = get_camera()
124
+ success, frame = camera.read()
125
+ if not success:
126
+ return jsonify({'error': 'Gagal mengambil gambar dari kamera'})
127
+
128
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
129
+ faces = face_cascade.detectMultiScale(gray, 1.3, 5)
130
+
131
+ if len(faces) == 0:
132
+ return jsonify({'error': 'Tidak ada wajah yang terdeteksi'})
133
+ if len(faces) > 1:
134
+ return jsonify({'error': 'Terdeteksi lebih dari satu wajah'})
135
+
136
+ (x, y, w, h) = faces[0]
137
+ face_roi = gray[y:y+h, x:x+w]
138
+ face_roi = cv2.resize(face_roi, (100, 100))
139
+
140
+ person_dir = os.path.join(FACE_DATA_DIR, name)
141
+ if not os.path.exists(person_dir):
142
+ os.makedirs(person_dir)
143
+
144
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
145
+ filename = f"{timestamp}.jpg"
146
+ cv2.imwrite(os.path.join(person_dir, filename), face_roi)
147
+
148
+ names_file = os.path.join(FACE_DATA_DIR, 'names.pkl')
149
+ if os.path.exists(names_file):
150
+ with open(names_file, 'rb') as f:
151
+ names = pickle.load(f)
152
+ else:
153
+ names = []
154
+
155
+ if name not in names:
156
+ names.append(name)
157
+ with open(names_file, 'wb') as f:
158
+ pickle.dump(names, f)
159
+
160
+ load_face_data()
161
+ return jsonify({'success': f'Wajah {name} berhasil didaftarkan'})
162
+
163
+ @flask_app.route('/delete_face/<name>')
164
+ def delete_face(name):
165
+ person_dir = os.path.join(FACE_DATA_DIR, name)
166
+ if os.path.exists(person_dir):
167
+ for filename in os.listdir(person_dir):
168
+ os.remove(os.path.join(person_dir, filename))
169
+ os.rmdir(person_dir)
170
+
171
+ names_file = os.path.join(FACE_DATA_DIR, 'names.pkl')
172
+ if os.path.exists(names_file):
173
+ with open(names_file, 'rb') as f:
174
+ names = pickle.load(f)
175
+ if name in names:
176
+ names.remove(name)
177
+ with open(names_file, 'wb') as f:
178
+ pickle.dump(names, f)
179
+ load_face_data()
180
+ return redirect(url_for('index'))
181
+
182
+ # ==== Bungkus Flask ke FastAPI untuk Hugging Face ====
183
+ from fastapi import FastAPI
184
+ from fastapi.middleware.wsgi import WSGIMiddleware
185
+
186
+ app = FastAPI()
187
+
188
+ # Endpoint bawaan FastAPI
189
+ @app.get("/hello")
190
+ def greet_json():
191
+ return {"Hello": "World!"}
192
+
193
+ # Mount Flask app ke FastAPI
194
+ app.mount("/", WSGIMiddleware(flask_app))
195
+
196
+ # Jalankan dengan uvicorn kalau lokal
197
+ if __name__ == "__main__":
198
+ import uvicorn
199
+ uvicorn.run(app, host="0.0.0.0", port=7860)