Using OpenPose for social distancing detection on Colab

Surapoom Somwangthanaroj
Super AI Engineer
Published in
4 min readMar 30, 2021

ที่ผ่านมาผมได้รับโจทย์ให้ประมาณระยะห่างระหว่างบุคคลจากภาพวีดีโอ ซึ่งเครื่องคอมพิวเตอร์ของผมเองก็ไม่ได้มี GPU ที่แรงมาก ผมจึงใช้ Colab ในการทดลองเขียนโจทย์นี้

ในโจทย์นี้ผมเลือกใช้ OpenPose + Norfair เพื่อตรวจจับและติดตามคนที่อยู่ในภาพ และหลังจากนั้นจึงใช้ Perspective Transform ของ OpenCV เพื่อปรับเปลี่ยนภาพจากมุมกล้องมาเป็นภาพ Top View เพื่อคำนวณระยะห่างของคนแต่ละคน ทั้งนี้สิ่งที่จำเป็นของการใช้ Perspective Transform ของ OpenCV คือการ map จุดอ้างอิงในภาพกับพื้นที่จริงรวมถึงระยะระหว่างจุดอ้างอิงเหล่านั้น

เพื่อความสะดวกผมจึงระบุจุดอ้างอิงเป็นรูปสี่เหลี่ยมผืนผ้าในพื้นที่จริงเพื่อให้ง่ายต่อการสร้าง numpy array ของจุดอ้างอิง และการแปลงจุดอ้างอิงเหล่านั้นมาเป็นภาพ Top View

จากภาพข้างบน สมมุติว่าพื้นที่ๆเราสนใจคือพื้นที่ในขอบสีแดงที่เห็นในรูป โดยผมประมาณพื้นที่ดังกล่าวเป็นรูปสี่เหลี่ยมขนาด ?? x 21 m. และขนาดที่ประมาณนี้เมื่อเอาภาพในกรอบสีแดงมาคำนวณหา Transformation Matrix เพื่อแปลงจุดในภาพให้กลายเป็นสี่เหลี่ยม เราก็จะสามารถใช้ Transformation Matrix นั้นประมาณตำแหน่งของคนในกรอบสี่เหลี่ยมเพื่อประเมินระยะห่างได้ด้วย

ในบทความนี้ผมประมาณด้วยการเดาล้วนๆ แต่ถ้าจะใช้จริงควรไปวัดจริง หรือไม่ก็มีคนที่ประมาณขนาดจากรูปได้แม่นๆหน่อย

เอาล่ะเริ่มเลยแล้วกัน

Colab OpenPose installation

ก่อนอื่นก็ติดตั้ง Norfair + OpenPose ()บน Colab ก่อนด้วย Script ตามข้างล่าง

pip install norfair[video]

โดยบรรทัดด้านบนเป็นการติดตั้ง Norfair ลงบน colab หลังจากนั้นจะทำการ Clone OpenPose Github ดังนี้

import osfrom os.path import exists, join, basename, splitextgit_repo_url = 'https://github.com/CMU-Perceptual-Computing-Lab/openpose.git'project_name = splitext(basename(git_repo_url))[0]if not exists(project_name):# see: https://github.com/CMU-Perceptual-Computing-Lab/openpose/issues/949# install new CMake becaue of CUDA10!wget -q https://cmake.org/files/v3.13/cmake-3.13.0-Linux-x86_64.tar.gz!tar xfz cmake-3.13.0-Linux-x86_64.tar.gz --strip-components=1 -C /usr/local# clone openpose!git clone -q --depth 1 $git_repo_url!sed -i 's/execute_process(COMMAND git checkout master WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\/3rdparty\/caffe)/execute_process(COMMAND git checkout f019d0dfe86f49d1140961f8c7dec22130c83154 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\/3rdparty\/caffe)/g' openpose/CMakeLists.txt# install system dependencies!apt-get -qq install -y libatlas-base-dev libprotobuf-dev libleveldb-dev libsnappy-dev libhdf5-serial-dev protobuf-compiler libgflags-dev libgoogle-glog-dev liblmdb-dev opencl-headers ocl-icd-opencl-dev libviennacl-dev# install python dependencies!pip install -q youtube-dl

เมื่อเราได้ code ของ OpenPose แล้วก็ download 3rd Party ตัวอื่นๆ ลงใน OpenPose directory

%cd /content/openpose!git submodule update --init --recursive --remote%cd /content/

หลังจากนั้นติดตั้ง library ที่จำเป็นอื่นๆ

!apt-get install python3-dev!pip install numpy opencv-python

เมื่อมาถึงจุดนี้เราก็จะมี source code พร้อมที่จะ compile OpenPose แล้ว เราจำเป็นต้องตั้งค่าให้มีการ compile Python wrapper ด้วย โดยเปลี่ยนค่า BUILD_python ให้เป็น ON ในไฟล์ /content/openpose/CMakeLists.txt ก่อนหลังจากนั้นจึงเริ่ม compile และ install ในขั้นตอนถัดไป

!cd openpose && rm -rf build || true && mkdir build && cd build && cmake .. && make -j`nproc`%cd /content/openpose/build!make install%cd /content/openpose/build/python/openpose!make install

ในขั้นตอน compile ใช้เวลาประมาณ 20–30 นาทีบน Colab และต้องทำทุกครั้งที่ เลิกเขียนทำให้เสียเวลามากในการเริ่มต้นเขียนในแต่ละครั้ง ซึ่งผมพยายามจะ zip directory เพื่อเก็บไว้ใน GDrive แล้วแต่ยังไม่สำเร็จ

import syssys.path.append('/content/openpose/python/openpose')

เมื่อติดตั้ง OpenPose เรียบร้อยแล้ว ให้ run คำสั่งข้างบนเพื่อทำให้ Colab รู้ที่อยู่ของ OpenPose

และในตอนนี้ OpenPose ก็จะพร้อมใช้งาน

Notebook ที่ผมใช้งานสามารถคัดลอกได้จาก https://colab.research.google.com/drive/1Pv3hGcl1mbZBxnWqwYKu-5lXyGFe8D0i?usp=sharing โดยใน Notebook นี้ผมเรียกใช้ OpenPose จาก https://github.com/surapoom/openpose.git ซึ่งผมได้แก้ไขไฟล์ /content/openpose/CMakeLists.txt เพื่อให้ติดตั้ง Python Wrapper แล้ว

Social Distancing

ในกรณีผู้ที่ต้องการดูตัวอย่างการใช้ OpenPose ด้วย Python สามารถดูได้จาก directory /content/openpose/examples/tutorial_api_python

ไฟล์ที่ใช้ในการประเมิน Social Distancing (openpose_social_distance_medium.py)สามารถ download ได้จาก https://drive.google.com/file/d/1uH--sHpDfi5zVWh5qdhc-IS8dJ7AEnUU/view?usp=sharing โดยไฟล์นี้จะ export

  • ภาพตีกรอบสี่เหลี่ยมรอบๆหน้าของคนที่เดินผ่าน
  • ไฟล์ภาพหน้าคนแต่ละคนที่อยู่ในพื้นที่ที่กำหนดแยกออกมา ตาม frame ของวีดีโอ และ id ที่ทำการ track ได้
  • ไฟล์ csv แสดงค่า distance ของคนที่มีระยะใกล้เกินกว่าค่า Threshold ในแต่ละ frame
  • ไฟล์ csv แสดงค่าความหนาแน่นของคนในพื้นที่กรอบสี่เหลี่ยมในแต่ละ frame

เพื่อความกระชับของบทความผมจะไม่อธิบายรายละเอียดของโปรแกรม แต่จะกล่าวถึงแนวคิดและวิธีการใช้งานอย่างคร่าวๆ

การตั้งค่าที่จำเป็นจะมีอยู่ 2 ช่วงสำคัญๆดังนี้

# Insert the path to your openpose instalation folder hereopenpose_install_path = "/content/openpose/python"detection_per_seconds = 0frame_skip_period = 1detection_threshold = 0.7distance_threshold = 0.4min_p_dist = 2.0     # meter in distance between persons# for detecting feet and faceminimum_detection_scores = 0.7    # check maximum of all partsminimum_part_detection_scores = 0.5image_out_path = '/content/'video_path = '/content'video_out_path = '/content/'

ในช่วงที่ 1 บรรทัดที่ 444–458 โดยตั้งค่าดังนี้

detection_per_seconds = 0frame_skip_period = 1

ค่า detection_per_seconds หากมีค่ามากกว่า 0 โปรแกรมคำนวณค่า frame_skip_period (ค่าการ skip เฟรมของวีดีโอ) เพื่อให้ทำการตรวจจับภาพจากวีดโอตามจำนวนที่ตั้งค่าต่อวินาที

detection_threshold = 0.7distance_threshold = 0.4

ค่า detection_threshold ใช้เพื่อกำหนดค่าให้กับ Norfair ใช้ในการพิจารณาว่าจุดที่ OpenPose ตรวจจับได้ต้องมีค่าคะแนนความน่าจะเป็นขั้นต่ำเท่าไหร่ ส่วนค่า distance_threshold เป็นค่าความแตกต่างที่ยอมรับได้ว่าเป็นคนๆเดียวกันระหว่างภาพในเฟรมปัจจุบันกับภาพในเฟรมที่ผ่านมา

min_p_dist = 2.0

ค่า min_p_dist ใช้เพื่อตั้งระยะห่างระหว่างคนสองคน หากระยะห่างมีค่าน้อยกว่าค่าดังกล่าวโปรแกรมจะทำการรายงานออกมายัง human_distance.csv

minimum_detection_scores = 0.7    # check maximum of all partsminimum_part_detection_scores = 0.5

ค่า minimum_detection_scores ใช้สำหรับตรวจจับค่าความน่าจะเป็นสูงสุดของกลุ่มตำแหน่งต่ำแหน่งของมนุษย์ที่ตรวจจับได้จาก OpenPose ว่าเป็นการตรวจพบคน ส่วนค่า minimum_part_detection_scores ใช้เป็นค่าความน่าจะเป็นขั้นต่ำในการยอมรับการตรวจจับตำแหน่งต่างๆของมนุษย์

image_out_path = '/content/'video_path = '/content'video_out_path = '/content/'

ในส่วนของ path ต่างๆข้างบนใช้เพื่อระบุ path ปลายทางสำหรับการเขียนรูปออก

ในช่วงที่ 2 จะอยู่ในช่วงบรรทัดที่ 528–533

# Perspective Transform settingorg_width, org_length = 9.0, 9.0      #m.transform_scale = 100                 #pixel / m.boundary_pts = [[1002, 215], [1690, 309], [1296, 899], [254, 625]]pts_org = np.array(boundary_pts, dtype=np.float32)boundary_area = org_width * org_length

โดยค่า org_width, org_length ใช้เพื่อระบุความกว้าง ความยาวของสี่เหลี่ยมในโลกจริง transform_scale ใช้เพื่อกำหนดสเกลสำหรับภาพที่ปรับแล้ว boundary_pts คือจุด 4 จุดที่เป็นมุมของสี่เหลี่ยมในภาพ

โดยโปรแกรมจะคำนวณหา transformation matrix ด้วยฟังก์ชั่น cv2.getPerspectiveTransform(pts_in_frame, pts_in_top_view) และโปรแกรมจะใช้ transformation matrix นี้ในการประเมินตำแหน่งของคนแต่ละคนในภายหลัง

ทั้งนี้โปรแกรมจะทำส่งเฟรมของวีดีโอไปยัง OpenPose เพื่อตรวจจับหาจุดต่างๆของคน โดยค่าที่ OpenPose ส่งกลับมาเป็น Array ขนาด 25 rows ซึ่งเป็นตัวแทนของจุดต่างของคนโดยที่ค่าที่ส่งกลับมาประกอบด้วย ตำแหน่ง x, y และ score สำหรับจุดต่างๆแต่ละจุดได้แก่

{0,  "Nose"},{1,  "Neck"},{2,  "RShoulder"},{3,  "RElbow"},{4,  "RWrist"},{5,  "LShoulder"},{6,  "LElbow"},{7,  "LWrist"},{8,  "MidHip"},{9,  "RHip"},{10, "RKnee"},{11, "RAnkle"},{12, "LHip"},{13, "LKnee"},{14, "LAnkle"},{15, "REye"},{16, "LEye"},{17, "REar"},{18, "LEar"},{19, "LBigToe"},{20, "LSmallToe"},{21, "LHeel"},{22, "RBigToe"},{23, "RSmallToe"},{24, "RHeel"},{25, "Background"}

หลังจากนั้นโปรแกรมจะส่งค่า Array ไปยัง Norfair เพื่อทำการ track คนแต่ละคนในแต่ละเฟรม หลังจากนั้นจะส่งค่าของคนแต่ละคนไปประเมินตำแหน่งของเท้า โดยเบื้องต้นโปรแกรมจะหาตำแหน่งของเท้าโดยตรงก่อน หากไม่พบจะทำการประมาณด้วยการใช้สัดส่วนของคนตามภาพด้านล่าง

เมื่อได้ตำแหน่งของเท้ามาแล้วจะใช้ transformation matrix เพื่อหาตำแหน่งของเท้าในภาพ Top View เพื่อคำนวณระยะห่างต่อไป

ในการใช้งานพบว่าโปรแกรมทำงานช้ากว่า Yolo ค่อนข้างมาก อย่างไรก็ตามการได้ตำแหน่งของคนน่าจะสามารถใช้งานต่างๆได้อีกมาก นอกจากนี้การ tracking ด้วย Norfair พบว่าหากคนอยู่ใกล้กับกล้องมาก จะทำให้การเคลื่อนที่เชิง pixel มีค่ามาก ซึ่งจะทำให้ไม่สามารถ skip frame ได้มากนัก รวมถึง Norfair ใช้ KalmanFilter ในการประมาณตำแหน่งของเฟรมถัดไป ซึ่งหากความเร็วในภาพมีการเปลี่ยนแปลงฉับพลันจะทำให้ระบบ tracking มีปัญหาค่อนข้างมาก

--

--