5.32. การบันทึกและการบีบอัด¶
ทุกหน้าที่ผ่านมาทำงานกับภาพบนกล้อง: จับภาพลงในบัฟเฟอร์เฟรมหรือจัดสรรบน MicroPython heap จัดการผ่านเมธอดของโมดูล image และแสดงผลในหน้าต่างพรีวิวของ IDE หรือส่งต่อไปยังขั้นตอนถัดไปในสคริปต์เดียวกัน แอปพลิเคชันส่วนใหญ่จำเป็นต้องทำสิ่งตรงข้ามในบางจุด: นำภาพที่อยู่ใน RAM และนำไปเก็บไว้ในที่ถาวร เช่น การ์ด SD, USB host หรือผ่านเครือข่าย เพื่อให้สิ่งอื่นนอกจากกล้องสามารถอ่านได้
โมดูล image เปิดเผยสองเส้นทางสำหรับงานนี้ เส้นทาง save เขียนภาพลงในไฟล์บนระบบไฟล์ โดยรูปแบบไฟล์ถูกเลือกจากนามสกุลและรายละเอียดการเข้ารหัสจัดการโดยเมธอด เส้นทาง to-format คืนค่าออบเจ็กต์ Image ที่มีสตรีมไบต์ที่เข้ารหัสแล้ว เหมาะสำหรับส่งต่อไปยังการเรียกแบบ streaming หรือเครือข่ายโดยไม่ต้องแตะระบบไฟล์เลย แต่ละแบบเหมาะกับแอปพลิเคชันที่แตกต่างกัน ทั้งสองสร้างบนเครื่องมือการบีบอัดเดียวกันภายใต้
5.32.1. การบันทึกลงไฟล์¶
save() เขียนภาพลงในระบบไฟล์ตามเส้นทางที่ระบุ:
img.save("/sdcard/capture.jpg")
img.save("/sdcard/capture.bmp")
img.save("/sdcard/region.jpg", roi=(40, 60, 200, 150), quality=85)
รูปแบบถูกเลือกจากนามสกุลไฟล์ มีห้านามสกุลที่รองรับ: .bmp เขียน Windows bitmap (ไม่สูญเสียข้อมูล ไม่บีบอัด เป็นพิกเซลที่จับภาพมาแบบไบต์ต่อไบต์); .pgm เขียน portable graymap (ไม่สูญเสียข้อมูล เฉพาะระดับสีเทาเท่านั้น); .ppm เขียน portable pixmap (ไม่สูญเสียข้อมูล RGB); .jpg และ .jpeg ทั้งสองเขียน JPEG (สูญเสียข้อมูล บีบอัด) ภาพรับต้องอยู่ในรูปแบบสีที่ถูกต้องสำหรับคอนเทนเนอร์ที่เลือก -- การบันทึกภาพสีเป็น .pgm จะเกิดข้อผิดพลาด
roi จำกัดการบันทึกให้อยู่ในสี่เหลี่ยมย่อยของภาพ เช่นเดียวกับคำสำคัญ roi ของเมธอดอื่นๆ ในโมดูล image ค่าเริ่มต้นคือภาพทั้งหมด คำสำคัญนี้จะถูกละเว้นเมื่อบันทึกภาพที่บีบอัดด้วย JPEG เนื่องจากรูปแบบบนดิสก์ครอบคลุมเฟรมทั้งหมดอยู่แล้ว และการเข้ารหัสซ้ำผ่านการครอปจะทำลายจุดประสงค์ของการบันทึกไบต์ที่บีบอัดไว้แล้ว
quality คือคุณภาพการบีบอัด JPEG จาก 0 ถึง 100 และมีความหมายเฉพาะเมื่อเอาต์พุตเป็น JPEG (คำสำคัญนี้จะถูกละเว้นสำหรับรูปแบบที่ไม่สูญเสียข้อมูล) ค่าเริ่มต้น 50 เป็นสมดุลที่เหมาะสมสำหรับแอปพลิเคชัน ส่วนใหญ่; 70 ถึง 85 คือช่วงสำหรับคุณภาพภาพที่สูงขึ้น 30 ถึง 50 เป็นช่วงที่เหมาะสำหรับรูปขนาดเล็กและการส่งในสภาวะที่แบนด์วิดธ์จำกัด และ 90 ขึ้นไปสงวนไว้สำหรับกรณีที่ภาพจะถูกตรวจสอบด้วยตนเองหรือผ่านอัลกอริทึมปลายทางที่ไวต่อสิ่งที่ผิดปกติจากการบีบอัด
ภาพผู้รับจะถูกคืนค่า เพื่อให้การเรียกสามารถเชื่อมต่อกันได้: img.save("/sdcard/x.jpg").draw_string(0, 0, "saved") ออบเจ็กต์ที่คืนค่ามาเป็นภาพในหน่วยความจำเดิม การบันทึกเป็นผลข้างเคียง
การใช้งานทั่วไปคือรูปแบบ capture-and-log ทริกเกอร์ทำงาน (พบบลอบ กดปุ่ม หรือตัวจับเวลาหมดเวลา); สคริปต์จับภาพเฟรม; เพิ่มตราเวลาลงในชื่อไฟล์; และเรียก save() เพื่อส่งภาพไปยังการ์ด SD พรีวิวใน IDE ยังคงทำงานต่อไป ทริกเกอร์ถัดไปทำงาน และไฟล์ที่บันทึกสะสมเพิ่มขึ้น
5.32.2. การเข้ารหัสลงหน่วยความจำ¶
เมื่อปลายทางไม่ใช่ระบบไฟล์แต่เป็นการเชื่อมต่อเครือข่าย พอร์ตอนุกรม หรืออินพุตของโมดูลอื่น แอปพลิเคชันต้องการสตรีมไบต์ที่เข้ารหัสแล้ว ในหน่วยความจำ แทนที่จะเป็นบนดิสก์ to_jpeg() และ to_png() ผลิตสิ่งนั้นได้พอดี:
encoded = img.to_jpeg(quality=80, copy=True)
bytes_to_send = encoded.bytearray()
sock.send(bytes_to_send)
พฤติกรรมเริ่มต้นคือการแปลงในตำแหน่งเดิม: ผู้รับถูกแปลงเป็นภาพ JPEG (หรือ PNG) และคืนค่าออบเจ็กต์เดิม ด้วย copy=True การแปลงเขียนลงในออบเจ็กต์ heap ที่จัดสรรใหม่; ด้วย copy_to_fb=True เอาต์พุตจะไปอยู่ในบัฟเฟอร์เฟรม ตัวเลือกนี้เป็นตัวเลือกเดิมที่เมธอดแปลงอื่นๆ เสนอ -- ในตำแหน่งเดิมโดยค่าเริ่มต้น คัดลอกเมื่อต้องการของเดิมในภายหลัง
quality และ subsampling คือปุ่มปรับจูน JPEG เดิมที่เส้นทาง save เปิดเผย subsampling เลือกรูปแบบการสุ่มตัวอย่างสี: image.JPEG_SUBSAMPLING_AUTO เลือกรูปแบบที่ดีที่สุดสำหรับคุณภาพที่เลือก, image.JPEG_SUBSAMPLING_444 คงความละเอียดสีไว้เต็มที่ (ไฟล์ใหญ่ที่สุด ความแม่นยำสีดีที่สุด), image.JPEG_SUBSAMPLING_422 และ image.JPEG_SUBSAMPLING_420 ลดความละเอียดสีครึ่งหนึ่งตามแกนหนึ่งหรือทั้งสองแกน (ไฟล์เล็กกว่า สีอ่อนลงเล็กน้อยซึ่งมองไม่เห็นในระยะดูปกติ) ค่าเริ่มต้น AUTO เป็นตัวเลือกที่ถูกต้องเว้นแต่แอปพลิเคชันมีความต้องการเฉพาะ
PNG ผ่าน to_png() เป็นแบบ ไม่สูญเสียข้อมูล แต่เข้ารหัสช้ากว่าและสร้างไฟล์ที่ใหญ่กว่า JPEG สำหรับเนื้อหาประเภทภาพถ่าย (เนื้อหาประเภทภาพถ่ายบีบอัดได้ไม่ดีภายใต้รูปแบบการทำนายของ PNG) ใช้ PNG เมื่อภาพเป็นงานศิลปะเส้น ภาพหน้าจอ หรือมีกราฟิกขอบแข็งที่วาดทับบนเฟรมที่จับภาพ -- การเข้ารหัสแบบไม่สูญเสียข้อมูลจะรักษาขอบที่คมชัดที่ JPEG จะทำให้อ่อนลง มิฉะนั้น JPEG คือค่าเริ่มต้นที่ถูกต้อง
ทั้ง to_jpeg() และ to_png() รับคำสำคัญตำแหน่งและการปรับขนาดแบบเดียวกับเมธอดแปลงอื่นๆ -- x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint -- ดังนั้นการเรียกเดียวกันสามารถเข้ารหัสเวอร์ชันที่ปรับขนาด ครอป หรือแมปพาเลตต์ของแหล่งข้อมูลได้ในขั้นตอนเดียว compress() คือการสะกดแบบเดิมของ to_jpeg(); ทั้งสองรับอาร์กิวเมนต์เดียวกันและให้ผลลัพธ์เหมือนกัน
5.32.3. ประโยชน์ที่การบีบอัดมอบให้¶
ตัวเลขเบื้องหลังการแลกเปลี่ยนระหว่าง JPEG กับข้อมูลดิบคุ้มค่าที่จะศึกษาสักครั้ง
เฟรม RGB565 ขนาด 320x240 มีขนาด 153,600 ไบต์ (เฟรมที่จับภาพหนึ่งเฟรมที่ QVGA) เฟรม 640x480 มีขนาด 614,400 ไบต์; เฟรม 1280x960 มีขนาด 2,457,600 ไบต์ ตัวเลขเหล่านี้ไม่ใหญ่มากเมื่อเทียบกับเดสก์ท็อปหรือหน้าจอโทรศัพท์ แต่มีนัยสำคัญในบริบทของกล้องที่มี RAM รวมเพียงไม่กี่ MB การ์ด SD ที่มีแบนด์วิดธ์การเขียนจำกัด และลิงก์โฮสต์ที่มักทำงานผ่าน USB CDC, UART หรือโมดูลไร้สายที่ความเร็วปานกลาง
JPEG ที่ quality=50 โดยทั่วไปบีบอัดเฟรมที่จับภาพแบบภาพถ่ายได้ 10 ถึง 20 เท่า: เฟรม 640x480 ขนาด 614 KB กลายเป็นสตรีมไบต์ที่เข้ารหัสขนาด 30 ถึง 60 KB ที่ quality=85 การบีบอัดลดลงเหลือ 5 ถึง 10 เท่า (60 ถึง 120 KB สำหรับเฟรมเดียวกัน) ที่ quality=10 -- มีสิ่งที่ผิดปกติแต่ยังจำได้ -- การบีบอัดถึง 30 ถึง 50 เท่า (12 ถึง 20 KB)
ตัวเลขเหล่านี้กำหนดว่าอะไรทำได้จริงกับเฟรมที่บันทึก เส้นทางการ์ด SD ที่รองรับ 10 MB/s สามารถจัดการ 30 เฟรมต่อวินาทีของเนื้อหา VGA ที่เข้ารหัส JPEG คุณภาพ quality=50 ได้อย่างมีที่เหลือ (ประมาณ 1 ถึง 2 MB/s); การบันทึกเนื้อหาเดียวกันแบบไม่บีบอัดต้องการมากกว่า 18 MB/s ซึ่งเกินกว่าที่เส้นทางระบบไฟล์ของกล้องจะรองรับได้ไปยังการ์ด USB host ที่ดึงเฟรมที่เข้ารหัส JPEG ผ่าน CDC ที่ 1 MB/s จะรับเฟรมขนาด 30 ถึง 60 KB ที่ประมาณ 15 ถึง 30 เฟรมต่อวินาที; การดึงเฟรมดิบในอัตราเดียวกันจะได้หนึ่งหรือสองเฟรมต่อวินาที
กล่าวโดยสรุป: วิธีการบีบอัดไม่ใช่เพียงความสะดวกสำหรับการบันทึก แต่เป็นสิ่งที่ทำให้เฟรมที่จับภาพ ใช้งานได้จริง นอกกล้องในอัตราเฟรมที่แอปพลิเคชันต้องการ การเลือกการบีบอัดที่เหมาะสม -- คุณภาพ JPEG 50 สำหรับการบันทึกทั่วไป, 80 สำหรับงานคุณภาพสูง, PNG สำหรับการจับภาพงานศิลปะเส้น -- เป็นส่วนหนึ่งของงานประจำของแอปพลิเคชันกล้องที่ไม่ธรรมดา