SKCONAN

เขียนโปรแกรมตรวจหาสีด้วย OpenCV

January 24, 2019

title

ภาพที่จะพูดถึงในบทความจะมีความลึกของสีอยู่ที่ 8-bit หรือมีค่า intensity อยู่ระหว่าง 0 - 255

Color detection

Color detection คือ การตรวจหาสีที่เราต้องการในภาพ โดยภาพที่เราเห็นปกติทั่วไปจะอยู่ในโหมด RGB

ในทาง image processing โหมดสีต่างๆ เราจะเรียกเป็น color model ซึ่งไม่ได้มีแค่ RGB เท่านั้น แต่ยังมี model อื่นๆอีก เช่น HSV, Lab, และ HSL เป็นต้น รายละเอียดเพิ่มเติมของ Color model

ตอนนี้เราก็รู้จัก color model กันคร่าวๆละ เราจะย้อนกลับไปที่ภาพ RGB ปกติก่อน แล้วลองจินตนาการดูว่าในแต่ละ Pixel ในภาพมันควร ประกอบไปด้วยค่าทั้งหมดกี่ค่า

ขอเน้นตรงนี้หน่อยนะครับ

ในการอธิบายจะใช้ rgb model นะครับ แต่จริงๆแล้ว OpenCV จะใช้ model สีเป็น BGR นะครับไม่ใช่ RGB

คำตอบ คือ 3 ค่า เหมือนกับเรามีสีแดง(R) สีเขียว(G) และสีน้ำเงิน(B) แล้วก็ผสมทั้ง 3 สีเข้าด้วยกันในปริมาณที่ต่างกัน เพื่อให้ได้ Pixel ที่มีสีที่เราต้องการ เช่น อยากได้สีแดง ค่าที่ได้ก็จะเป็น (255, 0, 0) เป็นต้น

rgb

ตอนนี้ถ้าเราอยาก detect ส่วนสีแดงของรถ sport คันขวา เราจะหาค่าของสีแดงทุก Pixel ยังไงดีละ ถ้าจะนั่งผสมสี แล้วก็ปรับค่า r g b ไปเรื่อยๆก็คงไม่ work เพราะ จากรูปข้างบนจะเห็นว่าค่า r ลดเหลือ 83 ค่า g กับ b เท่ากับ 1 เราจะหาค่าสีเป๊ะๆ ของทุก pixel ได้ไงใช่มั้ยครับ

ทำให้โลกนี้เกิด color model ที่ชื่อว่า HSV ขึ้นมา (อันนี้เว่อไปๆ แต่มันก็ดีจริง) โดยแบ่งเป็น 3 ค่าเหมือนกัน

hsv
H (Hue) เป็นค่าสี 0 - 180
S (Saturation) เป็นค่าบริสุทธิ์ของสี (สีขาวผสมกับ Hue) 0 - 255
V (Value) เป็นค่าความสว่าง 0 - 255

ค่าของแต่ละ channel ยึดตาม OpenCV นะครับ คราวนี้ถ้าเราอยากได้สีแดงตรงรถ sport ก็แค่กำหนด H เป็น 160 - 180 แล้วก็ปรับค่า S กับ V เอาจะเห็นว่าง่ายกว่าเยอะเลย เพราะ สีถูกกำหนดโดย Hue ตัวเดียว

ทีนี้เราลองมาเขียนโค้ดกันดีกว่าครับ โดย OpenCV จะมี function cv2.inRange(image, lower, upper) สำหรับการตรวจหา Pixel ที่มีค่าสีอยู่ในช่วงที่เรากำหนด

โดย lower และ upper จะเก็บอยู่ในรูปแบบ numpy array เดี๋ยวจะยกตัวอย่างให้ดูนะครับ

และ return ผลลัพธ์เป็น binary image หรือเรียกอีกอย่างว่า mask โดยสีขาว คือ pixel ที่มีค่าสีอยู่ในช่วงที่เรากำหนด ส่วน pixel อื่นๆจะเป็นสีดำหมดเลย

ยกตัวอย่าง เราอยากตรวจหาสีเขียว เราก็จะกำหนด

lower = np.array([38,0,0])

upper = np.array([75,255,255])

ทีนี้เรามาดูโค้ดกันแบบเต็มๆเลยครับ

import cv2 as cv
import numpy as np

img = cv.imread(r".\car.png")
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)

upper = np.array([180,255,255],np.uint8)
lower = np.array([160,0,0],np.uint8)
result = cv.inRange(hsv,lower,upper)

cv.imshow('img',img)
cv.imshow('hsv',hsv)
cv.imshow('result',result)
cv.waitKey(-1)

อันนี้ก็จะเป็นภาพรถ กับผลลัพธ์ที่ได้นะครับ

title
result

จากผลลัพธ์จะเห็นว่า เราไม่ได้สีแดงทั้งหมด เพราะ ว่าตรงส่วนนั้นอาจเกิดจากค่า H ของสีส้มถ้าดูจากรูปล่างที่ H = 0 มันจะออกแดงๆส้มๆ บวกกับการปรับค่า S กับ V ก็จะทำให้ได้ Pixel บริเวณที่ขาดหายไป

hue

ซึ่งตรงนี้ก็เป็นหนึ่งในข้อเสียของ HSV color model มีข้อดีก็ต้องมีข้อเสียนะครับ แต่เราแก้ไขได้ด้วยการ หาช่วงของสีเหลืองเพิ่ม แล้วเอามารวมกันลองไปทำกันดูนะครับ ตอนรวมให้ใช้ resultRed + resultYellow ได้เลยนะครับ โดย resultRed กับ resultYellow คือ ผลลัพธ์จาก function inRange

หากใครชอบเนื้อหาที่ผมเขียน สามารถร่วมกัน Donate เพื่อเป็นค่ากาแฟได้นะครับ ^^


ใครที่สงสัยจุดไหน หรือพบว่าจุดไหนที่ผมอธิบายผิด สามารถเข้ามาพูดคุยกันได้นะครับ inbox มาที่ Facebook, Twitter เลยก็ได้ครับ หรือ mail มาที่ supakit.kr@gmail.com จะยินดีมากเลยครับ



Written by Supakit Kriangkhajorn

© 2019, Built with