แสดงตัวอย่างจากกล้องถ่ายรูป

หมายเหตุ: หน้านี้เกี่ยวข้องกับแพ็กเกจ camera2 เราขอแนะนำให้ใช้ CameraX เว้นแต่แอปของคุณต้องใช้ฟีเจอร์ระดับต่ำที่เฉพาะเจาะจงจาก Camera2 ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป

กล้องและการแสดงตัวอย่างจากกล้องใน Android ไม่ได้วางแนวแตกต่างกันเสมอไป อุปกรณ์

กล้องจะมีตำแหน่งคงที่ในอุปกรณ์ ไม่ว่าอุปกรณ์จะ คือโทรศัพท์ แท็บเล็ต หรือคอมพิวเตอร์ เมื่อการวางแนวของอุปกรณ์เปลี่ยน การเปลี่ยนการวางแนวกล้อง

ด้วยเหตุนี้ แอปกล้องถ่ายรูปมักมีความสัมพันธ์ที่ตายตัวระหว่าง การวางแนวของอุปกรณ์และสัดส่วนภาพแสดงตัวอย่างจากกล้อง เมื่อ โทรศัพท์อยู่ในแนวตั้ง ภาพตัวอย่างจากกล้องจะสูงกว่า มากกว่าความกว้าง เมื่อหมุนโทรศัพท์ (และกล้อง) เป็นแนวนอน การแสดงตัวอย่างจากกล้องควรจะกว้างกว่าความสูง

แต่สมมติฐานเหล่านี้ท้าทายโดยรูปแบบของอุปกรณ์ใหม่ๆ เช่น อุปกรณ์แบบพับได้ อุปกรณ์ และโหมดการแสดงผล เช่น หลายหน้าต่าง และ multi-display อุปกรณ์แบบพับได้เปลี่ยนขนาดการแสดงผลและสัดส่วนการแสดงผลโดยไม่เปลี่ยน การวางแนว โหมดหลายหน้าต่างจะจำกัดแอปกล้องให้เป็นส่วนหนึ่งของ ปรับขนาดภาพตัวอย่างจากกล้องโดยไม่คำนึงถึงการวางแนวของอุปกรณ์ โหมดหลายจอแสดงผลทำให้สามารถใช้จอแสดงผลสำรองที่อาจไม่ เป็นแนวเดียวกับจอแสดงผลหลัก

การวางแนวของกล้อง

คำจำกัดความความเข้ากันได้กับ Android ระบุว่าเซ็นเซอร์ภาพของกล้อง "ต้องตั้งทิศทางเพื่อให้ ของกล้องจะอยู่ในแนวเดียวกับด้านยาวของหน้าจอ นั่นคือเมื่อ ถืออุปกรณ์ในแนวนอน กล้องต้องจับภาพ การวางแนวแนวนอน การดำเนินการนี้จะมีผลเสมอไม่ว่าอุปกรณ์จะ การวางแนว กล่าวคือ จะใช้กับอุปกรณ์หลักแนวนอน อุปกรณ์หลักในแนวตั้ง"

การจัดเรียงกล้องให้เข้ากับหน้าจอจะขยายพื้นที่แสดงผลของกล้องให้สูงที่สุด ช่องมองภาพในแอปกล้อง นอกจากนี้ เซ็นเซอร์ภาพมักจะส่งออกข้อมูล สัดส่วนภาพแนวนอนที่ 4:3 เป็นสิ่งที่ใช้กันมากที่สุด

วันที่ เซ็นเซอร์ของโทรศัพท์และกล้องทั้งในแนวตั้ง
รูปที่ 1 ความสัมพันธ์โดยทั่วไปของเซ็นเซอร์โทรศัพท์และกล้อง การวางแนว

การวางแนวตามธรรมชาติของเซ็นเซอร์กล้องจะเป็นแนวนอน ในรูปที่ 1 เซ็นเซอร์ ของกล้องด้านหน้า (กล้องจะชี้ไปในทิศทางเดียวกับ ) จะหมุนไป 270 องศาโดยสัมพันธ์กับโทรศัพท์เพื่อให้เป็นไปตาม คำจำกัดความความเข้ากันได้กับ Android

เพื่อแสดงการหมุนเซ็นเซอร์กับแอป camera2 API ประกอบด้วย SENSOR_ORIENTATION คงที่ สำหรับโทรศัพท์และแท็บเล็ตส่วนใหญ่ อุปกรณ์จะรายงานการวางแนวเซ็นเซอร์ 270 องศาสำหรับกล้องหน้า และ 90 องศา (มุมมองจาก ด้านหลังอุปกรณ์) สำหรับกล้องหลัง ซึ่งจะจัดให้ขอบด้านยาวของ เซ็นเซอร์ที่มีขอบด้านยาวของอุปกรณ์ โดยทั่วไปแล้ว กล้องแล็ปท็อปจะรายงานว่า การวางแนวเซ็นเซอร์ 0 หรือ 180 องศา

เนื่องจากเซ็นเซอร์รูปภาพของกล้องจะส่งออกข้อมูล (บัฟเฟอร์รูปภาพ) ใน การวางแนวตามธรรมชาติของเซ็นเซอร์ (แนวนอน) บัฟเฟอร์ภาพจะต้องหมุน จำนวนองศาที่ระบุโดย SENSOR_ORIENTATION สำหรับการแสดงตัวอย่างของกล้อง จะปรากฏขึ้นตั้งตรงตามการวางแนวธรรมชาติของอุปกรณ์ สำหรับกล้องหน้า การหมุนจะทวนเข็มนาฬิกา สำหรับกล้องหลังตามเข็มนาฬิกา

เช่น สำหรับกล้องหน้ารูปที่ 1 บัฟเฟอร์รูปภาพ ที่ผลิตโดยเซ็นเซอร์กล้องมีลักษณะดังนี้

เซ็นเซอร์กล้องหมุนให้อยู่ในแนวนอนโดยมีรูปภาพ
            ไปด้านข้าง, ด้านบนซ้าย

ต้องหมุนรูปภาพทวนเข็มนาฬิกา 270 องศาเพื่อให้ภาพตัวอย่าง การวางแนวตรงกับการวางแนวของอุปกรณ์:

เซ็นเซอร์กล้องในแนวตั้งโดยตั้งรูปภาพตั้งตรง

กล้องหลังจะถ่ายบัฟเฟอร์รูปภาพที่มีการวางแนวเดียวกัน เป็นบัฟเฟอร์ด้านบน แต่ SENSOR_ORIENTATION เป็น 90 องศา ด้วยเหตุนี้ ฟิลด์ บัฟเฟอร์จะถูกหมุนตามเข็มนาฬิกา 90 องศา

การหมุนอุปกรณ์

การหมุนอุปกรณ์คือจำนวนองศาที่หมุนจากอุปกรณ์ตามปกติ การวางแนว ตัวอย่างเช่น โทรศัพท์ในแนวนอนมีอุปกรณ์ การหมุน 90 หรือ 270 องศา ขึ้นอยู่กับทิศทางการหมุน

บัฟเฟอร์ภาพเซ็นเซอร์ของกล้องจะต้องหมุนในจำนวนองศาเท่ากับ การหมุนอุปกรณ์ (นอกเหนือจากองศาการวางแนวของเซ็นเซอร์) ภาพตัวอย่างจากกล้องจะปรากฏขึ้นตั้งตรง

การคำนวณการวางแนว

การวางแนวที่เหมาะสมของการแสดงตัวอย่างจากกล้องจะพิจารณาจากเซ็นเซอร์ การวางแนวและการหมุนอุปกรณ์

การหมุนโดยรวมของบัฟเฟอร์ภาพเซ็นเซอร์สามารถคำนวณได้โดยใช้ สูตรต่อไปนี้

rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360

โดย sign คือ 1 สำหรับกล้องหน้า -1 สำหรับกล้องหลัง

สำหรับกล้องหน้า บัฟเฟอร์ภาพจะหมุนทวนเข็มนาฬิกา (จาก การวางแนวตามธรรมชาติของเซ็นเซอร์) สำหรับกล้องหลัง เซ็นเซอร์ บัฟเฟอร์ภาพถูกหมุนตามเข็มนาฬิกา

นิพจน์ deviceOrientationDegrees * sign + 360 แปลงการหมุนอุปกรณ์ สำหรับกล้องหลัง (เช่น แปลง 270 องศาทวนเข็มนาฬิกาเป็น 90 องศาตามเข็มนาฬิกา) มอดูโล การดำเนินการนี้จะปรับขนาดผลลัพธ์ให้น้อยกว่า 360 องศา (ตัวอย่างเช่น การปรับขนาด 540) องศาการหมุนเป็น 180)

API ที่ต่างกันจะรายงานการหมุนอุปกรณ์แตกต่างกันดังนี้

  • Display#getRotation() ให้การหมุนทวนเข็มนาฬิกาของอุปกรณ์ (จากจุดของผู้ใช้ ของมุมมอง) ค่านี้จะสอดคล้องกับสูตรด้านบนตามที่เป็น
  • OrientationEventListener#onOrientationChanged() จะแสดงการหมุนตามเข็มนาฬิกาของอุปกรณ์ (จากมุมมองของผู้ใช้) ลบค่าเพื่อใช้ในสูตรด้านบน

กล้องหน้า

วันที่ แสดงตัวอย่างจากกล้องและเซ็นเซอร์ทั้งในแนวนอนและเซ็นเซอร์
            อยู่ทางขวา
รูปที่ 2 การแสดงตัวอย่างและเซ็นเซอร์ของกล้องโดยที่โทรศัพท์หมุน 90 องศาเป็น แนวนอน

นี่คือบัฟเฟอร์ภาพที่เซ็นเซอร์ของกล้องสร้างขึ้นในรูปที่ 2

เซ็นเซอร์กล้องในแนวนอนโดยรูปภาพตั้งขึ้น

บัฟเฟอร์ต้องหมุนทวนเข็มนาฬิกา 270 องศาเพื่อปรับเซ็นเซอร์ การวางแนว (ดูการวางแนวกล้องด้านบน)

เซ็นเซอร์กล้องหมุนให้อยู่ในแนวแนวตั้งโดยมีรูปภาพตะแคงข้าง
            ที่ด้านขวาบน

จากนั้นบัฟเฟอร์จะหมุนทวนเข็มนาฬิกาอีก 90 องศาเพื่อ คำนึงถึงการหมุนอุปกรณ์ ซึ่งทำให้การวางแนวของ ตัวอย่างจากกล้องในรูปที่ 2:

เซ็นเซอร์กล้องหมุนให้อยู่ในแนวนอนโดยมีรูปภาพ
            ตั้งตรง

กล้องหันไปทางขวาเพื่อวางแนวนอน ดังนี้

วันที่ แสดงตัวอย่างจากกล้องและเซ็นเซอร์ทั้งในแนวนอน แต่
            เซ็นเซอร์กลับหัว
รูปที่ 3 แสดงตัวอย่างจากกล้องและเซ็นเซอร์ที่โทรศัพท์หมุน 270 องศา (หรือ -90 องศา) เป็นแนวนอน

ต่อไปนี้คือบัฟเฟอร์รูปภาพ

เซ็นเซอร์กล้องหมุนให้อยู่ในแนวนอนโดยที่รูปภาพกลับด้าน
            ลง

บัฟเฟอร์ต้องหมุนทวนเข็มนาฬิกา 270 องศาเพื่อปรับเซ็นเซอร์ การวางแนว:

เซ็นเซอร์กล้องที่จัดประเภทตามการวางแนวตั้งและแสดงรูปภาพตะแคงข้าง
            ด้านบนซ้าย

จากนั้นบัฟเฟอร์จะหมุนทวนเข็มนาฬิกาอีก 270 องศาเพื่อรองรับ การหมุนอุปกรณ์:

เซ็นเซอร์กล้องหมุนให้อยู่ในแนวนอนโดยมีรูปภาพ
            ตั้งตรง

กล้องหลัง

สำหรับกล้องหลัง กล้องหลังจะมีการวางแนวเซ็นเซอร์ 90 องศา (เช่น โดยดูจากด้านหลังของอุปกรณ์) เมื่อจัดแนวการแสดงตัวอย่างของกล้อง บัฟเฟอร์ภาพเซ็นเซอร์หมุนตามเข็มนาฬิกาตามปริมาณการหมุนเซ็นเซอร์ (แทนทวนเข็มนาฬิกาเหมือนกล้องหน้า) จากนั้นภาพ บัฟเฟอร์จะถูกหมุนทวนเข็มนาฬิกาตามปริมาณการหมุนของอุปกรณ์

วันที่ แสดงตัวอย่างจากกล้องและเซ็นเซอร์ทั้งในแนวนอน แต่
            เซ็นเซอร์กลับหัว
รูปที่ 4 โทรศัพท์ที่มีกล้องหลังในแนวนอน (เปลี่ยนเป็น 270 หรือ -90 องศา)

นี่คือบัฟเฟอร์รูปภาพจากเซ็นเซอร์กล้องในรูปที่ 4

เซ็นเซอร์กล้องหมุนให้อยู่ในแนวนอนโดยที่รูปภาพกลับด้าน
            ลง

บัฟเฟอร์ต้องหมุนตามเข็มนาฬิกา 90 องศาเพื่อปรับเซ็นเซอร์ การวางแนว:

เซ็นเซอร์กล้องที่จัดประเภทตามการวางแนวตั้งและแสดงรูปภาพตะแคงข้าง
            ด้านบนซ้าย

จากนั้นบัฟเฟอร์จะหมุนทวนเข็มนาฬิกา 270 องศาเพื่อรองรับอุปกรณ์ การหมุน:

เซ็นเซอร์กล้องหมุนให้อยู่ในแนวนอนโดยมีรูปภาพ
            ตั้งตรง

สัดส่วนภาพ

อัตราส่วนการแสดงผลจะเปลี่ยนเมื่อการวางแนวของอุปกรณ์เปลี่ยน แต่เมื่อเปลี่ยนตามแนว อุปกรณ์แบบพับได้พับและกางออกเมื่อปรับขนาดหน้าต่างในหลายหน้าต่าง สภาพแวดล้อม และเมื่อแอปเปิดขึ้นในจอแสดงผลรอง

บัฟเฟอร์ภาพเซ็นเซอร์ของกล้องถ่ายรูปจะต้องอยู่ในแนวและปรับขนาดให้ตรงกับ การวางแนวและสัดส่วนภาพขององค์ประกอบ UI ของช่องมองภาพเป็น UI เปลี่ยนการวางแนวแบบไดนามิก ไม่ว่าอุปกรณ์จะเปลี่ยนหรือไม่ การวางแนว

ในรูปแบบของอุปกรณ์ใหม่ๆ หรือในสภาพแวดล้อมหลายหน้าต่างหรือหลายจอแสดงผล หาก แอปจะถือว่าตัวอย่างจากกล้องมีการวางแนวเดียวกันกับอุปกรณ์ (แนวตั้งหรือแนวนอน) ตัวอย่างของคุณอาจจัดวางไม่ถูกต้อง มีการปรับขนาด ไม่ถูกต้อง หรือทั้งคู่

วันที่ อุปกรณ์แบบพับได้กางออกและเปิดการแสดงตัวอย่างด้วยกล้องแนวตั้ง
            ไปด้านข้าง
รูปที่ 5 อุปกรณ์แบบพับได้เปลี่ยนจากแนวตั้งเป็นแนวนอน แต่เซ็นเซอร์กล้องจะยังคงอยู่ในแนวตั้ง

ในรูปที่ 5 แอปพลิเคชันเข้าใจผิดว่าอุปกรณ์หมุน 90 องศา องศาทวนเข็มนาฬิกา และแอปจะหมุนตัวอย่างในจำนวนที่เท่ากัน

วันที่ อุปกรณ์แบบพับได้กางออกพร้อมการแสดงตัวอย่างจากกล้องตั้งตรงแต่บีบ
            เพราะการปรับขนาดไม่ถูกต้อง
รูปที่ 6 อุปกรณ์แบบพับได้เปลี่ยนจากแนวตั้งเป็นแนวนอน แต่เซ็นเซอร์กล้องจะยังคงอยู่ในแนวตั้ง

ในรูปที่ 6 แอปไม่ได้ปรับสัดส่วนภาพของบัฟเฟอร์รูปภาพเป็น โปรดเปิดใช้การปรับขนาดอย่างเหมาะสมเพื่อให้พอดีกับขนาดใหม่ของ UI การแสดงตัวอย่างจากกล้อง

โดยปกติแล้ว แอปกล้องที่ปรับทิศทางจะมีปัญหากับอุปกรณ์แบบพับได้และ อุปกรณ์ที่มีหน้าจอขนาดใหญ่อื่นๆ เช่น แล็ปท็อป

วันที่ ภาพตัวอย่างจากกล้องบนแล็ปท็อปตั้งตรง แต่ UI ของแอปตะแคงข้าง
รูปที่ 7 แอปแนวตั้งที่แก้ไขได้ในคอมพิวเตอร์แล็ปท็อป

ในรูปที่ 7 UI ของแอปกล้องตะแคงข้างเนื่องจากการวางแนวของแอป จำกัดเฉพาะแนวตั้งเท่านั้น ภาพในช่องมองภาพอยู่ในแนวที่ถูกต้อง ที่สัมพันธ์กับเซ็นเซอร์ของกล้อง

โหมดภาพแนวตั้ง

แอปกล้องที่ไม่รองรับโหมดหลายหน้าต่าง (resizeableActivity="false") และจำกัดการวางแนว (screenOrientation="portrait") หรือ screenOrientation="landscape") สามารถวางในโหมดภาพบุคคลบนหน้าจอขนาดใหญ่ เพื่อจัดแนวอย่างเหมาะสม การแสดงตัวอย่างจากกล้อง

ฝังแอปโหมดแนวตั้งแบบแนวตั้ง (Insets) แบบแนวตั้งเท่านั้นในแนวตั้ง การวางแนวแม้ว่าสัดส่วนการแสดงผลจะเป็นแนวนอนก็ตาม แอปแนวนอนเท่านั้นจะมีแถบดำด้านบน-ล่างของภาพในแนวนอน สัดส่วนการแสดงผลคือแนวตั้ง หมุนรูปภาพจากกล้องเพื่อจัดแนว กับ UI ของแอป มีการครอบตัดเพื่อให้ตรงกับสัดส่วนภาพของตัวอย่างจากกล้อง และ จากนั้นก็ปรับขนาดให้เต็มตัวอย่าง

โหมดภาพบุคคลภายในจะทริกเกอร์เมื่อสัดส่วนภาพของรูปภาพจากกล้อง เซ็นเซอร์และอัตราส่วนกิจกรรมหลักของแอปพลิเคชันไม่ตรงกัน

วันที่ การแสดงตัวอย่างจากกล้องและ UI ของแอปในแนวตั้งอย่างเหมาะสมบนแล็ปท็อป
            ปรับขนาดและครอบตัดรูปภาพตัวอย่างแบบกว้างให้พอดีกับแนวตั้ง
            การวางแนว
รูปที่ 8 แอปปรับทิศทางการตั้งโหมดแนวตั้งในโหมดภาพบุคคลภายใน แล็ปท็อป

ในรูปที่ 8 แอปกล้องแนวตั้งเท่านั้นได้หมุนเพื่อแสดง UI ตั้งตรงบนจอแสดงผลของแล็ปท็อป แอปมีแถบดำด้านบน-ล่างของภาพเนื่องจากความแตกต่าง ในอัตราส่วนระหว่างแอปแนวตั้งและแนวนอน กล้อง มีการหมุนภาพตัวอย่างเพื่อชดเชยการหมุน UI ของแอป (เนื่องจาก โหมดแนวตั้งภายใน) และรูปภาพถูกครอบตัดและปรับขนาดให้พอดีกับ การวางแนวตั้งขึ้น ซึ่งจะลดขอบเขตการมองเห็น

หมุน ครอบตัด ปรับขนาด

ระบบเรียกใช้โหมดภาพบุคคลแบบซ้อนสำหรับแอปกล้องสำหรับภาพบุคคลในจอแสดงผล ที่มีสัดส่วนภาพแนวนอน ดังนี้

วันที่ ภาพตัวอย่างจากกล้องบนแล็ปท็อปตั้งตรง แต่ UI ของแอปตะแคงข้าง
รูปที่ 9 แอปแนวตั้งแบบปรับทิศทางบนแล็ปท็อป

แอปมีแถบดำด้านบน-ล่างของภาพในแนวตั้ง:

แอปหมุนไปเป็นแนวตั้งและมีแถบดำด้านบน-ล่างของภาพ ภาพคือ
            ตะแคงข้าง ไปด้านบนทางขวา

ภาพจากกล้องจะหมุน 90 องศาเพื่อปรับทิศทางของ แอป:

ภาพเซ็นเซอร์จะหมุน 90 องศาเพื่อทำให้ตั้งตรง

รูปภาพจะถูกครอบตัดตามสัดส่วนภาพของตัวอย่างจากกล้อง จากนั้นจึงปรับขนาดเป็น เติมเต็มตัวอย่าง (ขอบเขตการมองเห็นลดลง):

รูปภาพจากกล้องที่ครอบตัดแล้วปรับขนาดให้เต็มตัวอย่างจากกล้อง

การวางแนวของเซ็นเซอร์กล้องอาจเป็นแนวตั้งในอุปกรณ์แบบพับได้ ในขณะที่สัดส่วนการแสดงผลเป็นแนวนอน

วันที่ การแสดงตัวอย่างในกล้องและ UI ของแอปหันไปด้านข้างของจอแสดงผลแบบกว้างที่กางออก
รูปที่ 10 อุปกรณ์กางออกที่มีแอปกล้องสำหรับภาพบุคคลเท่านั้นและ ในอัตราส่วนที่ต่างกันของเซ็นเซอร์กล้องและจอแสดงผล

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

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

แอปที่มีแถบดำด้านบน-ล่างของภาพในการวางแนวแบบแนวตั้ง พร้อมภาพตัวอย่างจากกล้อง
            ตั้งตรงบนอุปกรณ์แบบพับได้

API

สำหรับแอป Android 12 (API ระดับ 31) ยังควบคุมการตั้งค่าแนวตั้งอย่างชัดแจ้งได้ด้วย โดยวิธีการ SCALER_ROTATE_AND_CROP ของพร็อพเพอร์ตี้ CaptureRequest

ค่าเริ่มต้นคือ SCALER_ROTATE_AND_CROP_AUTO ซึ่งทำให้ระบบสามารถเรียกใช้โหมดแนวตั้งภายใน SCALER_ROTATE_AND_CROP_90 คือลักษณะการทำงานของโหมดภาพบุคคลตามที่อธิบายข้างต้น

อุปกรณ์บางรุ่นไม่รองรับค่า SCALER_ROTATE_AND_CROP ทุกค่า หากต้องการดูรายการ ค่าที่รองรับ การอ้างอิง CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES

กล้องถ่ายรูป X

ไลบรารี Jetpack CameraX ทำให้การสร้างช่องมองภาพของกล้อง ที่รองรับการวางแนวเซ็นเซอร์และ การหมุนอุปกรณ์ให้เป็นงานง่ายๆ

องค์ประกอบเลย์เอาต์ PreviewView สร้างการแสดงตัวอย่างจากกล้อง ปรับ การวางแนวเซ็นเซอร์โดยอัตโนมัติ การหมุนอุปกรณ์และการปรับขนาด PreviewView จะรักษาอัตราส่วนของ รูปภาพจากกล้องโดยใช้ FILL_CENTER ประเภทมาตราส่วน ซึ่งกำหนดให้รูปภาพอยู่กึ่งกลาง แต่อาจครอบตัดให้พอดีกับขนาด ของPreviewView หากต้องการให้มีแถบดำด้านบน-ล่างของภาพในกล้อง ให้กำหนดประเภทมาตราส่วนเป็น FIT_CENTER

หากต้องการเรียนรู้พื้นฐานในการสร้างตัวอย่างจากกล้องด้วย PreviewView โปรดดู ใช้การแสดงตัวอย่าง

ดูตัวอย่างการติดตั้งใช้งานที่สมบูรณ์ได้ที่ CameraXBasic ใน GitHub

ช่องมองภาพของกล้อง

ซึ่งคล้ายกับกรณีการใช้งานของตัวอย่าง กล้องมองภาพ ไลบรารีมีชุดเครื่องมือที่ช่วยให้การสร้างการแสดงตัวอย่างจากกล้องง่ายขึ้น วิธีนี้ไม่ได้ขึ้นอยู่กับ CameraX Core คุณจึงผสานรวมเข้ากับ ฐานของโค้ด Camera2 ที่มีอยู่

แทนที่จะใช้ Surface โดยตรง คุณสามารถใช้ CameraViewfinder วิดเจ็ตเพื่อแสดงฟีดกล้องสำหรับ Camera2

CameraViewfinder ใช้ TextureView หรือ SurfaceView เป็นการภายใน เพื่อแสดงฟีดกล้อง และใช้การเปลี่ยนรูปแบบที่จําเป็นกับ แสดงช่องมองภาพได้อย่างถูกต้อง ซึ่งรวมถึงการแก้ไขสัดส่วนภาพ ขนาด และการหมุน

ในการขอพื้นผิวจากออบเจ็กต์ CameraViewfinder คุณต้อง สร้าง ViewfinderSurfaceRequest

คำขอนี้มีข้อกำหนดสำหรับความละเอียดของพื้นผิวและอุปกรณ์กล้อง ข้อมูลจาก CameraCharacteristics

กำลังโทรหา requestSurfaceAsync() ส่งคำขอไปยังผู้ให้บริการแพลตฟอร์ม ไม่ว่าจะเป็น TextureView หรือ SurfaceView และรับ ListenableFuture เป็น Surface

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

Kotlin


fun startCamera(){
    val previewResolution = Size(width, height)
    val viewfinderSurfaceRequest =
        ViewfinderSurfaceRequest(previewResolution, characteristics)
    val surfaceListenableFuture =
        cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)

    Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
        override fun onSuccess(surface: Surface) {
            /* create a CaptureSession using this surface as usual */
        }
        override fun onFailure(t: Throwable) { /* something went wrong */}
    }, ContextCompat.getMainExecutor(context))
}

Java


    void startCamera(){
        Size previewResolution = new Size(width, height);
        ViewfinderSurfaceRequest viewfinderSurfaceRequest =
                new ViewfinderSurfaceRequest(previewResolution, characteristics);
        ListenableFuture<Surface> surfaceListenableFuture =
                cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest);

        Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() {
            @Override
            public void onSuccess(Surface result) {
                /* create a CaptureSession using this surface as usual */
            }
            @Override public void onFailure(Throwable t) { /* something went wrong */}
        },  ContextCompat.getMainExecutor(context));
    }

มุมมองพื้นผิว

SurfaceView เป็น วิธีสร้างการแสดงตัวอย่างจากกล้องที่ตรงไปตรงมาหากตัวอย่างไม่ได้ ต้องประมวลผลและไม่เคลื่อนไหว

SurfaceView จะหมุนบัฟเฟอร์ภาพเซ็นเซอร์ของกล้องโดยอัตโนมัติให้ตรงกัน การวางแนวจอแสดงผล ซึ่งพิจารณาทั้งการวางแนวเซ็นเซอร์และอุปกรณ์ การหมุน แต่บัฟเฟอร์รูปภาพจะมีการปรับขนาดให้พอดีกับ SurfaceView โดยไม่ต้องพิจารณาสัดส่วนการแสดงผล

คุณต้องตรวจสอบว่าสัดส่วนภาพของบัฟเฟอร์รูปภาพตรงกับ ของ SurfaceView ซึ่งทำได้โดยการปรับขนาดเนื้อหา ของ SurfaceView ในคอมโพเนนต์ onMeasure() วิธีการ:

(ซอร์สโค้ด computeRelativeRotation() อยู่ใน การหมุนเวียนแบบสัมพัทธ์ด้านล่าง)

Kotlin

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val width = MeasureSpec.getSize(widthMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)

    val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees)

    if (previewWidth > 0f && previewHeight > 0f) {
        /* Scale factor required to scale the preview to its original size on the x-axis. */
        val scaleX =
            if (relativeRotation % 180 == 0) {
                width.toFloat() / previewWidth
            } else {
                width.toFloat() / previewHeight
            }
        /* Scale factor required to scale the preview to its original size on the y-axis. */
        val scaleY =
            if (relativeRotation % 180 == 0) {
                height.toFloat() / previewHeight
            } else {
                height.toFloat() / previewWidth
            }

        /* Scale factor required to fit the preview to the SurfaceView size. */
        val finalScale = min(scaleX, scaleY)

        setScaleX(1 / scaleX * finalScale)
        setScaleY(1 / scaleY * finalScale)
    }
    setMeasuredDimension(width, height)
}

Java

@Override
void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees);

    if (previewWidth > 0f && previewHeight > 0f) {

        /* Scale factor required to scale the preview to its original size on the x-axis. */
        float scaleX = (relativeRotation % 180 == 0)
                       ? (float) width / previewWidth
                       : (float) width / previewHeight;

        /* Scale factor required to scale the preview to its original size on the y-axis. */
        float scaleY = (relativeRotation % 180 == 0)
                       ? (float) height / previewHeight
                       : (float) height / previewWidth;

        /* Scale factor required to fit the preview to the SurfaceView size. */
        float finalScale = Math.min(scaleX, scaleY);

        setScaleX(1 / scaleX * finalScale);
        setScaleY(1 / scaleY * finalScale);
    }
    setMeasuredDimension(width, height);
}

ดูรายละเอียดเพิ่มเติมเกี่ยวกับการใช้ SurfaceView เป็นตัวอย่างจากกล้องได้ที่ การวางแนวกล้อง

มุมมองพื้นผิว

TextureView มีประสิทธิภาพน้อยกว่า SurfaceView และงานอื่นๆ เพิ่มเติม แต่ TextureView ให้ขีดจำกัดสูงสุด การควบคุมการแสดงตัวอย่างจากกล้อง

TextureView จะหมุนบัฟเฟอร์รูปภาพเซ็นเซอร์ตามการวางแนวเซ็นเซอร์ ไม่ได้จัดการการหมุนอุปกรณ์หรือการปรับขนาดตัวอย่าง

การปรับขนาดและการหมุนสามารถเข้ารหัสใน เมทริกซ์ ดูวิธีการ ปรับขนาดและหมุน TextureView อย่างถูกต้อง โปรดดู รองรับพื้นผิวที่ปรับขนาดได้ในแอปกล้อง

การหมุนเวียนแบบสัมพัทธ์

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

คอมโพเนนต์ เช่น SurfaceView และ TextureView ใช้การหมุนเวียนแบบสัมพัทธ์ เพื่อกำหนดตัวคูณมาตราส่วน x และ y สำหรับรูปภาพตัวอย่าง นอกจากนี้ยังใช้เพื่อ ระบุการหมุนของบัฟเฟอร์ภาพเซ็นเซอร์

CameraCharacteristics และ Surface ชั้นเรียนเปิดใช้การคำนวณ การหมุนสัมพัทธ์ของเซ็นเซอร์กล้อง:

Kotlin

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public fun computeRelativeRotation(
    characteristics: CameraCharacteristics,
    surfaceRotationDegrees: Int
): Int {
    val sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!

    // Reverse device orientation for back-facing cameras.
    val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT
    ) 1 else -1

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360
}

Java

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public int computeRelativeRotation(
    CameraCharacteristics characteristics,
    int surfaceRotationDegrees
){
    Integer sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

    // Reverse device orientation for back-facing cameras.
    int sign = characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1;

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360;
}

เมตริกกรอบเวลา

ไม่ควรใช้ขนาดหน้าจอในการกำหนดขนาดของกล้อง ช่องมองภาพ แอปกล้องอาจกำลังทำงานในส่วนใดของหน้าจอหนึ่ง ในโหมดหลายหน้าต่างบนอุปกรณ์เคลื่อนที่หรือโหมดอิสระใน ChromeOS

WindowManager#getCurrentWindowMetrics() (เพิ่มใน API ระดับ 30) แสดงผลขนาดของหน้าต่างแอปพลิเคชันแทน ขนาดหน้าจอ เมธอดไลบรารี Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() และ WindowInfoTracker#currentWindowMetrics() ให้การสนับสนุนที่คล้ายกันโดยมีความเข้ากันได้แบบย้อนหลังกับ API ระดับ 14

การหมุน 180 องศา

การหมุน 180 องศาของอุปกรณ์ (เช่น จากการวางแนวตามธรรมชาติเป็น การวางแนวแบบธรรมชาติกลับหัว) จะไม่ทริกเกอร์ onConfigurationChanged() Callback ด้วยเหตุนี้ การแสดงตัวอย่างจากกล้องจึงอาจกลับหัวกลับหาง

หากต้องการตรวจหาการหมุน 180 องศา ให้ใช้ DisplayListener และตรวจสอบการหมุนอุปกรณ์ โดยให้มีการเรียก Display#getRotation() ในช่วง onDisplayChanged() Callback

แหล่งข้อมูลสุดพิเศษ

เวอร์ชันก่อนหน้า Android 10 มีเฉพาะกิจกรรมที่มองเห็นได้ง่ายสุดในหน้าต่างหลายหน้าต่าง สภาพแวดล้อมเคยอยู่ในสถานะ RESUMED ซึ่งทำให้ผู้ใช้สับสนเนื่องจาก ระบบไม่ได้ระบุว่ากิจกรรมใดกลับมาทำงานต่อ

Android 10 (API ระดับ 29) กลับมาให้บริการอีกครั้งเมื่อกิจกรรมที่มองเห็นได้ทั้งหมด อยู่ในสถานะ RESUMED กิจกรรมที่มองเห็นได้จะยังคงเข้าสู่ PAUSED ได้ ตัวอย่างเช่น หากกิจกรรมแบบโปร่งใสซ้อนทับกิจกรรม หรือ โฟกัสที่กิจกรรมไม่ได้ เช่น ในโหมดการแสดงภาพซ้อนภาพ (โปรดดู การรองรับการแสดงภาพซ้อนภาพ)

แอปพลิเคชันที่ใช้กล้อง ไมโครโฟน หรือโปรแกรม ทรัพยากร Singleton ใน API ระดับ 29 ขึ้นไปต้องรองรับการทำงานต่อหลายรายการ สำหรับ เช่น หากกิจกรรมที่ทำต่อ 3 กิจกรรมต้องการใช้กล้อง จะมีเพียงกิจกรรมเดียว เพื่อเข้าถึงแหล่งข้อมูลสุดพิเศษนี้ แต่ละกิจกรรมต้องใช้ onDisconnected() Callback เพื่อรับทราบสิทธิ์ล่วงหน้าในการเข้าถึงกล้องตามลำดับความสำคัญที่สูงกว่า กิจกรรม

สำหรับข้อมูลเพิ่มเติม โปรดดู เล่นต่อหลายรายการ

แหล่งข้อมูลเพิ่มเติม