ต่อจาก Part ที่แล้วในส่วนถัดไปจะเป็นการทำงานของ BlobAnalysis โดยมีการทำงานดังนี้
- ทำการวน Loop ตามความยาวของ array cs
- ส่งค่า array cs ชุดที่ i ไปที่ class BlobAnalysis เพื่อเตรียมการคำนวณ
ในที่นี้ cs[i] ที่ส่งเข้ามาจะถูกเก็บในตัวแปรชื่อ contour ซึ่ง self.contour ก็คือการเก็บค่า contour ไว้ใช้ใน class
self.contour_s คือตัวแปรที่เก็บค่า contour ซึ่งถูกปรับการเรียงเป็นแนวตั้ง และ squeeze() คือการลบ array นอกสุดออก 1 มิติ เช่น หากข้อมูลมีลักษณะเป็น [ [1,2] ] array ตัวนอกจะถูกลบออก
1 มิติ กลายเป็น [ 1,2 ] แทน
self.contour_point จะไปเรียกฟังค์ชันซึ่งทำการนำ array self.contour_s มาแปลงค่าเป็น numpy array เป็น python list เพื่อให้สามารถทำการคำนวณใน python ได้ง่ายขึ้น
self.centroid จะไปเรียกฟังค์ชัน get_centroid() เพื่อนำค่า self.contour ไปคำนวณ Moment เพื่อนำมาหาจุดศูนย์กลางของข้อมูล ผลที่ได้จะเป็นลักษณะคู่อันดับ (x,y)
self.convex_hull จะเรียกฟังค์ชัน get_convex_hull โดยจะนำ self.contour มาทำการหา hull หรือส่วนโค้งเว้าใน contour นำมาคำนวณเพื่อเก็บใส่ตัวแปร epsilon และนำ hull กับ epsilon ไปเพื่อปรับค่า contour ในคำสั่ง cv2.approxPolyDP(convexHull,epsilon,True) และปรับการเรียงเป็นแนวตั้งพร้อมลบ array นอกสุดออก 1 มิติ และแปลงค่าจาก numpy array เป็น python list ก่อนทำการเก็บค่า
self.approx_hull_count จะทำการเก็บค่าความยาว self.convex_hull ไว้
self.id กำหนดให้มีค่าเป็น -1
self.area ทำการเก็บค่าพื้นที่ของ contour ด้วยคำสั่ง cv2.contourArea(self.contour)
self.deflect_count_90 จะเรียกฟังค์ชัน get_deflect_count(90) โดยค่าที่ส่งไปคือมุมที่เราต้องการทำไปคิด และนำ self.contour มาหา convex_hull จากนั้นนำ contour กับ hull มาทำการหา deflect ของภาพ จากนั้นจะนำ deflect มาทำการคำนวณหามุม และเข้าเงื่อนไขเพื่อเช็คว่าค่ามุมที่หามาได้น้อยกว่าหรือเท่ากับ 90 หรือไม่ ซึ่งก็คือการหามุมระหว่างร่องมือ หากไม่ถึง 90 จะเพิ่มค่า count 1 ค่า คนครบทุกตัว และเก็บค่า count ไป
self.isHand จะเรียกคำสั่ง self.check_isHand() ซึ่งจะนำค่า self.deflect_count_90 มาเข้าเงื่อนไขว่ามีค่า == 4 หรือไม่ ซึ่งเป็นการเปรียบเทียบว่า มือเรานั้นจะมีร่องมือเพียง 4 ร่องเท่านั้น หากมีค่าเท่ากับ 4 พอดีแสดงว่า blob ที่ได้มานั้นเป็นรูปมือจริงๆ จะทำการเก็บค่าเป็น True หากมีค่ามากกว่า 4 หรือน้อยกว่า 4 แสดงว่าไม่ใช่มือ เป็นอันเสร็จสิ้นการทำงานส่วนเก็บค่าตัวแปร
แหล่งอ้างอิง
squeeze :
https://www.tutorialspoint.com/numpy/numpy_squeeze.htm
np.vstack :
https://www.tutorialspoint.com/numpy/numpy_vstack.htm
np.array().tolist()
https://stackoverflow.com/questions/1966207/converting-numpy-array-into-python-list-structure
moment, epsilon, convexHull :
https://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html
https://www.learnopencv.com/find-center-of-blob-centroid-using-opencv-cpp-python/
โค้ดส่วนที่ทำงาน
class BlobAnalysis:
def __init__(self,contour):
self.contour = contour
self.contour_s = np.vstack(contour).squeeze()
self.contour_point = self.get_contour_point()
self.centroid = self.get_centroid()
self.convex_hull = self.get_convex_hull()
self.approx_hull_count = self.get_approx_hull_count()
self.id = -1
self.area = cv2.contourArea(self.contour)
self.deflect_count_90 = self.get_deflect_count(90)
self.isHand = self.check_isHand()
def set_id(self,i):
self.id = i
def get_contour_point(self):
return np.array(self.contour_s).tolist()
def get_centroid(self):
m = cv2.moments(self.contour)
cX = int(m['m10'] / m['m00'])
cY = int(m['m01'] / m['m00'])
return (cX, cY)
def get_convex_hull(self):
convexHull = cv2.convexHull(self.contour)
epsilon = 0.015*cv2.arcLength(convexHull,True)
approx = cv2.approxPolyDP(convexHull,epsilon,True)
approx = np.vstack(approx).squeeze()
return np.array(approx).tolist()
def get_approx_hull_count(self):
approx = self.convex_hull
return len(approx)
def get_deflect_count(self,max_angle):
count = 0
hull = cv2.convexHull(self.contour,returnPoints = False)
defects = cv2.convexityDefects(self.contour, hull)
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = self.contour_s[s]
end = self.contour_s[e]
far = self.contour_s[f]
a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)
c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2)
angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57
if angle <= max_angle:
count += 1
return count
def check_isHand(self):
if self.deflect_count_90 == 4 :
return True
else:
return False