Skip to content

Commit 55b5c66

Browse files
Add "colormode" option
1 parent 1b0eb8d commit 55b5c66

File tree

1 file changed

+15
-28
lines changed
  • internal_filesystem/apps/com.micropythonos.camera/assets

1 file changed

+15
-28
lines changed

internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
# This code grabs images from the camera in RGB565 format (2 bytes per pixel)
2-
# and sends that to the QR decoder if QR decoding is enabled.
3-
# The QR decoder then converts the RGB565 to grayscale, as that's what quirc operates on.
4-
# It would be slightly more efficient to capture the images from the camera in L8/grayscale format,
5-
# or in YUV format and discarding the U and V planes, but then the image will be gray (not great UX)
6-
# and the performance impact of converting RGB565 to grayscale is probably minimal anyway.
7-
81
import lvgl as lv
92
from mpos.ui.keyboard import MposKeyboard
103

@@ -76,7 +69,8 @@ def onCreate(self):
7669
self.main_screen.set_size(lv.pct(100), lv.pct(100))
7770
self.main_screen.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
7871
# Initialize LVGL image widget
79-
self.create_preview_image()
72+
self.image = lv.image(self.main_screen)
73+
self.image.align(lv.ALIGN.LEFT_MID, 0, 0)
8074
close_button = lv.button(self.main_screen)
8175
close_button.set_size(self.button_width, self.button_height)
8276
close_button.align(lv.ALIGN.TOP_RIGHT, 0, 0)
@@ -149,6 +143,7 @@ def onResume(self, screen):
149143
print(f"camera app: webcam exception: {e}")
150144
if self.cam:
151145
print("Camera app initialized, continuing...")
146+
self.create_preview_image()
152147
self.set_image_size()
153148
self.capture_timer = lv.timer_create(self.try_capture, 100, None)
154149
self.status_label_cont.add_flag(lv.obj.FLAG.HIDDEN)
@@ -200,25 +195,19 @@ def set_image_size(self):
200195
self.image.set_scale(min(scale_factor_w,scale_factor_h))
201196

202197
def create_preview_image(self):
203-
self.image = lv.image(self.main_screen)
204-
self.image.align(lv.ALIGN.LEFT_MID, 0, 0)
205198
# Create image descriptor once
206199
self.image_dsc = lv.image_dsc_t({
207200
"header": {
208201
"magic": lv.IMAGE_HEADER_MAGIC,
209202
"w": self.width,
210203
"h": self.height,
211-
#"stride": self.width * 2, # RGB565
212-
"stride": self.width, # RGB565
213-
#"cf": lv.COLOR_FORMAT.RGB565
214-
"cf": lv.COLOR_FORMAT.L8
204+
"stride": self.width * (2 if self.colormode else 1),
205+
"cf": lv.COLOR_FORMAT.RGB565 if self.colormode else lv.COLOR_FORMAT.L8
215206
},
216-
#'data_size': self.width * self.height * 2, # RGB565
217-
'data_size': self.width * self.height, # gray
207+
'data_size': self.width * self.height * (2 if self.colormode else 1),
218208
'data': None # Will be updated per frame
219209
})
220210
self.image.set_src(self.image_dsc)
221-
#self.image.set_size(160, 120)
222211

223212

224213
def qrdecode_one(self):
@@ -263,7 +252,8 @@ def snap_button_click(self, e):
263252
except OSError:
264253
pass
265254
if self.current_cam_buffer is not None:
266-
filename=f"data/images/camera_capture_{mpos.time.epoch_seconds()}_{self.width}x{self.height}_RGB565.raw"
255+
colorname = "RGB565" if self.colormode else "GRAY"
256+
filename=f"data/images/camera_capture_{mpos.time.epoch_seconds()}_{self.width}x{self.height}_{colorname}.raw"
267257
try:
268258
with open(filename, 'wb') as f:
269259
f.write(self.current_cam_buffer)
@@ -345,10 +335,8 @@ def handle_settings_result(self, result):
345335
# Note: image_dsc is an LVGL struct, use attribute access not dictionary access
346336
self.image_dsc.header.w = self.width
347337
self.image_dsc.header.h = self.height
348-
#self.image_dsc.header.stride = self.width * 2 # RGB565
349-
#self.image_dsc.data_size = self.width * self.height * 2 #RGB565
350-
self.image_dsc.header.stride = self.width
351-
self.image_dsc.data_size = self.width * self.height
338+
self.image_dsc.header.stride = self.width * (2 if self.colormode else 1)
339+
self.image_dsc.data_size = self.width * self.height * (2 if self.colormode else 1)
352340
print(f"Image descriptor updated to {self.width}x{self.height}")
353341

354342
# Reconfigure camera if active
@@ -376,27 +364,27 @@ def handle_settings_result(self, result):
376364
self.status_label_cont.remove_flag(lv.obj.FLAG.HIDDEN)
377365
return # Don't continue if camera failed
378366

367+
self.create_preview_image()
379368
self.set_image_size()
380369

381370
def try_capture(self, event):
382371
#print("capturing camera frame")
383372
try:
384373
if self.use_webcam:
385-
self.current_cam_buffer = webcam.capture_frame(self.cam, "rgb565")
374+
self.current_cam_buffer = webcam.capture_frame(self.cam, "rgb565" if self.colormode else "grayscale")
386375
elif self.cam.frame_available():
387376
#self.cam.free_buffer()
388377
self.current_cam_buffer = self.cam.capture()
389378
#self.cam.free_buffer()
390379

391380
if self.current_cam_buffer and len(self.current_cam_buffer):
392381
# Defensive check: verify buffer size matches expected dimensions
393-
#expected_size = self.width * self.height * 2 # RGB565 = 2 bytes per pixel
394-
expected_size = self.width * self.height # Grayscale = 1 byte per pixel
382+
expected_size = self.width * self.height * (2 if self.colormode else 1)
395383
actual_size = len(self.current_cam_buffer)
396384

397385
if actual_size == expected_size:
398386
self.image_dsc.data = self.current_cam_buffer
399-
#image.invalidate() # does not work so do this:
387+
#self.image.invalidate() # does not work so do this:
400388
self.image.set_src(self.image_dsc)
401389
if not self.use_webcam:
402390
self.cam.free_buffer() # Free the old buffer
@@ -468,8 +456,7 @@ def init_internal_cam(width, height):
468456
xclk_freq=20000000,
469457
powerdown_pin=-1,
470458
reset_pin=-1,
471-
#pixel_format=PixelFormat.RGB565,
472-
pixel_format=PixelFormat.GRAYSCALE,
459+
pixel_format=PixelFormat.RGB565 if self.colormode else PixelFormat.GRAYSCALE,
473460
frame_size=frame_size,
474461
#grab_mode=GrabMode.WHEN_EMPTY,
475462
grab_mode=GrabMode.LATEST,

0 commit comments

Comments
 (0)