Working on pose threshold and fix multithreading
This commit is contained in:
parent
cec1cc8ff0
commit
1870c956b0
2 changed files with 21 additions and 12 deletions
13
main.py
13
main.py
|
|
@ -29,7 +29,7 @@ class AppConfig:
|
||||||
output_folder: str = "output"
|
output_folder: str = "output"
|
||||||
landmark_model: str = "shape_predictor_68_face_landmarks.dat"
|
landmark_model: str = "shape_predictor_68_face_landmarks.dat"
|
||||||
resize_size: int = 512
|
resize_size: int = 512
|
||||||
face_resolution_threshold: int = 128
|
face_resolution_threshold: int = 80
|
||||||
pose_threshold: float = 25.0
|
pose_threshold: float = 25.0
|
||||||
left_eye_pos: Tuple[float, float] = (0.35, 0.4)
|
left_eye_pos: Tuple[float, float] = (0.35, 0.4)
|
||||||
date_from: str = None
|
date_from: str = None
|
||||||
|
|
@ -71,6 +71,7 @@ def check_output_folder() -> Tuple[bool, int]:
|
||||||
return len(files) == 0, len(files)
|
return len(files) == 0, len(files)
|
||||||
|
|
||||||
def background_process(
|
def background_process(
|
||||||
|
max_workers: int = 1,
|
||||||
progress_callback: Callable = None,
|
progress_callback: Callable = None,
|
||||||
cancel_flag: Callable = None
|
cancel_flag: Callable = None
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
|
|
@ -86,7 +87,7 @@ def background_process(
|
||||||
try:
|
try:
|
||||||
return process_faces(
|
return process_faces(
|
||||||
config=config,
|
config=config,
|
||||||
max_workers=1,
|
max_workers=max_workers,
|
||||||
progress_callback=progress_callback,
|
progress_callback=progress_callback,
|
||||||
cancel_flag=cancel_flag
|
cancel_flag=cancel_flag
|
||||||
)
|
)
|
||||||
|
|
@ -110,13 +111,10 @@ def check_connection() -> Dict[str, any]:
|
||||||
def cancel() -> Dict[str, any]:
|
def cancel() -> Dict[str, any]:
|
||||||
"""Cancel the current processing job."""
|
"""Cancel the current processing job."""
|
||||||
global processing_thread, cancel_requested
|
global processing_thread, cancel_requested
|
||||||
|
|
||||||
cancel_requested = True
|
cancel_requested = True
|
||||||
|
|
||||||
if processing_thread and processing_thread.is_alive():
|
if processing_thread and processing_thread.is_alive():
|
||||||
progress_info["status"] = "cancelled"
|
progress_info["status"] = "cancelled"
|
||||||
return jsonify({"success": True, "message": "Processing cancelled."})
|
return jsonify({"success": True, "message": "Processing cancelled."})
|
||||||
|
|
||||||
cancel_requested = False
|
cancel_requested = False
|
||||||
return jsonify({"success": False, "message": "No active processing to cancel."})
|
return jsonify({"success": False, "message": "No active processing to cancel."})
|
||||||
|
|
||||||
|
|
@ -152,8 +150,7 @@ def index() -> str:
|
||||||
config.pose_threshold = float(request.form.get("pose_threshold"))
|
config.pose_threshold = float(request.form.get("pose_threshold"))
|
||||||
config.date_from = request.form.get("date_from")
|
config.date_from = request.form.get("date_from")
|
||||||
config.date_to = request.form.get("date_to")
|
config.date_to = request.form.get("date_to")
|
||||||
|
max_workers = int(request.form.get("max_workers"))
|
||||||
# Video compilation options
|
|
||||||
compile_video = request.form.get("compile_video") == "on"
|
compile_video = request.form.get("compile_video") == "on"
|
||||||
framerate = int(request.form.get("framerate", 15))
|
framerate = int(request.form.get("framerate", 15))
|
||||||
|
|
||||||
|
|
@ -168,7 +165,7 @@ def index() -> str:
|
||||||
# Start processing
|
# Start processing
|
||||||
processing_thread = threading.Thread(
|
processing_thread = threading.Thread(
|
||||||
target=background_process,
|
target=background_process,
|
||||||
args=(update_progress, lambda: cancel_requested)
|
args=(max_workers, update_progress, lambda: cancel_requested)
|
||||||
)
|
)
|
||||||
processing_thread.start()
|
processing_thread.start()
|
||||||
result = "Processing started. Please wait and watch the progress bar below."
|
result = "Processing started. Please wait and watch the progress bar below."
|
||||||
|
|
|
||||||
20
timelapse.py
20
timelapse.py
|
|
@ -247,6 +247,18 @@ def get_head_pose(landmarks, image):
|
||||||
proj_matrix = np.hstack((rotation_matrix, translation_vector))
|
proj_matrix = np.hstack((rotation_matrix, translation_vector))
|
||||||
_, _, _, _, _, _, euler_angles = cv2.decomposeProjectionMatrix(proj_matrix)
|
_, _, _, _, _, _, euler_angles = cv2.decomposeProjectionMatrix(proj_matrix)
|
||||||
pitch, yaw, roll = [float(angle) for angle in euler_angles]
|
pitch, yaw, roll = [float(angle) for angle in euler_angles]
|
||||||
|
|
||||||
|
# Normalize angles to be between -180 and 180 degrees
|
||||||
|
pitch = (pitch + 180) % 360 - 180
|
||||||
|
yaw = (yaw + 180) % 360 - 180
|
||||||
|
roll = (roll + 180) % 360 - 180
|
||||||
|
|
||||||
|
# Adjust pitch to be between -90 and 90 degrees
|
||||||
|
if pitch > 90:
|
||||||
|
pitch = 180 - pitch
|
||||||
|
elif pitch < -90:
|
||||||
|
pitch = -180 - pitch
|
||||||
|
|
||||||
return pitch, yaw, roll
|
return pitch, yaw, roll
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -493,7 +505,7 @@ def crop_and_align_face(image, face_data, resize_size, face_resolution_threshold
|
||||||
# Check if both eyes are visible
|
# Check if both eyes are visible
|
||||||
if not check_eye_visibility(landmarks['left_eye'], landmarks['right_eye']):
|
if not check_eye_visibility(landmarks['left_eye'], landmarks['right_eye']):
|
||||||
logger.info("Eyes are too closed")
|
logger.info("Eyes are too closed")
|
||||||
draw_landmarks(img_np, landmarks['all_landmarks'], (x1, y1, x2, y2), "discarded/eyes_closed.jpg")
|
# draw_landmarks(img_np, landmarks['all_landmarks'], (x1, y1, x2, y2), f"discarded/eyes_closed_{face_data.get('id')}.jpg")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Get head pose
|
# Get head pose
|
||||||
|
|
@ -505,10 +517,10 @@ def crop_and_align_face(image, face_data, resize_size, face_resolution_threshold
|
||||||
|
|
||||||
# Check if head pose is within acceptable range
|
# Check if head pose is within acceptable range
|
||||||
pitch, yaw, roll = pose
|
pitch, yaw, roll = pose
|
||||||
if abs(pitch) > pose_threshold or abs(yaw) > pose_threshold or abs(roll) > pose_threshold:
|
if abs(yaw) > pose_threshold:
|
||||||
logger.info(f"Head pose exceeds threshold: pitch={pitch:.1f}°, yaw={yaw:.1f}°, roll={roll:.1f}°")
|
logger.info(f"Head pose exceeds threshold: pitch={pitch:.1f}°, yaw={yaw:.1f}°, roll={roll:.1f}°")
|
||||||
draw_landmarks(img_np, landmarks['all_landmarks'], (x1, y1, x2, y2), f"discarded/pose_pitch_{pitch:.1f}_yaw_{yaw:.1f}_roll_{roll:.1f}.jpg")
|
draw_landmarks(img_np, landmarks['all_landmarks'], (x1, y1, x2, y2), f"discarded/pose_yaw_{yaw:.1f}.jpg")
|
||||||
# return None
|
return None
|
||||||
|
|
||||||
# Get eye positions
|
# Get eye positions
|
||||||
left_eye_center = np.mean(landmarks['left_eye'], axis=0)
|
left_eye_center = np.mean(landmarks['left_eye'], axis=0)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue