ตอนที่ 13: งานศิลปะบนภาพ - วาดเส้น, วงกลม, สี่เหลี่ยม และข้อความ

1. 🎯 ตอนที่ 13: งานศิลปะบนภาพ - วาดเส้น, วงกลม, สี่เหลี่ยม และข้อความ
2. 📖 เปิดฉาก (The Hook)
น้องๆ ครับ ลองจินตนาการดูนะ สมมติว่าเราเขียน AI ตรวจจับใบหน้าโจรผู้ร้าย หรือตรวจจับน็อตที่หลุด QC บนสายพานได้แม่นยำ 100% แล้ว แต่พอรันโปรแกรมโชว์ให้ลูกค้าดู… หน้าจอกลับมีแต่วิดีโอเปล่าๆ แล้วมีตัวเลขพิกัด (x, y) วิ่งรัวๆ อยู่ในหน้าต่าง Console สีดำ ลูกค้าคงจะงงเป็นไก่ตาแตกแน่ๆ ว่า “แล้วตกลง AI มันมองเห็นตรงไหนล่ะน้อง?”
ในโลกของ Machine Vision การที่เราประมวลผลได้ผลลัพธ์มาแล้ว สิ่งสำคัญไม่แพ้กันคือ “การแสดงผล” ให้มนุษย์เข้าใจได้ง่ายที่สุดครับ! เราต้องสามารถวาด Bounding Box (กรอบสี่เหลี่ยม) ล้อมรอบวัตถุ, วาดวงกลมมาร์กจุดกึ่งกลาง (Center), หรือเขียนข้อความ (Text) บอกความมั่นใจ (Confidence Score) แปะทับลงไปบนภาพวิดีโอแบบ Real-time
วันนี้พี่จะมาชงกาแฟ แล้วพาน้องๆ สวมวิญญาณศิลปิน หยิบพู่กันดิจิทัลของ OpenCV ขึ้นมาวาดรูปและเขียนข้อความลงบนภาพกันครับ รับรองว่าคำสั่งพวกนี้ใช้ง่าย แถมประมวลผลเร็วทะลุนรก!
3. 🧠 แก่นวิชา (Core Concepts)
ใน OpenCV มีฟังก์ชันสำหรับวาดรูป (Drawing Functions) พื้นฐานที่ทรงพลังและทำงานร่วมกับตาราง cv::Mat ได้ทุกความลึกสี (Depth) โดยพระเอกของเรามีอยู่ 4 ตัวหลักๆ พร้อมกับพารามิเตอร์ลับที่เราต้องทำความเข้าใจครับ:
- 1. แกนพิกัด (Coordinate System): ลืมวิชาคณิตศาสตร์มัธยมไปก่อนครับ! ใน OpenCV จุดกำเนิด (0,0) จะอยู่มุมซ้ายบนสุดของภาพเสมอ แกน X วิ่งไปทางขวา และแกน Y วิ่งลงข้างล่าง
- 2. พระเอกทั้ง 4 (The 4 Heroes):
line(): วาดเส้นตรง เชื่อมระหว่างจุด 2 จุดrectangle(): วาดกรอบสี่เหลี่ยม (Bounding Box) โดยใช้จุดมุมซ้ายบนและมุมขวาล่างcircle(): วาดวงกลมโดยระบุพิกัดจุดกึ่งกลาง (Center) และรัศมี (Radius)putText(): วาดข้อความ (Text) ลงบนภาพ
- 3. พารามิเตอร์สุดคลาสสิก (Common Parameters):
ฟังก์ชันวาดรูปแทบทุกตัวใน OpenCV จะแชร์พารามิเตอร์ชุดเดียวกัน ถ้าน้องๆ จำชุดนี้ได้ ก็วาดได้ทุกอย่างครับ:
color: ระบุสีด้วยcv::Scalarอย่าลืมกับดักคลาสสิกว่า OpenCV ใช้ระบบสี BGR (Blue, Green, Red) นะครับ ไม่ใช่ RGB!,thickness: ความหนาของเส้นบอกเป็นพิกเซล ค่าเริ่มต้นคือ 1 ความลับคือ: ถ้าเราใส่ค่าติดลบ (เช่น-1) หรือใช้ค่าcv::FILLEDโปรแกรมจะทำการวาดแบบ “ทึบแสง” (Filled shape) เติมสีให้เต็มรูปทรงเลยครับ,lineType: ประเภทของการวาดเส้นขอบ ที่ใช้บ่อยมี 2 ตัวคือLINE_8: วาดแบบปกติ (เชื่อมต่อ 8 ทิศทาง) รันไวปานสายฟ้าLINE_AA: ย่อมาจาก Anti-Aliasing หรือการวาดแบบลบรอยหยัก ทำให้เส้นโค้งและข้อความเนียนกริบ ดูแพง, แต่จะกินสเปก CPU เพิ่มขึ้นนิดหน่อยครับ,

4. 💻 ร่ายมนต์คำสั่ง (Show me the Code)
เรามาดูเวทมนตร์การวาดภาพด้วย C++ กันครับ โค้ดนี้จะจำลองการวาด Bounding Box, เป้าเล็ง (Crosshair) และเขียนข้อความกำกับ เหมือนเวลา AI จับวัตถุเจอครับ!
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
// 1. สร้างผืนผ้าใบ (Canvas) สีดำ ขนาด 800x600 พิกเซล แบบ 3 Channels (BGR)
Mat canvas = Mat::zeros(600, 800, CV_8UC3);
// 2. กำหนดสีต่างๆ ด้วย BGR Format (น้ำเงิน, เขียว, แดง)
Scalar colorGreen(0, 255, 0); // สีเขียว
Scalar colorRed(0, 0, 255); // สีแดง
Scalar colorBlue(255, 0, 0); // สีน้ำเงิน
Scalar colorWhite(255, 255, 255); // สีขาว
// 3. วาดวงกลม (เป้าเล็ง) ตรงกลางภาพ
// พารามิเตอร์: (ภาพ, จุดศูนย์กลาง, รัศมี, สี, ความหนา, ชนิดเส้น)
Point center(canvas.cols / 2, canvas.rows / 2);
circle(canvas, center, 50, colorRed, 2, LINE_AA);
// วาดจุดกึ่งกลางแบบทึบ (ใช้ thickness = -1)
circle(canvas, center, 5, colorRed, -1, LINE_AA);
// 4. วาดเส้นตรงตัดกันเป็นเป้าเล็ง (Crosshair)
line(canvas, Point(center.x - 70, center.y), Point(center.x + 70, center.y), colorRed, 2, LINE_AA);
line(canvas, Point(center.x, center.y - 70), Point(center.x, center.y + 70), colorRed, 2, LINE_AA);
// 5. วาดกรอบสี่เหลี่ยม (Bounding Box) ล้อมรอบวัตถุจำลอง
// พารามิเตอร์: (ภาพ, จุดซ้ายบน, จุดขวาล่าง, สี, ความหนา, ชนิดเส้น)
Point pt1(center.x - 150, center.y - 150);
Point pt2(center.x + 150, center.y + 150);
rectangle(canvas, pt1, pt2, colorGreen, 3, LINE_8);
// 6. เขียนข้อความ (Text) กำกับลงไปบนภาพ
// พารามิเตอร์: (ภาพ, ข้อความ, พิกัดซ้ายล่าง, ฟอนต์, สเกลขนาด, สี, ความหนา, ชนิดเส้น)
String text = "AI Target Locked: 99%";
Point textOrg(pt1.x, pt1.y - 10); // ขยับข้อความให้อยู่เหนือ Bounding Box นิดนึง
putText(canvas, text, textOrg, FONT_HERSHEY_SIMPLEX, 0.8, colorWhite, 2, LINE_AA);
// แสดงผลงานศิลปะของเรา!
imshow("Drawing Functions in OpenCV", canvas);
waitKey(0);
destroyAllWindows();
return 0;
}5. 🛡️ เคล็ดลับจากคัมภีร์ลับ (Under the Hood / Pro-Tips)
- ศิลปะแห่งการ Render เส้น (LINE_AA คือของดี): เวลาวาดเส้นทแยงมุม วงกลม หรือเขียน Text ถ้าน้องๆ ปล่อยค่า
lineTypeเป็นค่าเริ่มต้น (LINE_8) ขอบของเส้นจะดูเป็นขั้นบันไดพิกเซลหยักๆ (Aliasing) พี่แนะนำอย่างยิ่งให้ใส่LINE_AA(Anti-Aliasing) ต่อท้ายเสมอครับ มันจะใช้เทคนิค Gaussian filtering ในการเกลี่ยสีขอบให้เนียนกริบ แอปพลิเคชันของเราจะดูมีความเป็นมืออาชีพขึ้นอีก 10 เท่าเลยล่ะ! - จุดเริ่มต้นของตัวอักษร (The Baseline Trap): พารามิเตอร์จุดพิกัด (Point) ในฟังก์ชัน
rectangleหรือcircleจะอ้างอิงจากมุมบนซ้ายหรือจุดกึ่งกลาง แต่สำหรับputTextพิกัดorgที่เราป้อนเข้าไป จะหมายถึง มุมซ้ายล่าง (Bottom-left) ของข้อความประโยคนั้นๆ ถ้าน้องๆ ระบุพิกัดเป็น (0,0) ข้อความของน้องจะหลุดลอยทะลุขอบบนของหน้าจอไปเลยครับ! - ขนาดอักษรที่เป๊ะปังด้วย
getTextSize: ในงานระดับ Production ถ้าเราอยากวาดพื้นหลังสีทึบรองรับตัวอักษรให้พอดีเป๊ะ (เหมือนแถบซับไตเติ้ล) เราสามารถใช้คำสั่งcv::getTextSize()โยนข้อความเข้าไป เพื่อให้มันคำนวณความกว้าง ความสูง และระยะ Baseline กลับมาให้เราก่อนที่จะวาดลงไปจริงได้ครับ,
6. 🏁 บทสรุป (To be continued…)
เป็นยังไงบ้างครับน้องๆ เมื่อเราได้รู้วิธีการใช้ line, rectangle, circle, และ putText แล้ว ตอนนี้ AI Camera ของเราก็จะสามารถสื่อสารและแสดงผลการตรวจจับให้คนทั่วไปเข้าใจได้ง่ายๆ ด้วยภาพที่สวยงามแล้วครับ
ในตอนต่อไป เราจะเข้าสู่โหมดฮาร์ดคอร์อีกนิด พี่จะพาไปดูเทคนิคสุดคลาสสิกในการหาตัวแทนของวัตถุ อย่างการประยุกต์ใช้ “Template Matching” ซึ่งเป็นอัลกอริทึมจับคู่ภาพขั้นเทพ ที่เอาไว้ตรวจหาสินค้าที่มีหน้าตาซ้ำๆ กันบนสายพานการผลิตครับ เตรียมคอมพิวเตอร์ให้พร้อม แล้วลุยกันต่อเลย!