รูปปกบทความ

1. 🎯 ตอนที่ 10: การตัดภาพและโฟกัสเฉพาะจุดด้วย ROI (Region of Interest)

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

น้องๆ เคยเจอปัญหาแบบนี้ไหมครับ? สมมติว่าเรามีกล้องความละเอียดระดับ 4K ติดตั้งอยู่ในโรงงาน เพื่อตรวจสอบรอยร้าวของน็อตตัวเล็กๆ ที่วิ่งผ่านสายพาน ถ้าเราโยนภาพขนาดยักษ์ 4K นี้เข้าไปรันในโมเดล Deep Learning หรือทำ Image Processing ทั้งภาพแบบตรงๆ CPU และ GPU ของเราคงร้องไห้ประท้วงแน่นอน เพราะเรากำลังเสียเวลาประมวลผลพื้นที่สายพานและฉากหลังที่ไม่ได้มีประโยชน์อะไรเลย!

มันเหมือนเราพยายามจะอ่านหนังสือทั้งเล่ม เพียงเพื่อจะหาคำตอบแค่ในย่อหน้าเดียวครับ ในโลกของ Computer Vision วิศวกรอย่างพวกเรามีเวทมนตร์ที่เรียกว่า ROI (Region of Interest) หรือ “พื้นที่ที่เราสนใจ” วันนี้พี่จะมาชงกาแฟ แล้วพาน้องๆ ไปดูวิธีการสร้างกรอบ Bounding Box เพื่อโฟกัสเฉพาะจุดที่ต้องการ และความลับระดับคัมภีร์ที่ว่า OpenCV มันสามารถตัดภาพออกมาได้โดย “ไม่ต้องก๊อปปี้ข้อมูลเลยแม้แต่ไบต์เดียว” มันทำได้ยังไง ไปดูกันครับ!

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

ROI (Region of Interest) คืออะไร? ROI คือการกำหนดกรอบพื้นที่ (มักจะเป็นสี่เหลี่ยม) บนภาพต้นฉบับ เพื่อดึงเฉพาะชิ้นส่วนของภาพนั้นออกมาประมวลผลต่อ (เช่น การทำ Feature Extraction เฉพาะจุด หรือการเซ็นเซอร์เบลอหน้าคน) เรามักจะใช้โครงสร้าง cv::Rect ซึ่งต้องการพารามิเตอร์ 4 ตัวคือ x, y (พิกัดมุมซ้ายบน) และ width, height (ความกว้างและความสูง) เพื่อเป็นตัวกำหนดกรอบ

ความลับของ ROI: ทำไมมันถึงทำงานได้เร็วปานสายฟ้า? ในตอนที่ 4 เราเคยคุยกันเรื่องโครงสร้างของ cv::Mat ไปแล้วว่ามันประกอบด้วยส่วน Header และ Data Pointer เมื่อน้องๆ สั่งตัดภาพด้วย ROI (เช่น Mat roi = image(Rect);) สิ่งที่ OpenCV ทำ ไม่ใช่การทำ Deep Copy (ก๊อปปี้ข้อมูลพิกเซลทั้งหมด) ออกมาสร้างรูปใหม่นะครับ!

แต่สิ่งที่มันทำคือ “การสร้าง Header ตัวใหม่” ที่ชี้ (Point) กลับไปหาโกดังเก็บพิกเซลของภาพต้นฉบับเดิมเป๊ะๆ

  • เปรียบเทียบ: เหมือนเรามีตาราง Excel ขนาดยักษ์อยู่ 1 ไฟล์ การทำ ROI ไม่ใช่การ Save As ไฟล์ใหม่ แต่เป็นการเอากระดาษเจาะรูสี่เหลี่ยม ไปทาบไว้บนหน้าจอ เพื่อให้เรามองเห็นและแก้ไขเฉพาะเซลล์ที่อยู่ในรูนั้น!

สถานการณ์คลาสสิกที่ต้องใช้ ROI:

  1. Face & Eye Detection: เมื่อ AI หาใบหน้าเจอ เราจะสร้าง ROI คลุมเฉพาะหน้า แล้วส่งแค่หน้าไปหาตำแหน่ง “ดวงตา” ต่อไป (ประหยัดเวลา ไม่ต้องหาตาทั้งภาพ)
  2. Privacy Blurring: หาตำแหน่งป้ายทะเบียนรถหรือใบหน้าคน แล้วทำ Gaussian Blur เฉพาะใน ROI นั้น
  3. Cropping: ตัดภาพสินค้าที่หลุด QC ออกมาจากฉากหลัง เพื่อบันทึกลงฐานข้อมูล
รูปประกอบ

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

เรามาดูตัวอย่างโค้ด C++ ในการสร้างกรอบ cv::Rect และการนำไปใช้ครอบภาพ (ROI) กันครับ สังเกตว่าเมื่อเราแก้ไขภาพ ROI ภาพต้นฉบับก็จะเปลี่ยนไปด้วยเพราะมันแชร์ Memory กัน!

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

using namespace cv;
using namespace std;

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

    // 2. กำหนดกรอบ Bounding Box (x, y, width, height)
    // สมมติว่าจุดที่เราสนใจ (เช่น น็อต) อยู่ที่พิกัด 500, 138 และมีขนาด 65x65 พิกเซล
    Rect roi_rect(500, 138, 65, 65);

    // 3. สร้างตัวแปร Mat ตัวใหม่เพื่อรับค่า ROI 
    // เวทมนตร์อยู่ตรงนี้! โค้ดนี้ทำงานไวมาก O(1) เพราะไม่ได้ก๊อปปี้ข้อมูลพิกเซล
    Mat roi = image(roi_rect);

    // 4. ทดลองดัดแปลง ROI: ทำให้พื้นที่นี้กลายเป็นสีดำสนิท
    // เนื่องจากการแชร์ Memory ทันทีที่เราเปลี่ยนค่า roi ภาพต้นฉบับ (image) จะโดนเปลี่ยนด้วย!
    roi = Scalar(0, 0, 0);

    // 5. หากต้องการภาพที่ตัดออกมา "แยกเป็นอิสระ" ไม่กวนต้นฉบับ ต้องร่ายคาถา .clone()
    // Mat safe_roi = image(roi_rect).clone();

    // 6. แสดงผลลัพธ์
    imshow("Original Image with Black ROI", image);
    waitKey(0);

    return 0;
}

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

  • กับดัก Memory Sharing: รุ่นน้องพี่หลายคนตกม้าตายตรงนี้ครับ! ตั้งใจจะดึง ROI ออกมาแปลงเป็น Grayscale ปรากฏว่าภาพสีต้นฉบับดันมีรอยแหว่งเป็นสีเทาซะงั้น! จำไว้ให้ขึ้นใจว่า “การแก้ไขพิกเซลใน ROI จะกระทบภาพต้นฉบับเสมอ” ถ้าต้องการอิสระ ต้องสั่ง .clone() เพื่อทำ Deep Copy แยกโกดัง Memory ออกมาต่างหากครับ
  • ระวังทะลุขอบ (Out of Bounds): ก่อนจะสร้าง cv::Rect ไปครอบ cv::Mat ต้องเขียนโค้ด if เช็กเสมอว่า x + width และ y + height ไม่ได้มีค่าทะลุเกินความกว้าง (image.cols) และความสูง (image.rows) ของภาพต้นฉบับ ไม่อย่างนั้นโปรแกรมจะพ่น cv::Exception แล้ว Crash ทันทีครับ
  • ครอบแค่บางแถวหรือบางคอลัมน์: หากน้องๆ ไม่ได้อยากครอบเป็นสี่เหลี่ยม แต่ต้องการดึงข้อมูลทั้ง “แถว (Row)” หรือ “คอลัมน์ (Column)” OpenCV มีคำสั่งอย่าง image.rowRange(start, end) หรือ image.colRange(start, end) ให้ใช้ ซึ่งทำงานด้วยหลักการแชร์ Memory แบบเดียวกันเป๊ะเลยครับ

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

ด้วยเทคนิค ROI ทำให้เราสามารถบีบวงแคบในการประมวลผล (Processing Pipeline) ลดภาระ CPU/GPU ลงไปได้มหาศาล และยังเป็นท่าพื้นฐานในการส่งต่อภาพ (Cropped Image) ไปให้ระบบ Deep Learning แยกแยะวัตถุอีกด้วย

ในตอนต่อไป เมื่อเราตัดภาพเป็นแล้ว พี่จะพาไปดูเครื่องมือในการขีดๆ เขียนๆ ลงบนภาพ ไม่ว่าจะเป็นการวาด Bounding Box (สี่เหลี่ยม), วาดวงกลม, หรือเขียนตัวอักษร เพื่อเอาไว้โชว์ผลลัพธ์ของ AI ออกมาทางหน้าจอกันครับ รอติดตามได้เลย!


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