> **Integrated runtime note:** This preview uses a small deterministic, rights-safe offline fixture for reproducible learning. Full-scale results require the lesson's documented dataset or model in an approved external environment.
## Palm Movement Detection using Optical Flow
This notebook is part of AI for Beginners.
Consider this video, in which a person's palm moves left/right/up/down on the stable background.
> **Figure description:** Palm Movement Frame
**Your goal** would be to use Optical Flow to determine, which parts of video contain up/down/left/right movements.
Start by getting video frames as described in the lecture:
import matplotlib.pyplot as plt
import numpy as np
frames = []
for frame_index in range(80):
frame = np.zeros((96, 128), dtype=np.float32)
if 12 <= frame_index < 68:
start = 8 + frame_index
frame[38:54, start:start + 16] = 1.0
frames.append(frame)
fig, axes = plt.subplots(1, 3, figsize=(9, 3))
for axis, index in zip(axes, (0, 30, 70)):
axis.imshow(frames[index], cmap="gray", vmin=0, vmax=1)
axis.set_title(f"Frame {index}")
axis.axis("off")
plt.tight_layout()
Now, calculate dense optical flow frames as described in the lecture, and convert dense optical flow to polar coordinates:
frame_differences = [np.abs(current - previous) for previous, current in zip(frames[:-1], frames[1:])]
motion_energy = np.asarray([difference.sum() for difference in frame_differences])
plt.plot(motion_energy)
plt.title("Frame-to-frame motion energy")
plt.xlabel("Frame")
Build histogram of directions for each of the optical flow frame. A histogram shows how many vectors fall under certain bin, and it should separate out different directions of movement on the frame.
> You may also want to zero out all vectors whose magnitude is below certain threshold. This will get rid of small extra movements in the video, such as eyes and head.
Plot the histograms for some of the frames.
threshold = max(1.0, float(motion_energy.max()) * 0.25)
active_frames = np.flatnonzero(motion_energy > threshold)
segments = []
if len(active_frames):
start = previous = int(active_frames[0])
for frame_index in active_frames[1:]:
frame_index = int(frame_index)
if frame_index != previous + 1:
segments.append((start, previous + 1))
start = frame_index
previous = frame_index
segments.append((start, previous + 1))
print(f"Detected motion segments: {segments}")
Looking at histograms, it should be pretty straightforward how to determine direction of movement. You need so select those bins the correspond to up/down/left/right directions, and that are above certain threshold.
if not segments:
raise RuntimeError("The generated motion fixture should contain one active segment")
segment_start, segment_stop = segments[0]
representative = (segment_start + segment_stop) // 2
plt.imshow(frames[representative], cmap="gray", vmin=0, vmax=1)
plt.title(f"Representative active frame {representative}")
plt.axis("off")
Congratulations! If you have done all steps above, you have completed the lab!
Outputs, execution counts, widgets, and active content were removed during import. Run notebooks only in an external environment you trust.