Contours in OpenCV

จาก Morange Wiki
รุ่นแก้ไขเมื่อ 03:38, 8 สิงหาคม 2559 โดย Patcharapun (คุย | มีส่วนร่วม) (fix center)
(ต่าง) ←รุ่นแก้ไขก่อนหน้า | รุ่นแก้ไขล่าสุด (ต่าง) | รุ่นแก้ไขถัดไป→ (ต่าง)

เนื้อหา

Contours : Getting Started

วัตถุประะสงค์

  • เข้าใจว่าอะไรคือ Contour (เส้นชั้น ความสูง)
  • รู้วิธีการเขียนเส้นชั้นความสูงและหาเส้นชั้นความสูง
  • เรียนรู้การใช้งานฟังก์ชั่น : cv2.findContours(), cv2.drawContours()

อะไรคือ เส้นชั้นความสูง

  • รูปทรงที่สามารถอธิบายได้ว่า เส้นไหนเป็นเส้นโค้งโดยร่วมแบบต่อเนื่อง โดยมีสีที่หรือความเข้มของรูปทรงที่เป็นเส้นชั้น ในการใช้นั้น จะมีีเครื่องมือที่มีประโยชน์ที่เหมาะสำหรับการวิเคราะห์รูปทรงและการตรวจสอบวัตถุและการเรียนรู้
    • เพื่อความถูกต้องดีกว่าใช้ภาพไบนารี ดังนั้นก่อนที่จะหาเส้นชั้นความสูง ควรใช้เกณฑ์ในการตรวจหาด้วย Canny Edge Detection
    • ฟังก์ชั่น findContours จะปรับเปลี่ยนภาพที่นำเข้ามา ดังนั้นหากคุณต้องการทั้งภาพที่นำเข้าและภาพที่หาเส้นชั้นความสูงแล้ว จะต้องนำไปเก็บไว้เป็นตัวแปรอื่นๆ
    • ใน OpenCV การหาเส้นชั้นความสูงเป็นเหมือนการหาวัตถุสีขาวจากพื้นหลังสีดำ ดังนั้นจำวัตถุที่จะพบควรเป็นสีขาวและพื้นหลังควรเป็นสีดำ

CODE

import numpy as np
import cv2

im = cv2.imread('test.jpg')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

วิธีการวาดเส้นชั้นความสูง

การวาดรูปเส้นชั้นความสูง ฟังก์ชั่น cv2.drawContours() ถูกนำมาใช้ นอกจากนี้ยังสามารถใช้ในการวาดรูปทรงใด ๆ ที่ให้คุณมีจุดเขตแดน อาร์กิวเมนต์แรกคือภาพที่ต้นฉบับที่นำเข้ามาส่วนอาร์กิวเมนต์ที่สองภาพที่แสดงเส้นชั้นความสูงที่ควรจะผ่านเป็นโปรแกรม Python ในอาร์กิวเมนต์ที่สามคือดัชนีของเส้นชั้นความสูง (มีประโยชน์เมื่อวาดเส้นชั้นความสูงของแต่ละส่วน. ในการวาดเส้นชั้นความสูงทั้งหมดผ่านมีค่า -1) และข้อโต้แย้งที่เหลือเป็นสีและความหนา เป็นต้น

การวาดรูปเส้นชั้นความสูง
cv2.drawContours(img, contours, -1, (0,255,0), 3)
สำหรับการวาด Individual Contour
cv2.drawContours(img, contours, 3, (0,255,0), 3)
แต่ส่วนมากของเวลาที่ด้านล่างวิธีการจะเป็นประโยชน์:
cnt = contours[4]
cv2.drawContours(img, [cnt], 0, (0,255,0), 3)

วิธีการประมาณเส้นชั้นความสูง

  • นี่คืออาร์กิวเมนต์ที่สามของฟังก์ชั่น cv2.findContours มันจะมีอะไรแสดงได้จริง?
  • ข้างต้นที่เราบอกว่าขอบเขตเส้นชั้นความสูงของรูปทรงที่มีความเข้มข้นเหมือนกัน โดยจะเก็บ (x, y) พิกัดเขตแดนของรูปร่าง แต่ไม่ได้เก็บพิกัดทั้งหมด ที่ระบุไว้นั้นจะได้โดยวิธีการประมาณ เส้นชั้นความสูงนี้
  • ด้านล่างภาพของรูปสี่เหลี่ยมผืนผ้า แสดงให้เห็นถึงเทคนิคนี้ เพียงแค่ วาดวงกลมบนพิกัดทั้งหมดในอาร์เรย์รูปร่าง (วาดเส้นสีฟ้า) ภาพแรกแสดงให้เห็นถึงจุดที่มี
    • cv2.CHAIN_APPROX_NONE (734 จุด)
และภาพที่สองแสดงให้เห็นว่าเป็นในแนวเดียวกัน
    • cv2.CHAIN_APPROX_SIMPLE (เฉพาะ 4 จุด) มาดูกันว่าวิธีไหนจะประหยัดการใช้ memory กว่ากัน


None.jpg


Contour Features

วัตถุประสงค์

  • เพื่อหาสิ่งที่คุณสมบัติแตกต่างกันของรูปทรงเส้นความสูงเช่นพื้นที่, ปริมณฑล, เซนทรอยด์, กล่อง ฯลฯ
  • จะได้เห็นทุกๆฟังก์ชั่นแบบเต็มรูปแบบ

Moments

  • Image Moment จะช่วยเรื่องการคำนวณ โดยบาง Features เหมือนจุดศูนย์กลางมวลของวัตถุพื้นที่ของวัตถุ ฯลฯ ตรวจสอบหน้าวิกิพีเดียในช่วงเวลาที่ภาพ
  • โดยฟังก์ชั่น cv2.moments() จะให้ทั้งหมดของ dictionary ของค่าที่คำนวณ

Example Code

import cv2
import numpy as np

img = cv2.imread('star.jpg',0)
ret, thresh = cv2.threshold(img,127,255,0)
contours , hierarchy = cv2.findContours(thresh,1,2)

cnt = contours[0]
M = cv2.moments(cnt)
print M

จาก Moment นี้ คุณจะเห็นได้ชัดว่าข้อมูลของพื้นที่ , centroid และอื่นๆนั้น จะมีค่าความสัมพันธ์ ตามสูตร คือ Selection 068.png

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])

Contour Area

  • ในฟังก์ชั่นนี้จะได้ พื้นที่ของเส้นชั้นความสูงโดย ใช้คำสั่งที่ชื่อว่า cv2.contourArea() หรือ ได้จาก M['m00']
area = cv2.contourArea(cnt)

Contour Perimeter

  • นอกจากนี้ยังเรียกใช้ฟังก์ชั้นเพื่อหาค่า arc length โดยจะใช้คำสั่ง cv2.arcLength() และใช้ 2 parameter หรือ 2 argument ในการเรียกใช้
perimeter = cv2.arcLength(cnt,True)

Contour Approximation

Example Code

epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)

Result

Approx.jpg

Convex Hull

Image Example

Convexitydefects.jpg

Code

hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
และ
hull = cv2.convexHull(cnt)

Checking Convexity

  • เป็นฟังก์ชั่นการตรวจสอบว่าเป็นเส้นโค้งนูนหรือไม่ ใช้คำสั่งชื่อว่า cv2.isContourConvex()

Code Example

k = cv2.isContourConvex(cnt)

Bounding Rectangle

Straight Bounding Rectangle

Code Example

x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

Rotated Rectangle

Code Example

rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(0,0,255),2)

Image Result

Boundingrect.png

Minimum Enclosing Circle

  • ในการทำวงกลมล้อมรอบ Object นั้นทำได้ด้วยคำสั่งชื่อว่า cv2.minEnclosingCicle()

Code Example

(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv2.circle(img,center,radius,(0,255,0),2)

Image Result

Circumcircle.png

Fitting an Ellipse

  • ในการวาดลงรีทับนั้นใช้คำสั่งดังด้านล่างนี้

Code Example

ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img,ellipse,(0,255,0),2)

Image Result

Fitellipse.png

Fitting a Line

  • เรื่องนี้จะเป็นการวาดเส้นทับรูปภาพ

Code Example

rows,cols = img.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

Image Result

Fitline.jpg



Contour Properties

  • ในบทนี้ จะเรียนรู้เกี่ยวกับคุณสมบัติของ Contour ว่า Object อะไรบ้าง เช่น Solidity, Equivalent Diameter, Mask image, Mean Intensity เพิ่มเติมที่ : [เพิ่มเติม]

Aspect Ratio

  • เรื่องการหาอัตราส่วนของความกว้างความสูง และขอบเขตของวัตถุ ตามสูตร
AspectRatio=Width/Height

Code Example

x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w)/h

Extent

  • ขอบเขตของอัตราส่วนพื้นที่สี่เหลี่ยมผืนผ้า ตามสูตร
Selection 070.png

Code Example

area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area

Solidity

  • ค่าความแข็งแรงคือ อัตราส่วนของพื้นที่เส้นแสดงรูปร่างการนูนออกของพื้นที่ ตามสูตร
Selection 072.png

Code Example

area= cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area

Equivalent Diameter

  • การหาเส้นผ่าศูนย์กลางของวงกลมนั้น ทำได้เหมือนกันกับการหาพื้นที่เส้นแสดงรูปร่าง ตามสูตร
Selection 073.png

Code Example

area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)

Orientation

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

Code Example

(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)

Mask and Pixel Points

  • วิธีนี้ ทุกๆจัดต้องประกอบด้วยวัตถุ สามารถทำได้ดังนี้

Code Example

mask = np.zeros(imgray.shape,np.uint8)
cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv2.findNonZero(mask)

Maximum Value, Minimum Value and their locations

  • ในบทนี้จะสามารถหาค่าพารามิเตอร์โดยการใช้ mask image

Code Example

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)

Mean Color or Mean Intensity

  • หัวข้อนี้สามารถหาสีที่มีค่าเฉลี่ยของวัตถุ หรืออาจใช้ความเข้มเฉลี่ย ของวัตถุในโหมดสีเทา อาจจะใช้วิธีเดียวกันกับ mask image

Code Example

mean_val = cv2.mean(im,mask = mask)

Extreme Points

  • จุดที่สูงที่สุดหมายถึง Topmost , Bottommost , rightmost , leftmost หรือ จุดสุดท้ายของแต่ละด้าน ของวัตถุ

Code Example

leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])

Result Extream Point

Extremepoints-non.jpg



Contours : More Functions

วัตถุประสงค์

  • เพื่อหาข้อบกพร่องนูนและวิธีการที่จะพบ
  • การหาระยะทางที่สั้นที่สุดจาก A ไปหา เหลี่ยม
  • จับคุ่รูปร่างที่แตกต่าง

Convexity Defects

  • ในการสิ่งที่เป็นเปลือกนูนในบทที่ 2 ของ Contour นั้น ทุกๆ การเบี่ยงเบนของ Object นั้น จะถือเป็นข้อบกพร่องของการนูน
  • โดย OpenCV จะนำมีฟังก์ชั้นเกี่ยวกับเรื่องนี้มาด้วย นั้นคือฟังก์ชั่น cv2.convexityDefects()

Code การใช้ฟังก์ชั่น

hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)

Code เต็ม

import cv2
import numpy as np
 
img = cv2.imread('star.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[0]
 
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
 
for i in range(defects.shape[0]):
    s,e,f,d = defects[i,0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv2.line(img,start,end,[0,255,0],2)
    cv2.circle(img,far,5,[0,0,255],-1)

cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
ขอบคุณรูปภาพจาก OpenCV.org

Point Polygon Test

  • ฟังก์ชั่นนี้จะหาระยะทางที่สั้นที่สุดระหว่างจุดในภาพและเส้นแสดงรูปร่าง โดยกลับระยะทางที่เป็นลบเมื่อจุดนั้นอยู่นอกเส้นบวก
    • ยกตัวอย่างการหาค่า (50,50)

Code Example

dist = cv2.pointPolygonTest(cnt,(50,50),True

Match Shapes

  • การหารูปร่างที่ตรงกัน โดยจะใช้ฟังก์ชั่น cv2.matchShapes() เพื่อเปิดการหาภาพที่ตรงกันทั้งสองภาพ มี Code ดังนี้

Code Example

import cv2
import numpy as np
 
img1 = cv2.imread('star.jpg',0)
img2 = cv2.imread('star2.jpg',0)
 
ret, thresh = cv2.threshold(img1, 127, 255,0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv2.findContours(thresh2,2,1)
cnt2 = contours[0]

ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
print ret

Result

ขอบคุณรูปภาพจาก OpenCV.org
  • ผลลัพธ์ที่ได้เป็นค่าคือ
    • รูป A กับ A = 0.0
    • รูป A กับ B = 0.001946
    • รูป A กับ C = 0.326911


Contours Hierarchy

วัตถุประสงค์

  • เรียนรู้เกี่ยวกับลำดับชั้นของรูปทรงที่ i.e มีความสัมพันธ์กับ parent-child ใน Contour

Hierarchy?

  • โดยตกติจะใช้ฟังก์ชั่น cv2.findContours() เพื่อตรวจจับวัตถุของรูปภาพที่นำเข้ามา แต่บางครั้ง วัตถุอื่นที่อยู่คนละ location เดียวกัน ในวิธีนี้บาง object อาจอยู่ในอีก object โดยการหา Parent และในนั้นเป็น child นั้นว่าทั้งสองมีความสัมพันธ์กันอย่างไรมีการเชื่อมต่อกับแบบไหนอย่างไร ทั้งหมดนั้นคือ Hierarchy
ขอบคุณรูปภาพจาก OpenCV.org

Hierarchy Representation in OpenCV

  • ในการหาเส้นรูปร่างของสารสนเทศที่นำเข้ามานั้นเพื่อหาว่าใครเป็น โน๊ดแม่ โน๊ดลูก (Parent-Child) ใน OpenCV จะแสดง Array of four values ออกมา จะเห็นได้ในโค๊ดตัวอย่างในหัวข้อ Contour Retrieval Mode

Contour Retrieval Mode

1. RETR_LIST

  • ในการยกตัวอย่างเรื่องนี้ จะยกตัวอย่างการผลลัพธ์ที่งมดที่ได้จาก Contour แต่จะไม่มีการสร้างความสัมพันธ์ของ Parent - Child ทั้งสั้น โดยกล่าวได้ว่า
  • Parents and kids are equal under this rule, and they are just contours

ยกตัวอย่าง CODE

 >>> hierarchy
 array([[[ 1, -1, -1, -1],
         [ 2,  0, -1, -1],
         [ 3,  1, -1, -1],
         [ 4,  2, -1, -1],
         [ 5,  3, -1, -1],
         [ 6,  4, -1, -1],
         [ 7,  5, -1, -1],
         [-1,  6, -1, -1]]])

2. RETR_EXTERNAL

  • ในเรื่องนี้จะหาค่าจุดสุดท้ายของแต่ละด้าน กล่าวได้ว่า
  • We can say, under this law, Only the eldest in every family is taken care of. It doesn't care about other members of the family :)

ยกตัวอย่าง CODE

 >>> hierarchy
 array([[[ 1, -1, -1, -1],
         [ 2,  0, -1, -1],
         [-1,  1, -1, -1]]])

3. RETR_CCOMP

  • เรื่องนี้จะแสดงเส้นแสดงรูปร่างของการจัดวางของ 2-level hierachy ยกตัวอย่างว่า วัตถุที่อยู่นอก object และอยู่ใน Object ดังกล่างโดยสามารถดูรูปเพื่อทำความเข้าใจ ในเรื่องนี้ได้

ยกตัวอย่างรูปภาพ

ขอบคุณรูปภาพจาก OpenCV.org

ยกตัวอย่าง CODE

>>> hierarchy
 array([[[ 3, -1,  1, -1],
         [ 2, -1, -1,  0],
         [-1,  1, -1,  0],
         [ 5,  0,  4, -1],
         [-1, -1, -1,  3],
         [ 7,  3,  6, -1],
         [-1, -1, -1,  5],
         [ 8,  5, -1, -1],
         [-1,  7, -1, -1]]])

4. RETR_TREE

  • ในบทนี้จะใช้ฟังก์ชั่น cv2.RETR_TREE เพื่อหาการเรียงลำดับของรูปทรงที่ผลลัพธ์จาก OpenCV โดยจะวิเคราะห์อีกครั้ง โดยข้อความสีแดงจะจะบอก ตัวเลขของ Contour และ ข้อความสีเขียวจะบอก ลำดับชั้นของความสัมพันธ์ (hierarchy)

ยกตัวอย่างรูปภาพ

ขอบคุณรูปภาพจาก OpenCV.org

ยกตัวอย่าง CODE

>>> hierarchy
 array([[[ 7, -1,  1, -1],
         [-1, -1,  2,  0],
         [-1, -1,  3,  1],
         [-1, -1,  4,  2],
         [-1, -1,  5,  3],
         [ 6, -1, -1,  4],
         [-1,  5, -1,  4],
         [ 8,  0, -1, -1],
         [-1,  7, -1, -1]]])