bram4627 commited on
Commit
db13789
·
verified ·
1 Parent(s): 50ff895

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +79 -84
app.py CHANGED
@@ -5,8 +5,7 @@ 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'
@@ -15,20 +14,20 @@ 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):
@@ -38,7 +37,7 @@ def load_face_data():
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
@@ -47,153 +46,149 @@ def load_face_data():
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)
 
5
  import pickle
6
  from datetime import datetime
7
 
8
+ app = Flask(__name__)
 
9
 
10
  FACE_DATA_DIR = 'face_data'
11
  FACE_CASCADE_PATH = cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
 
14
  os.makedirs(FACE_DATA_DIR)
15
 
16
  face_cascade = cv2.CascadeClassifier(FACE_CASCADE_PATH)
17
+
18
  camera = None
19
  face_recognizer = cv2.face.LBPHFaceRecognizer_create()
20
  is_trained = False
21
+ has_webcam = os.path.exists("/dev/video0") # deteksi webcam
22
 
23
  def load_face_data():
24
  global is_trained
25
+ faces, labels, names = [], [], []
26
+
 
 
27
  if os.path.exists(os.path.join(FACE_DATA_DIR, 'names.pkl')):
28
  with open(os.path.join(FACE_DATA_DIR, 'names.pkl'), 'rb') as f:
29
  names = pickle.load(f)
30
+
31
  for idx, name in enumerate(names):
32
  face_dir = os.path.join(FACE_DATA_DIR, name)
33
  if os.path.exists(face_dir):
 
37
  img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
38
  faces.append(img)
39
  labels.append(idx)
40
+
41
  if faces:
42
  face_recognizer.train(faces, np.array(labels))
43
  is_trained = True
 
46
 
47
  def get_camera():
48
  global camera
49
+ if has_webcam:
50
+ if camera is None:
51
+ camera = cv2.VideoCapture(0)
52
+ return camera
53
+ return None
54
 
55
+ @app.route('/')
56
  def index():
57
  names = load_face_data()
58
+ return render_template('index.html', registered_faces=names, has_webcam=has_webcam)
59
 
60
+ @app.route('/register')
61
  def register():
62
+ return render_template('register.html', has_webcam=has_webcam)
63
 
64
+ @app.route('/recognize')
65
  def recognize():
66
+ return render_template('recognize.html', has_webcam=has_webcam)
67
 
68
+ @app.route('/video_feed')
69
  def video_feed():
70
+ if not has_webcam:
71
+ return "Webcam tidak tersedia di server ini", 404
72
+
73
  def generate():
74
+ cam = get_camera()
75
  while True:
76
+ success, frame = cam.read()
77
  if not success:
78
  break
79
  ret, buffer = cv2.imencode('.jpg', frame)
80
  frame = buffer.tobytes()
81
  yield (b'--frame\r\n'
82
  b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
83
+
84
  return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
85
 
86
+ @app.route('/recognition_feed')
87
  def recognition_feed():
88
+ if not has_webcam:
89
+ return "Webcam tidak tersedia di server ini", 404
90
+
91
  def generate():
92
+ cam = get_camera()
93
  names = load_face_data()
94
+
95
  while True:
96
+ success, frame = cam.read()
97
  if not success:
98
  break
99
+
100
  gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
101
  faces = face_cascade.detectMultiScale(gray, 1.3, 5)
102
+
103
  for (x, y, w, h) in faces:
104
  cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
105
+
106
  if is_trained and names:
107
  roi_gray = gray[y:y+h, x:x+w]
108
  roi_gray = cv2.resize(roi_gray, (100, 100))
109
+
110
  id_, confidence = face_recognizer.predict(roi_gray)
 
111
  if confidence < 100:
112
  name = names[id_]
113
  confidence_text = f"{name} ({round(100-confidence)}%)"
114
  else:
115
  confidence_text = "Unknown"
116
+
117
+ cv2.putText(frame, confidence_text, (x, y-10),
118
  cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
119
+
120
  ret, buffer = cv2.imencode('.jpg', frame)
121
  frame = buffer.tobytes()
122
  yield (b'--frame\r\n'
123
  b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
124
+
125
  return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame')
126
 
127
+ @app.route('/capture_face', methods=['POST'])
128
  def capture_face():
129
+ if has_webcam:
130
+ name = request.json.get('name', '').strip()
131
+ if not name:
132
+ return jsonify({'error': 'Nama tidak boleh kosong'})
133
+
134
+ cam = get_camera()
135
+ success, frame = cam.read()
136
+ if not success:
137
+ return jsonify({'error': 'Gagal mengambil gambar dari kamera'})
138
+
139
+ return save_face(name, frame)
140
+ else:
141
+ return jsonify({'error': 'Webcam tidak tersedia, gunakan /upload_face'})
142
+
143
+ @app.route('/upload_face', methods=['POST'])
144
+ def upload_face():
145
+ """Upload foto untuk registrasi (tanpa webcam)"""
146
+ name = request.form.get('name', '').strip()
147
+ file = request.files.get('file')
148
+
149
  if not name:
150
  return jsonify({'error': 'Nama tidak boleh kosong'})
151
+ if not file:
152
+ return jsonify({'error': 'File tidak ditemukan'})
153
+
154
+ np_img = np.frombuffer(file.read(), np.uint8)
155
+ frame = cv2.imdecode(np_img, cv2.IMREAD_COLOR)
156
+ return save_face(name, frame)
157
+
158
+ def save_face(name, frame):
159
  gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
160
  faces = face_cascade.detectMultiScale(gray, 1.3, 5)
161
+
162
  if len(faces) == 0:
163
  return jsonify({'error': 'Tidak ada wajah yang terdeteksi'})
164
  if len(faces) > 1:
165
  return jsonify({'error': 'Terdeteksi lebih dari satu wajah'})
166
+
167
  (x, y, w, h) = faces[0]
168
  face_roi = gray[y:y+h, x:x+w]
169
  face_roi = cv2.resize(face_roi, (100, 100))
170
+
171
  person_dir = os.path.join(FACE_DATA_DIR, name)
172
  if not os.path.exists(person_dir):
173
  os.makedirs(person_dir)
174
+
175
+ filename = f"{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
 
176
  cv2.imwrite(os.path.join(person_dir, filename), face_roi)
177
+
178
  names_file = os.path.join(FACE_DATA_DIR, 'names.pkl')
179
  if os.path.exists(names_file):
180
  with open(names_file, 'rb') as f:
181
  names = pickle.load(f)
182
  else:
183
  names = []
184
+
185
  if name not in names:
186
  names.append(name)
187
  with open(names_file, 'wb') as f:
188
  pickle.dump(names, f)
189
+
190
  load_face_data()
191
  return jsonify({'success': f'Wajah {name} berhasil didaftarkan'})
192
 
193
+ if __name__ == '__main__':
194
+ app.run(debug=True, host='0.0.0.0', port=5000)