MediaPipe — ทำ Six Seven Counter … ทำไม?
ช่วงนี้ ถ้าใครได้เลื่อนดู shorts หรือ reels ก็คงจะเห็นโปรเจคแนว ๆ นี้กันบ้าง ที่เป็นคนเปิดกล้องแล้วทำท่า “six seven” หลังจากนั้นก็ให้ AI…
MediaPipe — ทำ Six Seven Counter … ทำไม?
ช่วงนี้ ถ้าใครได้เลื่อนดู shorts หรือ reels ก็คงจะเห็นโปรเจคแนว ๆ นี้กันบ้าง ที่เป็นคนเปิดกล้องแล้วทำท่า “six seven” หลังจากนั้นก็ให้ AI นับว่าเราทำไปกี่ครั้งแล้ว? หรือ ภายในเวลาที่กำหนดเราทำได้ทั้งหมดกี่ครั้ง (ฟีล ๆ wpm แต่เป็น 67pm แทน) เนื่องจากระหว่างนี้ได้ลองทำโปรเจคเกี่ยวกับ pose estimation พอดีเลยอยากลองทำ AI นับ 67 ดู ถือว่าลองทำโปรเจคจริง (?) สักอย่างก่อนไปทำอย่างอื่นต่อ 555

Six Sevennnnnnn (Thanks ChatGPT)
รู้จักกับ Pose Estimation
Pose Estimation เป็น งานทางด้านภาพประเภทหนึ่งที่ใช้ในการ “ระบุจุด หรือ keypoint ในภาพ” ตัวอย่าง เช่น ไหล่ ข้อศอก ข้อมือ หรือ ขา เพื่อนำไปใช้ต่อกับงานอื่น ๆ อีก

Pose Estimation I (Thanks ChatGPT)
ซึ่งหลัก ๆ แล้วสิ่งที่เราจะได้มาจากขั้นตอนดังกล่าวจะประกอบไปด้วย (i) Landmark (ii) Connection เพื่อระบุว่าเรามีจุดและเส้นเชื่อมจากจุดไหนไปจุดไหนบ้าง
Mediapipe
Mediapipe เป็น framework เกี่ยวกับงานด้านภาพจาก Google ซึ่งหนึ่งเครื่องมือที่สามารถนำมาใช้ได้ก็คือ Pose Estimation
Let’s Code!
ในขั้นตอนนี้เราจะแบ่งโค้ดหลัก ๆ เป็น 2 ส่วน
- Pose Estimation
- Six Seven Counter
Pose Estimation
หลัก ๆ เราจะใช้ feature ของ mediapipe ที่เป็น live stream ในการทำงานร่วมกับกล้อง webcam สำหรับการทำ real time pose estimation ซึ่งขั้นตอนหลัก ๆ ของเราจะแบ่งเป็น
(i) Setup Model Options
ในขั้นนี้โมเดลที่เลือกจะเป็น LITE_MODEL ซึ่งเป็นโมเดลขนาดที่เล็กที่สุดแล้ว
options = PoseLandmarkerOptions(
base_options=BaseOptions(model_asset_path=model_path),
running_mode=VisionRunningMode.LIVE_STREAM,
result_callback=self._pose_landmarker_result_callback,
)
(ii) Inference Pose Estimation
with PoseLandmarker.create_from_options(self.options) as landmarker:
landmarker.detect_async(input_image, timestamp_ms)
หลังจากที่เราทำกระบวนการที่ (ii) เราจะได้ผลลัพธ์เป็น ข้อมูล landmark และ connection ของ joint ต่าง ๆ ที่พร้อมสำหรับการนำไปใช้ต่อแล้ว

Pose Estimation II(Thanks ChatGPT)
Six Seven Counter
หลังจากที่เราได้ตัวของ landmark กับ connection กันมาแล้ว เราจะใช้ข้อมูลส่วนนี้ในการคำนวณการขึ้นลงของมือกัน
เราจะนิยามว่า “การทำ six seven 1 รอบ คือ การที่มือแต่ละข้าง ขึ้น-ลง อย่างน้อย 1 ครั้ง” แล้วคำถามถัดมาคือ “เราจะรู้ได้ยังไงว่ามือนั้น ขึ้น-ลง แล้ว?”
เราสามารถมอง connection ระหว่าง joint เป็น vector แล้วเราจะทำการหามุมระหว่าง vector นั้น ๆ แทน ซึ่งเราจะหามุมระหว่าง ไหล่-ศอก-ข้อมือ
def _calculate_angle(self, shoulder, elbow, wrist):
a = np.array(shoulder)
b = np.array(elbow)
c = np.array(wrist)
ba = a - b
bc = c - b
cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle = np.arccos(cosine_angle)
return np.degrees(angle)
โดย เราจะดึงข้อมูล landmark ของ ไหล่-ศอก-ข้อมือ ได้จาก index ของ landmark
# Right Hand
right_shoulder = (
landmarks[mp.tasks.vision.PoseLandmark.RIGHT_SHOULDER].x,
landmarks[mp.tasks.vision.PoseLandmark.RIGHT_SHOULDER].y,
)
right_elbow = (
landmarks[mp.tasks.vision.PoseLandmark.RIGHT_ELBOW].x,
landmarks[mp.tasks.vision.PoseLandmark.RIGHT_ELBOW].y,
)
right_wrist = (
landmarks[mp.tasks.vision.PoseLandmark.RIGHT_WRIST].x,
landmarks[mp.tasks.vision.PoseLandmark.RIGHT_WRIST].y,
)
# Left Hand
left_shoulder = (
landmarks[mp.tasks.vision.PoseLandmark.LEFT_SHOULDER].x,
landmarks[mp.tasks.vision.PoseLandmark.LEFT_SHOULDER].y,
)
left_elbow = (
landmarks[mp.tasks.vision.PoseLandmark.LEFT_ELBOW].x,
landmarks[mp.tasks.vision.PoseLandmark.LEFT_ELBOW].y,
)
left_wrist = (
landmarks[mp.tasks.vision.PoseLandmark.LEFT_WRIST].x,
landmarks[mp.tasks.vision.PoseLandmark.LEFT_WRIST].y,
)
จากนั้นเราจะนิยาม state ของ counter เราดังนี้ ถ้ามุมที่คำนวณได้น้อยกว่า 90 องศา ให้หมายถึงว่าเรากำลังยกแขนขึ้น แต่ถ้ามากกว่านั้นถือว่ายกแขนลง

State Diagram (Thanks ChatGPT)
IDLE (0 หรือ 00)กรณีที่ยังไม่ได้ยกมือLEFT_UP (1 หรือ 01)กรณีที่เคยยกมือข้างซ้ายแล้วRIGHT_UP (2 หรือ 10)กรณีที่เคยยกมือข้างขวาแล้วBOTH_UP (3 หรือ 11)กรณีที่เคยยกมือทั้งสองข้าง (เราจะนับแต้มกันใน state นี้)
def _update_state(self, left_arm_up, right_arm_up):
if left_arm_up and self.prev_left == 2:
self.state |= 1 << 0
if right_arm_up and self.prev_right == 2:
self.state |= 1 << 1
if self.state == 3:
self.count += 1
self.state = 0
self.prev_left = 0
self.prev_right = 0
self._update_prev_state(left_arm_up, right_arm_up)
ในส่วนของ prev_state ของมือแต่ละข้างจะแบ่งเป็น
0คือ ยังไม่เคยยกมือมาก่อน1คือ กำลังยกมือขึ้น2คือ เคยยกมือขึ้นแล้วเอาลงอย่างน้อย 1 รอบ
หลังจากนั้นไม่ว่าจะขึ้นหรือลงก็จะค้างที่ 2 เสมอ จนกว่าจะเข้า BOTH_UP ถึงจะกลับไปที่ 0 ใหม่ (สรุป 0 -> 1 -> 2 -> 0 -> …)
ผลลัพธ์ที่ได้:

Result from Our Counter!
จริง ๆ ช่วงนี้ทำอยู่หลายโปรเจคเลยทำให้ไม่ค่อยได้เขียนโค้ดเองเล่น ๆ แบบนี้สักพักแล้ว ส่วนมากจะ vibe เอา 555 สำหรับคนที่สนใจลองจิ้ม ๆ ดูโค้ดได้ในนี้เลยครับบ
메타데이터
- post_id
- d3fbfae98c6b
- slug
- mediapipe-ทำ-six-seven-counter-ทำไม-d3fbfae98c6b
- url
- https://medium.com/@rufflogix/mediapipe-%E0%B8%97%E0%B8%B3-six-seven-counter-%E0%B8%97%E0%B8%B3%E0%B9%84%E0%B8%A1-d3fbfae98c6b
- canonical_url
- https://medium.com/@rufflogix/mediapipe-%E0%B8%97%E0%B8%B3-six-seven-counter-%E0%B8%97%E0%B8%B3%E0%B9%84%E0%B8%A1-d3fbfae98c6b
- author_url
- https://medium.com/@rufflogix
- status
- ok
- fetched_at
- 2026-08-12 23:48:45