รูปปกบทความ

1. 🎯 ตอนที่ 9: โลกของสีใน OpenCV - ไขความลับ BGR, HSV และ Grayscale

2. 📖 เปิดฉาก (The Hook)

น้องๆ เคยเจอปัญหานี้ไหมครับ? เราเขียนโค้ด AI เพื่อทำ Object Tracking ให้หุ่นยนต์วิ่งตามลูกบอลสีแดงในห้องแล็บ ตอนทดสอบทุกอย่างทำงานเพอร์เฟกต์มาก! แต่พอเอาหุ่นยนต์ไปรันหน้างานจริงที่โรงงาน แสงแดดส่องผ่านหน้าต่างเข้ามา หรือมีเงาพาดผ่านลูกบอลนิดเดียว AI ของเรากลับตาบอด มองไม่เห็นลูกบอลซะงั้น!

ปัญหาสุดคลาสสิกนี้เกิดขึ้นเพราะเราพยายามจะสอนให้คอมพิวเตอร์รู้จัก “สีแดง” ผ่านระบบสีแบบ RGB (Red, Green, Blue) ครับ ในโลกของความเป็นจริง เมื่อแสงสว่างเปลี่ยน ค่าของ R, G และ B จะเปลี่ยนตามไปหมดจนสมการเราพังทลาย วันนี้พี่จะมาชงกาแฟ แล้วพาน้องๆ ไปทำความรู้จักกับ “Color Space (ปริภูมิสี)” ใน OpenCV เราจะมาดูกันว่าทำไม OpenCV ถึงอินดี้ใช้ BGR แทนที่จะเป็น RGB แล้วทำไมระบบสีอย่าง HSV ถึงเป็นฮีโร่ขี่ม้าขาวที่วิศวกรสาย Vision ขาดไม่ได้เลยเวลาต้องทำ Object Tracking!

3. 🧠 แก่นวิชา (Core Concepts)

ใน Computer Vision การเลือกใช้ Color Space ให้ถูกกับงานมีชัยไปกว่าครึ่งครับ เรามาเจาะลึก 3 ระบบสีหลักๆ ที่ต้องเจอกัน:

  • 1. แกะรอยความอินดี้: ทำไม OpenCV ถึงใช้ BGR? เวลาเราใช้ฟังก์ชันโหลดภาพ รูปภาพที่ได้จะถูกเก็บในรูปแบบ cv::Mat เป็นตาราง Excel ขนาดยักษ์ที่มี 3 แผ่นซ้อนกันอยู่ แต่แทนที่มันจะเรียงเป็น แดง-เขียว-น้ำเงิน (RGB) แบบที่ชาวบ้านเขาใช้กัน OpenCV กลับเรียงข้อมูลเป็น น้ำเงิน-เขียว-แดง (BGR) สาเหตุไม่ได้มาจากความเท่แต่อย่างใดครับ แต่มันคือ “มรดกตกทอด” จากยุค 90s ซึ่งในตอนนั้นผู้ผลิตกล้องและระบบปฏิบัติการ (โดยเฉพาะ Windows API) นิยมเก็บข้อมูลสีในหน่วยความจำแบบ BGR เป็นมาตรฐาน ทีมสร้าง OpenCV ในยุคแรกจึงยึดโครงสร้างนี้เพื่อให้ประมวลผลได้เร็วที่สุดโดยไม่ต้องแปลงไปมา

  • 2. Grayscale (โลกสีเทาที่ทรงพลัง) การแปลงภาพสีเป็นภาพขาวดำ (Grayscale) คือการกำจัดข้อมูลสีทิ้งไป เหลือไว้เพียงแค่ “ความสว่าง (Intensity)” การทำแบบนี้ช่วยลดขนาดข้อมูลใน Memory ลงไปได้ถึง 3 เท่า! (จาก 3 Channels เหลือ 1 Channel) เรามักจะแปลงภาพเป็น Grayscale ก่อนส่งเข้าอัลกอริทึมที่สนใจแค่ “รูปร่าง” หรือ “เส้นขอบ” เช่น การหาขอบ (Edge Detection) หรือการตรวจจับใบหน้า (Face Detection)

  • 3. HSV (ฮีโร่แห่งการทำ Object Tracking) เวลาที่เราต้องการจับวัตถุด้วยสี (Color-based Object Tracking) การใช้ RGB เป็นเรื่องฝันร้าย เพราะถ้าแสงมืดลง ค่า R, G, B จะลดลงฮวบฮาบพร้อมกันหมด นี่คือจุดที่ HSV (Hue, Saturation, Value) เข้ามาช่วยชีวิตครับ:

    • H (Hue - สีสัน): คือตัวบอกว่ามันคือสีอะไร (เช่น แดง, เขียว, น้ำเงิน) โดยมองเป็นวงล้อสี
    • S (Saturation - ความอิ่มตัว): คือความสดของสี ค่า 0 คือสีเทาจืดชืด ค่าสูงสุดคือสีสดจัดจ้าน
    • V (Value - ความสว่าง): คือระดับความสว่างของแสง 0 คือมืดสนิท

    จุดเด่นของ HSV คือมันแยก “สี” (Hue) ออกจาก “ความสว่าง” (Value) อย่างเด็ดขาด! ทำให้เวลาแสงเปลี่ยน เงาบัง เราก็ยังใช้ค่า Hue เดิมในการตรวจจับวัตถุได้อย่างแม่นยำ นี่คือเหตุผลที่อัลกอริทึมขั้นเทพอย่าง MeanShift หรือ CAMShift ต้องพึ่งพา HSV Color Space ในการแทร็กวัตถุเสมอ

รูปประกอบ

4. 💻 ร่ายมนต์คำสั่ง (Show me the Code)

เรามาดูเวทมนตร์การแปลงสี (Color Space Conversion) ด้วยฟังก์ชัน cv::cvtColor และลองดึงเฉพาะ “วัตถุสีน้ำเงิน” ออกมาจากภาพ (Thresholding) กันครับ!

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main() {
    // 1. โหลดภาพต้นฉบับ (เข้ามาเป็น BGR เสมอ)
    Mat image = imread("factory_objects.jpg", IMREAD_COLOR);
    if (image.empty()) return -1;

    // 2. เตรียมพื้นที่สำหรับภาพที่แปลงสี
    Mat grayImage, hsvImage, mask;

    // 3. แปลง BGR เป็น Grayscale (โลกสีเทา)
    cvtColor(image, grayImage, COLOR_BGR2GRAY);

    // 4. แปลง BGR เป็น HSV (ฮีโร่ของเรา)
    cvtColor(image, hsvImage, COLOR_BGR2HSV);

    // 5. ค้นหาวัตถุสีน้ำเงินในระบบ HSV
    // ใน OpenCV สีน้ำเงินจะมีค่า Hue อยู่แถวๆ 100-124
    // พารามิเตอร์: (ภาพ HSV, ค่าสีต่ำสุด(H,S,V), ค่าสีสูงสุด(H,S,V), ภาพ Mask ผลลัพธ์)
    inRange(hsvImage, Scalar(100, 100, 100), Scalar(124, 255, 255), mask);

    // 6. โชว์ผลงานให้โลกเห็น
    imshow("Original (BGR)", image);
    imshow("Grayscale", grayImage);
    imshow("Blue Object Mask (HSV)", mask);

    waitKey(0);
    destroyAllWindows();
    return 0;
}

5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)

  • กฎเหล็กของค่า Hue (The Hue Range Trap): ในโปรแกรมแต่งภาพทั่วไป ค่า Hue มักจะมีตั้งแต่ 0-360 องศา (วงกลม) แต่ใน OpenCV ชนิดข้อมูล 8-bit (CV_8U) เก็บตัวเลขได้สูงสุดแค่ 255 ครับ! ดังนั้น OpenCV จึงต้องหารสอง ทำให้ค่า Hue จะวิ่งอยู่แค่ 0 ถึง 179 เท่านั้น ถ้าน้องๆ ไปตั้งค่าขีดจำกัด (Threshold) ทะลุ 180 ไป โค้ดอาจจะพังหรือทำงานผิดพลาดได้ครับ
  • ระวังสีแดงที่ถูกฉีกขาด: ในวงล้อสี HSV สีแดงจะอยู่ตรงรอยต่อของมุม 0 องศาและ 360 องศาพอดี ทำให้ใน OpenCV สีแดงถูกแบ่งออกเป็น 2 ช่วง คือช่วงน้อยๆ (0-10) และช่วงปลายๆ (156-180) ถ้าจะแทร็กวัตถุสีแดง ต้องทำ inRange สองรอบแล้วเอา Mask มารวมกันด้วย Bitwise OR นะครับ!
  • กับดักเวลาผสมกับ Qt (The UI Mismatch): ถ้าน้องๆ เขียน UI ด้วย Qt จำไว้ให้ขึ้นใจเลยว่า Qt แสดงผลภาพด้วยระบบ RGB! ดังนั้นก่อนจะเอาภาพ cv::Mat (ซึ่งเป็น BGR) ไปโยนใส่ QImage เราต้องร่ายคาถา cv::cvtColor(mat, mat, CV_BGR2RGB); เสมอ ไม่อย่างนั้นคนในกล้องจะหน้าเขียวกลายเป็นอวตาร (Avatar) ทันทีครับ!

6. 🏁 บทสรุป (To be continued…)

เห็นไหมครับว่าความเข้าใจเรื่อง Color Space สำคัญกับโลกของ Computer Vision มากแค่ไหน การหนีจาก BGR ไปพึ่งพา HSV ช่วยให้เราสร้างระบบ Object Tracking ที่ทนทานต่อแสงเงาหน้างานจริงได้อย่างเหลือเชื่อ!

ในตอนต่อไป เมื่อเราสกัด Mask ขาวดำของวัตถุออกมาได้แล้ว พี่จะพาไปดูวิธีใช้เวทมนตร์วิเคราะห์รูปทรง อย่างการหา “Contours (เส้นขอบรูปทรง)” เพื่อหาว่าวัตถุของเรากว้างยาวเท่าไหร่ มีพื้นที่กี่พิกเซลกันครับ รอสนุกได้เลย!


ต้องการที่ปรึกษาด้านการพัฒนาระบบ AI Camera หรือ Machine Vision ให้กับโรงงานของคุณ? ทีมงาน WP Solution พร้อมให้บริการออกแบบและติดตั้งระบบแบบครบวงจร ดูรายละเอียดบริการของเราได้ที่: www.wpsolution2017.com หรือพูดคุยปรึกษาเบื้องต้นได้ที่ Line: wisit.p