Ahilan Kumaresan commited on
Commit ·
5807ca9
1
Parent(s): 9997313
added functions from the presentation file into the functions.py script, make presentation notebook more cleaner
Browse files- ModularedPresentation.ipynb +0 -0
- functions.py +141 -0
ModularedPresentation.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
functions.py
CHANGED
|
@@ -595,3 +595,144 @@ def capture_potential(tune, A_MIN, A_MAX, mode='wait'):
|
|
| 595 |
cv2.destroyAllWindows()
|
| 596 |
return captured_V
|
| 597 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 595 |
cv2.destroyAllWindows()
|
| 596 |
return captured_V
|
| 597 |
|
| 598 |
+
# Create a notebook-friendly version of the function
|
| 599 |
+
def capture_potential_notebook(tune, A_MIN, A_MAX, mode='wait'):
|
| 600 |
+
import time
|
| 601 |
+
from IPython.display import display, Image, clear_output
|
| 602 |
+
|
| 603 |
+
|
| 604 |
+
# Copy relevant constants from the file for local scope
|
| 605 |
+
THUMB_TIP_ID = 4
|
| 606 |
+
INDEX_TIP_ID = 8
|
| 607 |
+
REQUIRED_STABLE_FRAMES = 45
|
| 608 |
+
MOVEMENT_THRESHOLD = 0.015
|
| 609 |
+
PLOT_CEILING_A = 10.0
|
| 610 |
+
EPS = 1e-9
|
| 611 |
+
|
| 612 |
+
D_MIN = 0.001
|
| 613 |
+
D_MAX = 0.2
|
| 614 |
+
D_RANGE = D_MAX - D_MIN
|
| 615 |
+
A_RANGE = A_MAX - A_MIN
|
| 616 |
+
SLOPE = -A_RANGE / D_RANGE
|
| 617 |
+
INTERCEPT = A_MAX - SLOPE * D_MIN
|
| 618 |
+
# End of copied constants
|
| 619 |
+
|
| 620 |
+
cap = cv2.VideoCapture(0)
|
| 621 |
+
captured_V = None
|
| 622 |
+
|
| 623 |
+
if not cap.isOpened():
|
| 624 |
+
print("Error: Could not open video stream. Check permissions or camera index.")
|
| 625 |
+
return None
|
| 626 |
+
|
| 627 |
+
stability_counter = 0
|
| 628 |
+
prev_landmarks = []
|
| 629 |
+
|
| 630 |
+
start_time = time.time()
|
| 631 |
+
MAX_RUN_TIME_SECONDS = 30
|
| 632 |
+
|
| 633 |
+
print("Controls: HOLD STILL to capture, or wait for the time limit to exit.")
|
| 634 |
+
|
| 635 |
+
while True:
|
| 636 |
+
ret, frame = cap.read()
|
| 637 |
+
if not ret:
|
| 638 |
+
break
|
| 639 |
+
|
| 640 |
+
frame = cv2.flip(frame, 1)
|
| 641 |
+
h, w, _ = frame.shape
|
| 642 |
+
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
| 643 |
+
res = hands.process(rgb)
|
| 644 |
+
|
| 645 |
+
pot_profile = None
|
| 646 |
+
mode_msg = "No Hands"
|
| 647 |
+
params_to_display = []
|
| 648 |
+
current_landmarks_flat = []
|
| 649 |
+
|
| 650 |
+
# --- LANDMARK AND POTENTIAL LOGIC (Skipped for brevity, assume this is correct) ---
|
| 651 |
+
if res.multi_hand_landmarks:
|
| 652 |
+
for hand_lms in res.multi_hand_landmarks:
|
| 653 |
+
for lm in hand_lms.landmark:
|
| 654 |
+
current_landmarks_flat.extend([lm.x, lm.y])
|
| 655 |
+
for lm in res.multi_hand_landmarks:
|
| 656 |
+
drawer.draw_landmarks(frame, lm, mp_hands.HAND_CONNECTIONS)
|
| 657 |
+
|
| 658 |
+
# TWO HANDS (Square Well)
|
| 659 |
+
if len(res.multi_hand_landmarks) >= 2:
|
| 660 |
+
mode_msg = "Mode: Square Well (Auto-Centered)"
|
| 661 |
+
x_coords = [lm.landmark[INDEX_TIP_ID].x * w for lm in res.multi_hand_landmarks]
|
| 662 |
+
x_coords.sort()
|
| 663 |
+
xL_hand, xR_hand = int(x_coords[0]), int(x_coords[1])
|
| 664 |
+
cv2.line(frame, (xL_hand, 0), (xL_hand, h), (0, 255, 255), 2)
|
| 665 |
+
cv2.line(frame, (xR_hand, 0), (xR_hand, h), (0, 255, 255), 2)
|
| 666 |
+
well_width = xR_hand - xL_hand
|
| 667 |
+
center_screen = w / 2
|
| 668 |
+
centered_L = center_screen - (well_width / 2)
|
| 669 |
+
centered_R = center_screen + (well_width / 2)
|
| 670 |
+
params_to_display.append(f"Width: {well_width:4.0f} px")
|
| 671 |
+
params_to_display.append(f"Status: Centered")
|
| 672 |
+
x_space = np.linspace(0, w, 400)
|
| 673 |
+
pot_profile = np.ones_like(x_space)
|
| 674 |
+
pot_profile[(x_space > centered_L) & (x_space < centered_R)] = 0
|
| 675 |
+
# ONE HAND (QHO)
|
| 676 |
+
elif len(res.multi_hand_landmarks) == 1:
|
| 677 |
+
mode_msg = "Mode: Pinch QHO"
|
| 678 |
+
lm = res.multi_hand_landmarks[0]
|
| 679 |
+
thumb = lm.landmark[THUMB_TIP_ID]
|
| 680 |
+
index = lm.landmark[INDEX_TIP_ID]
|
| 681 |
+
dx = index.x - thumb.x
|
| 682 |
+
dy = index.y - thumb.y
|
| 683 |
+
pinch_distance = math.sqrt(dx**2 + dy**2)
|
| 684 |
+
A = SLOPE * pinch_distance + INTERCEPT
|
| 685 |
+
A = max(A_MIN, min(A_MAX, A))
|
| 686 |
+
x_space = np.linspace(-1, 1, 400)
|
| 687 |
+
pot_profile = A * (x_space**2)
|
| 688 |
+
pot_profile = pot_profile / (PLOT_CEILING_A + EPS)
|
| 689 |
+
pot_profile = np.clip(pot_profile, 0.0, 1.0)
|
| 690 |
+
params_to_display.append(f"Pinch Dist: {pinch_distance:.4f}")
|
| 691 |
+
params_to_display.append(f"A (curv): {A:.4f}")
|
| 692 |
+
display_pts = np.column_stack(((x_space + 1)/2 * w, (1 - pot_profile) * h)).astype(np.int32)
|
| 693 |
+
cv2.polylines(frame, [display_pts], False, (0, 0, 255), 2)
|
| 694 |
+
# --- END LANDMARK AND POTENTIAL LOGIC ---
|
| 695 |
+
|
| 696 |
+
# STABILITY CHECK
|
| 697 |
+
if mode != 'wait':
|
| 698 |
+
if current_landmarks_flat and prev_landmarks and len(current_landmarks_flat) == len(prev_landmarks):
|
| 699 |
+
movement = np.mean(np.abs(np.array(current_landmarks_flat) - np.array(prev_landmarks)))
|
| 700 |
+
stability_counter = stability_counter + 1 if movement < MOVEMENT_THRESHOLD else 0
|
| 701 |
+
else:
|
| 702 |
+
stability_counter = 0
|
| 703 |
+
|
| 704 |
+
prev_landmarks = current_landmarks_flat
|
| 705 |
+
|
| 706 |
+
if stability_counter > 0:
|
| 707 |
+
progress = stability_counter / REQUIRED_STABLE_FRAMES
|
| 708 |
+
bar_width = int(w * progress)
|
| 709 |
+
color = (0, 255*progress, 255*(1-progress))
|
| 710 |
+
cv2.rectangle(frame, (0, 0), (bar_width, 20), color, -1)
|
| 711 |
+
cv2.putText(frame, "HOLDING...", (10, 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)
|
| 712 |
+
|
| 713 |
+
# Finished
|
| 714 |
+
if stability_counter >= REQUIRED_STABLE_FRAMES and pot_profile is not None:
|
| 715 |
+
captured_V = pot_profile
|
| 716 |
+
cap.release()
|
| 717 |
+
# --- LINE REMOVED HERE (was cv2.destroyAllWindows()) ---
|
| 718 |
+
print("Stable capture triggered and video stream closed.")
|
| 719 |
+
return captured_V
|
| 720 |
+
|
| 721 |
+
# UI OVERLAY
|
| 722 |
+
cv2.putText(frame, mode_msg, (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
| 723 |
+
display_params(frame, params_to_display)
|
| 724 |
+
|
| 725 |
+
# NOTEBOOK DISPLAY
|
| 726 |
+
clear_output(wait=True)
|
| 727 |
+
_, buffer = cv2.imencode('.jpeg', frame)
|
| 728 |
+
display(Image(data=buffer.tobytes()))
|
| 729 |
+
|
| 730 |
+
time.sleep(0.01)
|
| 731 |
+
|
| 732 |
+
if time.time() - start_time > MAX_RUN_TIME_SECONDS:
|
| 733 |
+
print(f"Time limit of {MAX_RUN_TIME_SECONDS} seconds reached.")
|
| 734 |
+
break
|
| 735 |
+
|
| 736 |
+
# -----------------------------------------------------------------
|
| 737 |
+
cap.release()
|
| 738 |
+
return captured_V
|