5.21. การปรับขนาด, การพลิก, และการตัดภาพ

หัวข้อย่อยก่อนหน้าทั้งหมดทำงานกับพิกเซลที่ตำแหน่งเดิมที่เริ่มต้น กลุ่ม transform เปลี่ยนแปลงสิ่งนั้น การปรับขนาดส่งพิกเซลอินพุตทุกตัวไปยังตำแหน่งเอาต์พุต ที่แตกต่างกัน อาจส่งไปยังหลายตำแหน่งพร้อมกัน (เมื่อขยายขนาด) หรือไปยังตำแหน่งที่ใช้ร่วมกับพิกเซลอินพุตอื่นๆ หลายตัว (เมื่อลดขนาด) การพลิกและการหมุนทำสิ่งเดียวกันผ่านการแมปที่แตกต่างกัน การตัดภาพจะเก็บพิกเซลอินพุตส่วนย่อยสี่เหลี่ยมและทิ้งส่วนที่เหลือ

โมดูล image เปิดเผยกลุ่มนั้นผ่านสามวิธีที่แบ่งปันอาร์กิวเมนต์และพฤติกรรมส่วนใหญ่:

  • copy() -- สร้างสำเนาของภาพ อาจมีการปรับขนาด ตัด หรือปรับทิศทาง

  • crop() -- การดำเนินการเดียวกับ copy แต่ด้วยความคาดหวังว่าแอปพลิเคชันจะเลือกส่วนสี่เหลี่ยมย่อยออกจากแหล่งที่มา

  • scale() -- เหมือนกันอีกครั้ง โดยมีความคาดหวังว่าแอปพลิเคชันจะปรับขนาดผลลัพธ์

ทั้งสามใช้อาร์กิวเมนต์เดียวกันและเครื่องจักรการแปลงเดียวกัน ความแตกต่างคือที่ที่ผลลัพธ์ลงจอดตามค่าเริ่มต้น copy() สร้างภาพใหม่ ในขณะที่ crop() และ scale() แก้ไขแหล่งที่มาในที่

5.21.1. อาร์กิวเมนต์ที่ใช้ร่วมกัน

การเรียกครั้งเดียวรวมการปรับขนาด การตัด การปรับทิศทาง และการแยกช่องสัญญาณในการรวมกันใดก็ตามที่แอปพลิเคชันต้องการ:

x_scale และ y_scale ปรับขนาดอินพุตตามแกนนอนและแกนตั้งอย่างอิสระ ทั้งสองค่าเริ่มต้นเป็น 1.0 (ไม่มีการปรับขนาด) ค่าที่แตกต่างกันสำหรับแต่ละค่าจะสร้างการปรับขนาดแบบไม่สม่ำเสมอ -- เช่น เฟรมที่ถูกยืดให้กว้างเป็นสองเท่าของความสูง

roi จำกัดอินพุตให้เป็นสี่เหลี่ยมของภาพต้นฉบับ โดยนำเฉพาะพิกเซลเหล่านั้นผ่านการแปลงที่เหลือ นี่คือส่วน "crop" ของการดำเนินการ: ส่ง roi เพื่อแยกส่วนย่อย

hint คือ bitfield ของแฟล็กที่เลือกวิธีการสอดแทรกและการพลิกทิศทางใดๆ แฟล็กหลายตัวรวมกันผ่านการดำเนินการ bitwise OR (hint=image.BILINEAR | image.HMIRROR) แฟล็กแบ่งออกเป็นสองกลุ่ม -- กลุ่ม interpolation และกลุ่ม orientation -- ที่ไม่มีความเกี่ยวข้องกัน แต่ใช้ bitfield เดียวกัน

rgb_channel เลือกช่องเดียวของแหล่งที่มา RGB565 0 หมายถึงสีแดง 1 หมายถึงสีเขียว 2 หมายถึงสีน้ำเงิน ผลลัพธ์ออกมาเป็นภาพระดับสีเทาที่มีเฉพาะช่องนั้น มีประโยชน์สำหรับการกำหนดค่าขีดแบ่งบนช่องสีแดงเพียงอย่างเดียว เป็นต้น

color_palette และ alpha_palette จัดเรียงค่าพิกเซลใหม่ผ่านตาราง lookup ระหว่างทางออก เหมือนกับที่วิธีการแปลง to_rainbow() และ to_ironbow() ทำ

copy=True และ copy_to_fb=True ปฏิบัติตามรูปแบบเดียวกับที่วิธีการสร้างผลลัพธ์อื่นๆ ทุกวิธีใช้ -- ค่าเริ่มต้นคือการแก้ไขในที่ copy=True จัดสรรผลลัพธ์แยกต่างหาก copy_to_fb=True วางผลลัพธ์ในบัฟเฟอร์เฟรมสำหรับการแสดงตัวอย่างใน IDE

5.21.2. การสอดแทรก: AREA, BILINEAR, BICUBIC

เมื่อการปรับขนาดส่งพิกเซลเอาต์พุตแต่ละตัวไปยังตำแหน่งที่ไม่ตรงกับพิกเซลอินพุตใดตัวเดียว วิธีการต้องเลือกค่าที่จะเขียน แฟล็กสามตัวควบคุมวิธีการ:

image.BILINEAR สอดแทรกระหว่างพิกเซลอินพุตที่ใกล้ที่สุดสี่ตัวโดยถ่วงน้ำหนักด้วยระยะห่างจากตำแหน่งเอาต์พุต ผลลัพธ์จะเรียบกว่าแบบ nearest-neighbour โดยไม่มีรอยหยักที่มองเห็นบนเส้นทแยงมุม แต่การคำนวณเพิ่มเติมมีค่าใช้จ่ายประมาณสี่เท่าของการผ่าน nearest-neighbour เหมาะสำหรับงานขยายขนาดส่วนใหญ่และสำหรับตัวประกอบขนาดที่ไม่ใช่จำนวนเต็มใดๆ

image.BICUBIC สอดแทรกระหว่างพิกเซลอินพุตที่ใกล้ที่สุดสิบหกตัวโดยใช้เส้นโค้งลูกบาศก์ ซึ่งให้ผลลัพธ์ที่เรียบกว่าด้วยค่าใช้จ่ายในการคำนวณที่มากขึ้นอีก คุณภาพดีที่สุดสำหรับแอปพลิเคชันที่คำนึงถึงต้นทุนที่ต้องการ แทบไม่คุ้มกับการคำนวณเพิ่มเติมสำหรับเฟรมสดที่ IDE จะแสดงเท่านั้น

image.AREA เฉลี่ยพิกเซลอินพุตทุกตัวที่ตกอยู่ภายใน footprint ของพิกเซลเอาต์พุต -- อัลกอริทึมที่เหมาะสมสำหรับ การลดขนาด Bilinear และ bicubic เป็นตัวสอดแทรก: พวกมันประเมินค่า ระหว่าง พิกเซลต้นฉบับ ซึ่งเป็นสิ่งที่การขยายขนาดต้องการ แต่เมื่อลดขนาด พิกเซลเอาต์พุตแต่ละตัวครอบคลุมพิกเซลต้นฉบับหลายตัว และตัวสอดแทรกจะอ่านเฉพาะตัวที่ใกล้ที่สุดไม่กี่ตัว -- รายละเอียดที่ข้ามไปจะกลับมาเป็น aliasing image.AREA นำพิกเซลที่ครอบคลุมทุกตัวมาเฉลี่ยแทน

อัลกอริทึมการปรับขนาดเริ่มต้นโดยไม่มี hint คือ nearest-neighbour ซึ่งถูกที่สุดและเป็นคำตอบที่ถูกต้องเมื่อแหล่งที่มาอยู่ที่ความละเอียดพิกเซลของปลายทางอยู่แล้ว

5.21.3. ทิศทาง: การพลิกและการหมุน

แฟล็กทิศทางเป็นชุดการแปลงบูลีนขนาดเล็กที่ประกอบกันได้อย่างอิสระทั้งกับกันเองและกับแฟล็ก interpolation:

  • image.VFLIP พลิกภาพในแนวตั้ง (บนกลายเป็นล่าง)

  • image.HMIRROR สะท้อนภาพในแนวนอน (ซ้ายกลายเป็นขวา)

  • image.TRANSPOSE สลับแกน x และ y (แถวกลายเป็นคอลัมน์)

การหมุนส่วนใหญ่มาจากการประกอบสามตัวนั้น โมดูลยังเปิดเผยชื่อย่อ:

  • image.ROTATE_90 (= VFLIP | TRANSPOSE)

  • image.ROTATE_180 (= HMIRROR | VFLIP)

  • image.ROTATE_270 (= HMIRROR | TRANSPOSE)

ในโค้ด:

img.copy(hint=image.ROTATE_90, copy_to_fb=True)

5.21.4. การจัดการสัดส่วนภาพ

เมื่อสัดส่วนภาพของแหล่งที่มาไม่ตรงกับสี่เหลี่ยมที่กำลังวาดเข้าไป แฟล็กสามตัวจะตัดสินว่าจะทำอะไรกับความไม่ตรงกันนั้น:

image.SCALE_ASPECT_KEEP รักษาสัดส่วนภาพของแหล่งที่มาและ letterboxes ผลลัพธ์ -- แหล่งที่มาถูกปรับขนาดจนพอดีภายในปลายทาง โดยมีพิกเซลว่างเปล่า (ศูนย์) เติมส่วนที่เหลือของปลายทาง เหมาะสมเมื่อการรักษาแหล่งที่มาไม่บิดเบี้ยวมีความสำคัญกว่าการเติมเอาต์พุตทั้งหมด

image.SCALE_ASPECT_EXPAND รักษาสัดส่วนภาพของแหล่งที่มาและ ตัด มัน -- แหล่งที่มาถูกปรับขนาดจนเต็มปลายทาง โดยส่วนที่เกินปลายทางจะถูกตัดออก เหมาะสมเมื่อการเติมเอาต์พุตทั้งหมดมีความสำคัญกว่าการเห็นทุกส่วนของแหล่งที่มา

image.SCALE_ASPECT_IGNORE ละเว้นสัดส่วนภาพและยืดแหล่งที่มาเพื่อเติมปลายทาง โดยยอมรับความบิดเบี้ยวใดก็ตามที่เกิดขึ้น เหมาะสมเมื่อแอปพลิเคชันได้คำนึงถึงความบิดเบี้ยวแล้ว -- เช่น เมื่อขนาดของปลายทางไม่ใช่สี่เหลี่ยมของฉากเดียวกันจริงๆ

ค่าเริ่มต้น (ไม่มีแฟล็ก aspect ตั้งค่า) เหมือนกับ SCALE_ASPECT_IGNORE: ยืดเพื่อเติม แอปพลิเคชันที่ใส่ใจสัดส่วนภาพจะระบุหนึ่งในสามตัวอย่างชัดเจน

5.21.5. เมื่อใดควรใช้อะไร

การปรับขนาดส่วนใหญ่ใช้ scale() กับคู่ x_scale / y_scale และ hint การสอดแทรก:

img.scale(x_scale=0.5, y_scale=0.5, hint=image.AREA)

การหมุนส่วนใหญ่ใช้การเรียกเดียวกันกับ hint=image.ROTATE_90 หรือที่คล้ายกัน

การตัดภาพใช้ crop() กับ roi ที่ไม่ใช่ค่าเริ่มต้น:

img.crop(roi=(40, 30, 200, 150))

เมื่อแหล่งที่มาต้องรอดจากการดำเนินการ -- การจับเฟรมอ้างอิง การสร้างภาพย่อของเฟรมที่กำลังจะถูกประมวลผลอย่างทำลาย -- copy() สร้างผลลัพธ์เป็นภาพใหม่และปล่อยให้แหล่งที่มาไม่เปลี่ยนแปลง:

thumbnail = img.copy(x_scale=0.25, y_scale=0.25, hint=image.AREA)

ค่าเริ่มต้นนั้นคือความแตกต่างที่แท้จริงเบื้องหลังชื่อทั้งสาม: scale และ crop แปลงในที่ copy จัดสรร คีย์เวิร์ดการวางผลลัพธ์เชื่อมช่องว่าง: copy=True บน scale หรือ crop จัดสรรผลลัพธ์เป็น heap buffer แยกต่างหากแทนที่จะเขียนทับแหล่งที่มา และ copy_to_fb=True บนทั้งสามตัวจะวางไว้ในบัฟเฟอร์เฟรมสำหรับการแสดงตัวอย่างใน IDE