4.16. Xem trước ảnh

Bộ đệm khung hình là nơi ứng dụng đọc các khung hình của nó. Trong khi ứng dụng đang làm việc trên các khung hình đó, bất cứ thứ gì được kết nối với camera để xem trước chúng cũng cần một bản sao của mỗi khung hình. Camera có một bộ đệm thứ hai, chuyên dụng cho mục đích đó, và một quy tắc duy nhất cho khi nó được điền: mỗi khi ứng dụng gọi snapshot(), khung hình đã chụp trước đó được sao chép vào bộ đệm xem trước trước khi khung hình mới được trả về.

Ứng dụng và bộ xem trước không bao giờ tranh chấp cùng một bộ nhớ. Ứng dụng đọc khung hình của nó từ bộ đệm khung hình; bộ xem trước đọc khung hình của nó từ bộ đệm xem trước. Cả hai diễn ra song song.

4.16.1. Bộ đệm khung hình luồng

Bộ đệm xem trước -- bộ đệm khung hình luồng -- là một vùng RAM cố định kích thước đơn, tách biệt với bộ đệm khung hình. Kích thước của nó được đặt tại thời điểm xây dựng firmware và không thay đổi với framesize() hoặc pixformat(). Khoảng một megabyte là điển hình trên các OpenMV Cam gần đây -- đủ lớn để chứa bản xem trước độ phân giải vừa phải, nhỏ hơn nhiều so với một khung hình độ phân giải đầy đủ ở kích thước cảm biến lớn nhất.

Mã ứng dụng không đọc hoặc ghi trực tiếp vào bộ đệm này; trình điều khiển camera điền vào nó như một tác dụng phụ của snapshot().

4.16.2. Những gì snapshot làm cho bản xem trước

Trên mỗi lần gọi snapshot(), trước khi trình điều khiển giải phóng bộ đệm khung hình trước đó của ứng dụng trở lại bộ đệm và trao bộ đệm mới ra, nó sao chép khung hình trước đó vào bộ đệm xem trước -- cùng với bất cứ thứ gì ứng dụng đã vẽ lên trên nó trong quá trình xử lý vẫn còn trên ảnh. Có hai nhánh có thể xảy ra. Nhánh nào chạy được chọn bởi bộ xem trước, không phải bởi camera: người dùng đã mở bản xem trước nói với trình điều khiển rằng nó muốn ảnh thô hay JPEG, và kích thước cửa sổ thô nào nó có thể chấp nhận.

  • Sao chép thô thu nhỏ. Khi bộ xem trước yêu cầu khung hình thô, trình điều khiển sao chép khung hình trước đó qua định dạng điểm ảnh gốc của nó (RGB565, thang xám, v.v.). Nếu khung hình lớn hơn cửa sổ thô mà bộ xem trước yêu cầu, trình điều khiển thu nhỏ nó bằng bộ lọc song tuyến tính cho đến khi nó vừa vặn; nếu không, các điểm ảnh đi qua không thay đổi. Không có hiện tượng nén; bộ xem trước thấy các điểm ảnh giống như ứng dụng đang làm việc.

  • Nén JPEG. Khi bộ xem trước yêu cầu JPEG -- hoặc khi bản sao thô không vừa trong bộ đệm luồng -- trình điều khiển nén JPEG khung hình trước đó ở độ phân giải đầy đủ vào bộ đệm luồng. Chất lượng được điều chỉnh thích ứng theo từng khung hình để đầu ra nén vừa trong dung lượng bộ đệm luồng. Khi một khung hình vừa vặn, trình điều khiển tăng dần chất lượng lên một bước về phía mức trần phụ thuộc vào kích thước điểm ảnh của khung hình đã chụp (các khung hình nhỏ hơn được phép chất lượng cao hơn; các khung hình lớn hơn bị giới hạn thấp hơn để chúng không thể tràn khi nội dung thay đổi nhỏ). Khi một khung hình không vừa, trình điều khiển giảm một nửa chất lượng hiện tại, giữ ở mức giảm cho vài chục khung hình tiếp theo để cài đặt mới có thời gian ổn định, và bỏ khung hình tràn ra khỏi bản xem trước. Vòng lặp ứng dụng tiếp tục chạy không bị ảnh hưởng; chỉ bộ xem trước bỏ lỡ khung hình bị loại bỏ.

Các khung hình mà camera tạo ra ở định dạng đã nén (định dạng điểm ảnh JPEG trên các cảm biến phát JPEG trực tiếp) bỏ qua cả hai nhánh: luồng bit đã mã hóa được sao chép thẳng vào bộ đệm xem trước nguyên vẹn.

Bộ xem trước thăm dò theo lịch trình riêng của nó, thường chậm hơn nhiều so với tốc độ camera chụp, vì vậy nó lấy mẫu con tốc độ chụp thô: chỉ những lần chụp mà nó kịp đọc được mới được hiển thị. Nếu một snapshot() mới đến bộ đệm xem trước trước khi bộ xem trước đã đọc khung hình trước đó, bộ đệm vẫn bị khóa bởi bộ xem trước và bản cập nhật xem trước mới bị bỏ qua -- lần chụp đó bị mất khỏi luồng xem trước. Bộ đệm khung hình riêng của ứng dụng không bị ảnh hưởng; khung hình đã chụp vẫn đến ứng dụng bình thường.

4.16.3. Đẩy khung hình cuối cùng theo cách thủ công

Vì bản xem trước được cập nhật như một tác dụng phụ của snapshot(), một tập lệnh kết thúc mà không gọi snapshot lần nữa sẽ để lại bất cứ thứ gì nó gửi cuối cùng đến bản xem trước ngồi mãi trên bộ xem trước -- đối với một tập lệnh thực hiện công việc trước lần chụp đầu tiên rồi thoát, đây là bản xem trước trống. image.Image.flush() (hoặc tương đương flush() trên đối tượng CSI) sao chép nội dung hiện tại của bộ đệm khung hình ứng dụng vào bộ đệm luồng theo yêu cầu, mà không chụp khung hình mới:

img = csi0.snapshot()
# process the image and draw on it
img.flush()                               # previewer sees the annotated frame

Lần gọi tương tự cũng hữu ích khi một thao tác chạy lâu nằm giữa các lần chụp và bộ xem trước sẽ hiển thị bản xem trước cũ trong toàn bộ thời gian đó.

Ghi chú

Ứng dụng xem trước phải đọc khung hình từ bộ đệm luồng trước khi tập lệnh thoát. Một lần flush ở cuối tập lệnh ngắn chỉ dàn dựng khung hình; nếu tập lệnh sau đó trả lại quyền điều khiển cho camera trước khi bộ xem trước đã thăm dò, bộ đệm được tái sử dụng trong lần chạy tiếp theo và khung hình cuối cùng đó bị mất. Đối với bản xem trước cuối tập lệnh, hãy cho bộ xem trước một khoảnh khắc để lấy khung hình (một khoảng ngủ ngắn sau lần flush, hoặc đơn giản là không thoát ngay lập tức) trước khi tập lệnh kết thúc.