[Firebase] ลองเล่น Image Labeling APIใน Firebase ML Kit กัน ทั้ง iOS และ Android (1)

Kajornsak P.
Firebase Thailand
Published in
4 min readMay 26, 2018

ต่อจากบทความที่แล้วที่ได้เกริ่นไว้เรื่อง ML Kit จาก Firebase ในบทความนี้เราจะมาลองดู API แต่ละตัวที่มีให้ใช้กัน โดยบทความนี้จะโฟกัสเฉพาะ Image Labeling ที่มีให้ใน ML Kit ก่อนเท่านั้น

พระเอกของเรา ML Kit

ต้องบอกไว้ก่อนว่าจริงๆแล้ว ML Kit นั้นมีรากฐานเดิมมาจากโปรเจค Mobile Vision ของ Google นั่นเอง ซึ่ง Google เคยทำ SDK สำหรับใช้งาน Text recognition, Face detection และ Barcode detection มาก่อนแล้วทั้งสำหรับ Android และ iOS

ทำให้เจ้า ML Kit นั้นสามารถต่อยอดมาจาก SDK เดิมได้เลย ซึ่งถ้าเข้าไปดูที่ API เก่า ก็จะเห็นว่าย้ายไปอยู่ใน ML Kit เรียบร้อยแล้วนั่นเอง

https://developers.google.com/vision/

ขั้นตอนการใช้งาน ML Kit ทั้งสำหรับ iOS และ Android

ด้วยความที่เป็น Firebase ทำให้การใช้งาน ML Kit ไม่ใช่เรื่องยุ่งยากอีกต่อไป เพียงแค่ setup project Firebase เหมือนกับ Product อื่นๆนั่นเอง ขอไม่พูดถึงวิธีติดตั้งเน้อ เพราะมันง่ายมากๆเลย ลองเข้าไปทำตาม docs ได้เลย ( iOS , Android )

Image labeling

อย่างที่เคยเกริ่นไว้แล้วในบทความก่อน Image labeling นั้นเป็น API สำหรับหาสิ่งของ / entity ที่อยู่ภายในรูปภาพเรานั่นเอง โดยจะคล้ายๆกับ Cloud Vision API (น่าจะเป็นตัวเดียวกันเลยแหละ) ซึ่งมีประโยชน์มากๆ หากเราต้องการทำระบบ autotag รูป ว่ามีอะไรในรูปบ้าง

ประมาณนี้แล (รูปถ่ายสดๆตอนเขียนบทความเลย)

หลังจากที่ติดตั้ง Firebase เสร็จแล้ว เราจะลองใช้งาน ML Kit ดู ซึ่งขอแบ่งออกเป็นสองส่วน คือ iOS และ Android (เขียนพร้อมกันเดี๋ยวผมจะงงเองเนี่ยแหละ 555)

iOS

อย่าลืม update repo cocoapods กันก่อนนะ เดี๋ยว pod จะหาไม่เจอ และใครที่มี Firebase อยู่ใน project อยู่แล้ว อัพเดตเป็น Firebase 5.0 ด้วยเน้อ (pod update)

เพิ่ม ML Kit เข้าไปใน Podfile ได้เลย และที่สำคัญ อย่าลืม Firebase/Core นะ เดี๋ยวต่อ Firebase ไม่ได้

pod 'Firebase/Core' #ต้องมี
pod 'Firebase/MLVision' #ต้องมี
pod 'Firebase/MLVisionLabelModel' #สำหรับ On-device image labeling

จากนั้นก็ pod install โลด (ถ้าสังเกตทัน ต่อ pod กำลังลง MLVision จะเห็นว่ามันดึง GoogleMobileVision มาด้วย) อย่าลืมใช้งาน Firebase ใน AppDelegate ด้วยนะ

FirebaseApp.configure() //ห้ามลืม เดี๋ยวเชื่อม Firebase ไม่ผ่าน
หน้าตาคร่าวๆของแอปที่เราจะทำ

แอปที่เราจะทำนั้นเป็นแอปง๊ายง่าย มีแค่สองหน้าเท่านั้น คือ 1. ถ่ายรูป/เลือกรูป จากนั้นใช้งาน Image Labeling API (On-Device) เพื่อหา Entities แล้วส่งไปแสดงผลอีกหน้า จบและ

ขั้นตอนหลักๆของการใช้งาน Image Labeling API นั้นไม่ยาก มีแค่ 3 ขั้นตอนเท่านั้น

  1. สร้างตัวแปรของ Vision module และ Label detector เพื่อไปใช้งาน
  2. เปลี่ยนรูปจาก UIImage/CMSampleBuffer ให้กลายเป็น VisionImage โดยในที่นี้เราจะใช้ UIImage เพราะมันได้มาจาก UIImagePicker เลย
  3. เรียกใช้งานฟังก์ชั่น detect ของ Label detector จบ!

ลองมาดูที่หน้าแรกเลยละกัน ซึ่งหน้านี้จะไม่มีอะไรมาก นอกจากปุ่มสองปุ่มเพื่อเลือก source ของรูปที่จะมาใช้กับ Labeling API พอได้ค่า label จาก ML Kit แล้วก็จะส่งรูปไปแสดงผลที่อีกหน้านึงแค่นั้นเอง

ส่วนแรกก็แค่เชื่อม IBAction จากปุ่มเข้ามา จากนั้นก็สร้าง vision module เอาไว้เพื่อเรียกใช้ภายหลังตอนจะ detect จริงๆ

จากนั้นก็ implement delegate ส่วนที่รับรูปจาก UIImagePickerController ซะ

แล้วก็ส่งรูปไป detect ด้วย Image Labeling ของ ML Kit (แบบ On-Device) ตาม default ของ ML Kit นั้น ตัว Image Labeling API จะใช้ threshold confidence อยู่ที่ 0.5 หมายความว่า หากสิ่งของใดที่มีความเหมือนเกิน 0.5 จะถูกรวมมาใน output ของ API นี้หมดเลย

คำเตือน : หากใช้กล้องถ่ายรูป อย่าลืม detect orientation แล้วระบุใน metadata ของ VisionImage ด้วย เพื่อผลจากการ classify จะได้แม่นขึ้น

เกร็ดความรู้~

ซึ่ง Output ของ Image Labeling API นั้นจะมาเป็น list ของ VisionLabel หรือ FIRVisionLabel ใน Objective-C ซึ่งเป็น class สำหรับผลลัพธ์จากการ detect label โดยเฉพาะ โดยประกอบไปด้วย frame, confidence, entityId และ label นั่นเอง

เราสามารถเอา frame ที่ได้ไปวาดกรอบบนรูปได้อีกด้วย ว่าของนั้นอยู่ตรงไหน (แต่ต้องระวังเรื่องขนาดภาพด้วยนะ เพราะ coordinate มันอ้างอิงจากรูป อย่าลืม scale เข้ากับ UIImageView ให้ดีๆ)

//ณ Firebase ML เวอร์ชั่นปัจจุบัน (0.9.0) frame ที่ส่งมาจาก On-device detector ยังเป็นค่าที่ใช้ไม่ได้อยู่ คาดว่าคงมีการแก้ไขในเวอร์ชั่นถัดๆไปแน่นอน

อยากรู้รายละเอียดอันไหนเพิ่ม หาใน ref หรือ source code ได้เลยจ้า เพราะมัน Open source อยู่แล้ว

กลับมาต่อที่เดิม~

พอเราได้ผลลัพธ์จากการ detect label แล้ว ก็โยนรูป original และ output ไปให้อีกหน้านึงซะ จบ!

มีโค้ด handle error นิดหน่อย เผื่อมีอะไรผิดพลาด
เสร็จแล้ว~ ง่ายยิ่งกว่า CoreML หรือ TFLite ซะอีก

แถมจ้า เนื่องจากลองไปเล่น AVKit มาเพื่อทำ real-time labeling

เปลี่ยนไปทำ real-time labeling นั้นก็ไม่ยาก เนื่องจาก VisionImage ที่เป็น Input ของ Image Labeling API นั้นรองรับข้อมูลประเภท media buffer (CMSampleBuffer) ด้วย ทำให้สามารถใช้งานร่วมกับ Output จาก AVCaptureSession ได้เลย แต่ระวัง memory leak จากการ detect รัวๆด้วยนาจา

ถามว่าวิธีนี้สะดวกกว่า Vision + CoreML ใน iOS 11 หรือไม่ ก็อาจจะไม่สะดวกเท่านัก แต่ขนาดเล็กกว่า(มาก) และความยืดหยุ่นเยอะกว่าแน่นอน คอนเฟิร์ม!

ผลก็จะประมาณนี้~

Android

ในส่วนของแอปแอนดรอยด์นั้นก็จะคล้ายๆกับ iOS เลย คือสามารถถ่ายรูปหรือเลือกรูปก็ได้ จากนั้นก็ส่งรูปเค้าไปใน Label detector เพื่อหา label ของรูปนั่นเอง

มีสองหน้า ประมาณนี้

โค้ดก็น้อยมากก เพราะทีม Firebase เค้าทำมาดี จะได้ใช้ง่ายๆ

ต้องขอบอกไว้ก่อนว่าไม่ได้เขียน Android มาเป็นปี โค้ดอาจจะดูแปลกๆ 555

สิ่งที่ต้องเพิ่มก็คือ dependencies 2 ตัวนั่นเอง(ไม่นับ Firebase Core) ใน build.gradle ของระดับ app แค่นี้ก็สามารถนำไปใช้ได้ในแอปแล้วนั่นเอง

จากนั้นขอ skip ไปตอนที่ได้ Uri ของรูปมาแล้วเน้อ บทความจะได้ไม่ยาว

ซึ่งเจ้า Image Labeling API ของฝั่ง Android นั้นจะมี Input Class ชื่อว่า FirebaseVisionImage เพื่อนำไปเรียกใช้ใน Label detector

โดยเจ้า FirebaseVisionImage นั้นสามารถสร้างได้หลายวิธีมาก ได้แก่ Bitmap, Media Image Object, Byte buffer/array หรือสร้างจาก path ของ file ก็ได้ เรียกได้ว่าทั่วถึงเลยทีเดียว source ของรูปจะมาจากทางไหนก็ได้ วิธีสร้างแต่ละแบบก็ตามนี้เลย

และเมื่อเราได้ Output ออกมาจาก Label Detector ก็สามารถนำไปใช้ต่อได้เลย ซึ่งชนิดของมันก็คือ List ของ FirebaseVisionLabel เหมือนกับใน iOS นั่นเอง ประกอบไปด้วย entityId, label และ confidence นั่นเอง

จากนั้นก็โยน label ทั้งหมดที่ concat แล้วไปให้หน้า Result จัดการะแสดงผลซะเลย (ส่ง Uri ไปด้วยจะได้โชว์รูปได้) //โค้ดชุดนี้ใช้ Navigation Component ใน Android Jetpack ด้วย เพราะอยากเล่นของใหม่ไปพร้อมๆกัน 555

ที่หน้า Result ก็ดึงค่าที่ส่งมาผ่านทาง Navigation แล้วก็นำไปโชว์นั่นเอง

//อันนี้ใช้ safeargs ช่วยทำให้ params ที่ส่งมัน type-safe แหละ

เสร็จแล้ว! ทั้งสอง platform เขียนคล้ายๆกันเลย บอกเลยว่าใช้ง่ายจริงๆ ถ้าเทียบกับ CoreML หรือ TFLite นี่ ML Kit ชนะขาดเลยแหละ (เฉพาะด้าน object recognition อะนะ)

Quick question : ถ้าอยากใช้ On-Cloud image labeling นั้นทำยังไง?

ง่ายมากก เพียงแค่ เปิดใช้ Cloud Vision API แล้วก็เปลี่ยน label detector ให้กลายเป็นตัวสำหรับ Cloud นั่นเอง โค้ดที่เหลือใช้ของเดิมได้เลย

บทความนี้คร่าวๆก็มีเพียงแค่นี้แล~ ไว้บทความหน้ามาลองใช้ Base API ตัวอื่นกัน หากมีข้อสงสัยหรือติชม สามารถบอกได้เลยนะครับ จะได้นำไปปรับปรุงในบทความต่อๆไป~~ ขอบคุณครับ

--

--

Kajornsak P.
Firebase Thailand

Android & iOS developer. Interest in UI/UX design. Currently, Senior iOS Engineer at Agoda — Mobile Platform team