第15章 获取图像
第十五章 获取图像
1. 通过摄像头获取
如果需要实时处理或者动态场景下的分析,建议选择这种方式,但是受限于环境光照,摄像头焦距等原因,可能不同的场景下做的试验会有略微差异。
import time, os, sys
from media.sensor import *
from media.display import *
from media.media import *
sensor_id = 2
sensor = None
picture_width = 400
picture_height = 240
# 显示模式选择:可以是 "VIRT"、"LCD" 或 "HDMI"
DISPLAY_MODE = "LCD"
# 根据模式设置显示宽高
if DISPLAY_MODE == "VIRT":
# 虚拟显示器模式
DISPLAY_WIDTH = ALIGN_UP(1920, 16)
DISPLAY_HEIGHT = 1080
elif DISPLAY_MODE == "LCD":
# 3.1寸屏幕模式
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 480
elif DISPLAY_MODE == "HDMI":
# HDMI扩展板模式
DISPLAY_WIDTH = 1920
DISPLAY_HEIGHT = 1080
else:
raise ValueError("未知的 DISPLAY_MODE,请选择 'VIRT', 'LCD' 或 'HDMI'")
try:
# 构造一个具有默认配置的摄像头对象
sensor = Sensor(id=sensor_id,width=1920, height=1080)
# 重置摄像头sensor
sensor.reset()
# 无需进行镜像和翻转
# 设置不要水平镜像
sensor.set_hmirror(False)
# 设置不要垂直翻转
sensor.set_vflip(False)
sensor.set_framesize(width=picture_width, height=picture_height, chn=CAM_CHN_ID_0)
# 设置通道0的输出像素格式为RGB565,要注意有些案例只支持GRAYSCALE格式
sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)
# 根据模式初始化显示器
if DISPLAY_MODE == "VIRT":
Display.init(Display.VIRT, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, fps=60)
elif DISPLAY_MODE == "LCD":
Display.init(Display.ST7701, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
elif DISPLAY_MODE == "HDMI":
Display.init(Display.LT9611, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
# 初始化媒体管理器
MediaManager.init()
# 启动传感器
sensor.run()
fps = time.clock()
while True:
fps.tick()
os.exitpoint()
# 捕获通道0的图像
src_img = sensor.snapshot(chn=CAM_CHN_ID_0)
# 在屏幕左上角显示原始图像
Display.show_image(src_img,x=0,y=0,layer = Display.LAYER_OSD0)
# 图像处理放到这里
#--------开始--------
# 这里可以插入各种图像处理逻辑,例如二值化、直方图均衡化、滤波等
# 当前示例仅仅直接显示原图,不做任何操作
#--------结束--------
# 在屏幕右上角显示处理后的图像
Display.show_image(src_img,x=DISPLAY_WIDTH-picture_width,y=0,layer = Display.LAYER_OSD1)
# 打印帧率到控制台
print(fps.fps())
except KeyboardInterrupt as e:
print("用户停止: ", e)
except BaseException as e:
print(f"异常: {e}")
finally:
# 停止传感器运行
if isinstance(sensor, Sensor):
sensor.stop()
# 反初始化显示模块
Display.deinit()
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
time.sleep_ms(100)
# 释放媒体缓冲区
MediaManager.deinit()
2. 通过TF卡获取
如果环境中不适合使用摄像头或者需要高质量的图像处理,建议使用这种方式。可以重复加载已有的测试图像要验证算法效果。
Image
类是机器视觉处理中的基础对象。此类支持从 Micropython GC、MMZ、系统堆、VB 区域等内存区域创建图像对象。此外,还可以通过引用外部内存直接创建图像(ALLOC_REF)。未使用的图像对象会在垃圾回收时自动释放,也可以手动释放内存。
支持的图像格式如下:
- BINARY
- GRAYSCALE
- RGB565
- BAYER
- YUV422
- JPEG
- PNG
- ARGB8888(新增)
- RGB888(新增)
- RGBP888(新增)
- YUV420(新增)
支持的内存分配区域:
- ALLOC_MPGC:Micropython 管理的内存
- ALLOC_HEAP:系统堆内存
- ALLOC_MMZ:多媒体内存
- ALLOC_VB:视频缓冲区
- ALLOC_REF:使用引用对象的内存,不分配新内存
image.Image(path, alloc=ALLOC_MMZ, cache=True, phyaddr=0, virtaddr=0, poolid=0, data=None)
从文件路径 path
创建图像对象,支持 BMP、PGM、PPM、JPG、JPEG 格式。
image.Image(w, h, format, alloc=ALLOC_MMZ, cache=True, phyaddr=0, virtaddr=0, poolid=0, data=None)
创建指定大小和格式的图像对象。
- w:图像宽度
- h:图像高度
- format:图像格式
- alloc:内存分配方式(默认 ALLOC_MMZ)
- cache:是否启用内存缓存(默认启用)
- phyaddr:物理内存地址,仅适用于 VB 区域
- virtaddr:虚拟内存地址,仅适用于 VB 区域
- poolid:VB 区域的池 ID,仅适用于 VB 区域
- data:引用外部数据对象(可选)
示例:
# 在 MMZ 区域创建 ARGB8888 格式的 640x480 图像
img = image.Image(640, 480, image.ARGB8888)
# 在 VB 区域创建 YUV420 格式的 640x480 图像
img = image.Image(640, 480, image.YUV420, alloc=image.ALLOC_VB, phyaddr=xxx, virtaddr=xxx, poolid=xxx)
# 使用外部引用创建 RGB888 格式的 640x480 图像
img = image.Image(640, 480, image.RGB888, alloc=image.ALLOC_REF, data=buffer_obj)
用下面这个函数就可以把摄像头拍摄到的保存到TF卡中。
image.save(path[, roi[, quality=50]])
2.1 保存一个bmp图像至TF卡中
import time, os, sys
from media.sensor import *
from media.display import *
from media.media import *
sensor_id = 2
sensor = None
picture_width = 400
picture_height = 240
# 显示模式选择:可以是 "VIRT"、"LCD" 或 "HDMI"
DISPLAY_MODE = "LCD"
# 根据模式设置显示宽高
if DISPLAY_MODE == "VIRT":
# 虚拟显示器模式
DISPLAY_WIDTH = ALIGN_UP(1920, 16)
DISPLAY_HEIGHT = 1080
elif DISPLAY_MODE == "LCD":
# 3.1寸屏幕模式
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 480
elif DISPLAY_MODE == "HDMI":
# HDMI扩展板模式
DISPLAY_WIDTH = 1920
DISPLAY_HEIGHT = 1080
else:
raise ValueError("未知的 DISPLAY_MODE,请选择 'VIRT', 'LCD' 或 'HDMI'")
try:
sensor = Sensor(id=sensor_id, width=1920, height=1080)
sensor.reset()
# 修正镜像和翻转的设置方法
sensor.set_hmirror(False)
sensor.set_vflip(False)
# 设置图像帧大小
sensor.set_framesize(width=picture_width, height=picture_height, chn=CAM_CHN_ID_0)
sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)
# 根据显示模式初始化显示
if DISPLAY_MODE == "VIRT":
Display.init(Display.VIRT, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, fps=60)
elif DISPLAY_MODE == "LCD":
Display.init(Display.ST7701, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
elif DISPLAY_MODE == "HDMI":
Display.init(Display.LT9611, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
# 初始化媒体管理器
MediaManager.init()
# 启动摄像头
sensor.run()
for i in range(100):
sensor.snapshot()
fps = time.clock()
while True:
fps.tick()
os.exitpoint()
# 捕获图像
img = sensor.snapshot(chn=CAM_CHN_ID_0)
Display.show_image(img, x=0, y=0, layer=Display.LAYER_OSD0)
# 图像处理逻辑
# 。。。
# 保存图片到data目录下
img.save("/data/img.bmp")
break
# 显示处理过后的图像
Display.show_image(img, x=DISPLAY_WIDTH - picture_width, y=0, layer=Display.LAYER_OSD1)
# 打印FPS
print(fps.fps())
except KeyboardInterrupt as e:
print("用户停止: ", e)
except BaseException as e:
print(f"异常: {e}")
finally:
# 停止传感器运行
if isinstance(sensor, Sensor):
sensor.stop()
# 反初始化显示模块
Display.deinit()
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
time.sleep_ms(100)
# 释放媒体缓冲区
MediaManager.deinit()
2.2 从TF卡读取图像
import time, os, sys
from media.sensor import *
from media.display import *
from media.media import *
picture_width = 400
picture_height = 240
# 显示模式选择:可以是 "VIRT"、"LCD" 或 "HDMI"
DISPLAY_MODE = "LCD"
# 根据模式设置显示宽高
if DISPLAY_MODE == "VIRT":
# 虚拟显示器模式
DISPLAY_WIDTH = ALIGN_UP(1920, 16)
DISPLAY_HEIGHT = 1080
elif DISPLAY_MODE == "LCD":
# 3.1寸屏幕模式
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 480
elif DISPLAY_MODE == "HDMI":
# HDMI扩展板模式
DISPLAY_WIDTH = 1920
DISPLAY_HEIGHT = 1080
else:
raise ValueError("未知的 DISPLAY_MODE,请选择 'VIRT', 'LCD' 或 'HDMI'")
try:
# 根据模式初始化显示器
if DISPLAY_MODE == "VIRT":
Display.init(Display.VIRT, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, fps=60)
elif DISPLAY_MODE == "LCD":
Display.init(Display.ST7701, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
elif DISPLAY_MODE == "HDMI":
Display.init(Display.LT9611, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
MediaManager.init()
fps = time.clock()
src_img = image.Image("/data/src_img.bmp")
Display.show_image(src_img, x=0, y=0, layer=Display.LAYER_OSD0)
while True:
fps.tick()
os.exitpoint()
# 这里以直方图均衡化作为案例,做简单的亮度/对比度增强操作。
src_img.histeq()
# 在屏幕右上角显示处理后的图像
Display.show_image(src_img, x=DISPLAY_WIDTH - picture_width, y=0, layer=Display.LAYER_OSD1)
print(fps.fps())
except KeyboardInterrupt as e:
print("用户停止: ", e)
except BaseException as e:
print(f"异常: {e}")
finally:
# 反初始化显示模块
Display.deinit()
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
time.sleep_ms(100)
# 释放媒体缓冲区
MediaManager.deinit()
本文作者:hazy1k
本文链接:https://www.cnblogs.com/hazy1k/p/18722759
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步