เร็วๆ นี้ผมได้รับผิดชอบ Project หนึ่งที่ต้องการเครื่องมือช่วยตัดภาพพื้นหลังออกจากรูปภาพสินค้าก่อนจะนำเข้าระบบส่วนกลาง หลังจากทำ POC ด้วย OpenCV บน OSX แล้ว พอจะขึ้นแอปจริงๆ จะต้องทำบน Windows ดังนั้นจะหันมาใช้ EmguCV แทน รายละเอียด EmguCV ดูได้ที่นี่
อย่างที่ Developer รู้กันดีครับว่าการทำ POC กับทำโปรดักต์นั้นต่างกันคนละขั้ว ดังสโลแกนที่ว่า Devil is in detail นะแหละ พอเริ่มทำแล้วจึงเจอปัญหาเรื่อยๆ โดยเฉพาะเรื่อง document เข้าใจเลยว่าศาสตร์ของ Image Processing นั้นทำไมถึงมีคนเข้าถึงได้น้อยก็เพราะไม่มี document นี่แหละ มีตัวอย่างให้ดูนิดเดียวถ้าจะต่อยอดต้องอาศัยจินตนาการและประสบการณ์ต่อยอดเอาเองนะจ๊ะ เอาหล่ะเดี๋ยววันนี้จะหยิบเอาปัญหาเรื่องสุดท้ายที่เจอก่อนเสร็จโปรเจ็กต์นั่นคือ พอตัดภาพแล้วเลือกพื้นที่ที่จะบอกระบบว่าให้เอาเฉดสีส่วนนี้ด้วยนะ ซึ่งมันก็ทำงานได้นะแต่ดันทำเกินตรงที่แถมมาสก์เป็นเส้นสีดำขีดทับภาพผลลัพธ์เกินมาให้ด้วยหน่ะสิ
Application concept
นำภาพตั้งต้นมาตัดพื้นหลังที่ไม่ต้องการออกไปได้
เริ่มทำการตัดพื้นหลัง
ใน EmguCV จะมีเมดทรอดที่เอาไว้ทำเรื่อง Image segmentation/Interactive Foreground Extraction หรือตัดพื้นหลังออกจากภาพ มีชื่อว่า GrabCut วิธีใช้งานง่ายเลยคือ เลือกพื้นที่สี่เหลี่ยมคลอบพื้นที่องค์ประกอบหลัก ได้ผลลัพธ์ตามด้านล่าง จะเห็นได้ว่าพื้นที่ตรงกลางของภาพดันเป็นสีขาวเฉดเดียวกับ Background ที่ระบบจะตัดออก
เลือกพื้นที่เพื่อบอกให้ระบบรู้ว่าคือเฉดสีที่ต้องการเก็บไว้
ซึ่งมีวิธีที่โดยให้ระบบเส้นตำแหน่งที่จะเก็บส่วนนั้นไว้และเทียบเฉียดรอบๆ ออกไปอีกหน่อย โดยทำ POC บน OpenCV พอทำขั้นตอนนี้จะได้ภาพผลลัพธ์ตามแบบที่เห็นใน Application Concept เลย แต่เจ้า EmguCV กลับเจอปัญหาว่าจะยังเก็บมาสก์หรือเส้นที่เราระบายลงไปนั้นมาทับภาพผลลัพธ์อยู่ดังภาพ คำนวณมาสก์แบบที่ 1 แล้วจึงลองผิดลองถูกจนได้สูตรการคำนวณมาสก์แบบที่ 2 ที่ไม่มีใน document เลย โดยแบบที่ 2 นี้จะเป็นการดึงเอาเส้นที่ระบายลงไปมาคิดรอบเดียว แต่แบบที่ 1 GrabCat จะพิจารณามาสก์นี้ให้
คำนวณมาสก์แบบที่ 1
imageMask = mask.ThresholdBinary(new Gray((double)2), new Gray(255));
คำนวณมาสก์แบบที่ 2
Image
imageMaskFG.SetZero();
using (ScalarArray ia = new ScalarArray(1))
CvInvoke.Compare(mask, ia, imageMaskFG, Emgu.CV.CvEnum.CmpType.Equal);
หลังพอเจอแบบนี้ก็ blank ไปแบบข้ามคืนเลย อย่างที่บอกมันไม่ document และเราไม่ได้เซียนเรื่อง Image Processing เลย อีกทั้งตอนเขียนด้วย C++ บน OpenCV มันก็ไม่เป็นแบบนี้แค่ส่งค่ามาสก์เขาไปในเมดทรอด GrabCut ทุกอย่างก็จบ นั่งเกาไข่รอผลลัพธ์ได้เลย แต่พอมาทำบน EmguCV ทำไมถึงเป็บแบบนี้หละ มันต้องมีอะไรผืดพลาดแน่ๆ แต่พอลองคิดไปคิดมา เอ้า เฮ้ยใช้แล้ว เราก็นำมาสก์ที่เป็นผลลัพธ์ในการเทียบค่าทั้งสองแบบมารวมกันให้เป็นตัวเดียวสิแล้ว คิดได้แบบนี้ก็คิดต่อได้อีกว่า Gray scale Image นั้นสามารถจับมาบวกกันได้ทันที่เลยนี่หว่าว่าแล้วก็ทดสอบเลย ได้ผลตามรูป โป๊ะเซ๊ะ นี่แหละที่ต้องการเลย
ไว้วันหลังจะหาเวลามาอธีบายเชิงลึกในเรื่อง Image segmentation with EmguCV อีกทีนะครับ ขอบคุณที่ติดตามอ่านครับผม