摄像头应用
一、演示功能概述
摄像头拍照功能通过光学传感器与图像处理算法,实现将现实场景转化为数字图像数据的技术。它允许设备捕捉静态画面,并支持实时预览、参数调节及后期处理。本章节将以 Air8000 整机开发板为平台,演示如何通过集成摄像头模块实现多场景智能拍摄,并展示其在嵌入式视觉应用中的创新实践。
二、准备硬件环境
参考:Air8000 硬件环境清单,准备好硬件环境。
2.1 Air8000 整机开发板
2.2 30W 摄像头
三、准备软件环境
3.1 文章内容应用
1. 烧录工具:Luatools 工具
2. Air8000 烧录需要的固件和脚本文件:
内核固件:Air8000 内核固件
脚本文件:Air8000 camera演示脚本
3. LuatOS 运行所需要的 lib 文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件。
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8000 开发板中,将本篇文章中演示使用的项目文件烧录到 Air8000 开发板中。
3.2 API 介绍
camera.on(id, event, func)
注册摄像头事件回调。
参数
**参数** | **类型** | **释义** | **取值** |
id | int | camera id | camera 0写0, camera 1写1 |
event | string | 事件名称 | 字符串 |
func | function | 回调函数 | 回调函数 |
返回值
**返回值** | **类型** | **释义** | **取值** |
nil | nil | 无返回值 | nil |
例子
camera.on(0, "scanned", function(id, str)
if type(str) == 'string' then -- 如果是扫码模式(使用摄像头对二维码、条形码或其他类型的图案进行扫描和识别)
log.info("扫码结果", str)
elseif str == false then -- 如果摄像头没有正常工作
log.error("摄像头没有数据")
else -- 如果摄像头正常工作,并且不是扫码模式
log.info("摄像头数据", str)
sys.publish("capture done", true)
end
end) -- 注册 camera 0 的 "scanned" 事件
camera.preview(id, onoff)
启停 camera 预览功能,直接输出到 LCD 上,只有硬件支持的 SOC 可以运行。
参数
**参数** | **类型** | **释义** | **取值** |
id | int | camera id | camera 0写0, camera 1写1 |
onoff | boolean | 启停camera预览功能 | true开启,false停止 |
返回值
**返回值** | **类型** | **释义** | **取值** |
onoff | boolean | 是否成功启动camera预览功能 | 成功返回true,否则返回false |
例子
camera.preview(camera_id, true) -- 打开LCD预览功能(直接将摄像头数据输出到LCD)
camera.capture(id, save_path, quality)
启动摄像头拍照功能。
参数
**参数** | **类型** | **释义** | **取值** |
id | int | camera id | camera 0写0, camera 1写1 |
save_path | string/zbuff/nil | 摄像头拍照后的数据存放路径 | string/nil:文件保存路径,空则写在上次路径里,默认是/capture.jpg zbuff:将图片保存在buff内不写入文件系统 |
quality | int | jpeg压缩质量 | 1最差,占用空间小,3最高,占用空间最大而且费时间,默认1 |
返回值
**返回值** | **类型** | **释义** | **取值** |
onoff | boolean | 是否成功启动摄像头拍照功能。完成后通过camera.on设置的回调函数回调接收到的长度 | 成功返回true,否则返回false |
例子
-- 将摄像头拍照的数据存入 "/testCamera.jpg" 文件中
-- jpeg压缩质量1最差,占用空间小,3最高,占用空间大,2和3需要非常多非常多的psram,尽量不要用
camera.capture(camera_id, "/testCamera.jpg", 1)
camera.close(id)
完全关闭指定的 camera,释放相应的 IO 资源。
参数
**参数** | **类型** | **释义** | **取值** |
id | int | camera id | camera 0写0, camera 1写1 |
返回值
**返回值** | **类型** | **释义** | **取值** |
onoff | boolean | 是否成功关闭指定摄像头 | 成功返回true,否则返回false |
例子
camera.close(0)
camera.stop(id)
暂停摄像头捕获数据。仅停止了图像捕获,未影响预览功能。
注意:调用该函数 camera.preview
的 LCD 预览功能依旧存在。
参数
**参数** | **类型** | **释义** | **取值** |
id | int | camera id | camera 0写0, camera 1写1 |
返回值
**返回值** | **类型** | **释义** | **取值** |
onoff | boolean | 是否成功暂停指定摄像头 | 成功返回true,否则返回false |
例子
camera.stop(0)
四、代码示例
--[[
1. 本demo可直接在Air8000整机开发板上运行
2. 演示摄像头拍照扫码功能,通过TEST_MODE宏来选择演示的内容。
摄像头使用了如下管脚
[85, "AGPIO4", " PIN85脚, PA供电使能"],
[67, "CAM_SPI_CLK", " PIN67脚, 用作摄像头时钟"],
[66, "CAM_SPI_CS", " PIN66脚, 用作摄像头片选"],
[98, "CAM_MCLK", " PIN98脚, 用于摄像头时钟"],
[52, "GPIO153", " PIN52脚, 控制摄像头开启/关闭"],
[53, "GPIO147", " PIN53脚, 控制摄像头电源"],
[80, "I2C0_SCL", " PIN80脚, 用作摄像头复用"],
[81, "I2C0_SDA", " PIN81脚, 用作摄像头复用"],
[1, "USB_BOOT", " PIN1脚, 用作功能键"],
[16, "UART1_TX", " PIN16脚,初始化串口1"],
[17, "UART1_RX", " PIN17脚,用作输出拍摄的照片"]
3.注意:在air8000整机开发版上,因为es8311/gsensor/lcd_tp触摸/camera 用的都是I2C0(80/81脚),所以使用此demo时不能同时使用es8311/gsensor/lcd_tp触摸功能
4. 本程序使用逻辑:
4.1 如果TEST_MODE 设置为1 ,程序运行后,点击boot 键,将进行扫码测试,如果解析二维码或者条形码成功,将会打印在luatools 中。
4.2 如果TEST_MODE 设置为0,程序运行后,点击boot 键,将进行拍照测试,并且保存在本地。
]]
PROJECT = "spi_camera_demo"
VERSION = "1.0.0"
-- 实际使用时选1个就行
-- require "bf30a2"
-- require "gc0310"
require "gc032a"
sys = require("sys")
sysplus = require("sysplus")
local taskName = "SPI_CAMERA"
local TEST_MODE = 0 -- 写1 演示扫码(使用摄像头对二维码、条形码或其他类型的图案进行扫描和识别),0 演示拍照
local scan_pause = true -- 扫码启动与停止标志位
local done_with_close = false -- true 结束后关闭摄像头
local uartid = 1 -- 根据实际设备选取不同的uartid
local cspiId = 1 -- 摄像头使用SPI1、I2C0
local i2cId = 0
local camera_id
-- 初始化UART
local result = uart.setup(uartid, -- 串口id
115200, -- 波特率
8, -- 数据位
1 -- 停止位
)
-- 注册摄像头事件回调
camera.on(0, "scanned", function(id, str)
if type(str) == 'string' then
log.info("扫码结果", str)
elseif str == false then
log.error("摄像头没有数据")
else
log.info("摄像头数据", str)
sys.publish("capture done", true)
end
end)
-- 初始化按键,这里选取boot键作为功能键
local function press_key()
log.info("boot press")
sys.publish("PRESS", true)
end
gpio.setup(0, press_key, gpio.PULLDOWN, gpio.RISING)
gpio.debounce(0, 100, 1)
-- 初始化摄像头
local rawbuff, err = zbuff.create(60 * 1024, 0, zbuff.HEAP_AUTO) -- gc032a
if rawbuff == nil then
log.info(err)
end
local function device_init()
i2c.setup(i2cId, i2c.FAST)
gpio.setup(153, 0) -- PD拉低
sys.wait(500)
-- return bf30a2Init(cspiId,i2cId,25500000,TEST_MODE,TEST_MODE)
-- return gc0310Init(cspiId, i2cId, 25500000, TEST_MODE, TEST_MODE)
return gc032aInit(cspiId, i2cId, 24000000, TEST_MODE, TEST_MODE)
end
local function main_task()
sys.wait(500)
gpio.setup(147, 1, gpio.PULLUP) -- camera的供电使能脚
gpio.setup(153, 1, gpio.PULLUP) -- 控制camera电源的pd脚
sys.wait(4000)
log.info("摄像头启动")
local camera_id = device_init()
if done_with_close then
camera.close(camera_id)
else
camera.stop(camera_id)
end
log.info("按下boot开始测试")
log.info(rtos.meminfo("sys"))
log.info(rtos.meminfo("psram"))
while 1 do
result, data = sys.waitUntil("PRESS", 30000)
if result == true and data == true then
if TEST_MODE == 1 then
if scan_pause then
log.info("启动扫码")
if done_with_close then
camera_id = device_init()
end
camera.start(camera_id)
scan_pause = false
sys.wait(1000)
log.info(rtos.meminfo("sys"))
log.info(rtos.meminfo("psram"))
else
log.info("停止扫码")
if done_with_close then
camera.close(camera_id)
else
camera.stop(camera_id)
end
scan_pause = true
sys.wait(1000)
log.info(rtos.meminfo("sys"))
log.info(rtos.meminfo("psram"))
end
else
log.debug("摄像头拍照")
if done_with_close then
camera_id = device_init()
end
camera.capture(camera_id, rawbuff, 1) -- 2和3需要非常多非常多的psram,尽量不要用
result, data = sys.waitUntil("capture done", 30000)
log.info(rawbuff:used())
if done_with_close then
camera.close(camera_id)
else
camera.stop(camera_id)
end
uart.tx(uartid, rawbuff) -- 找个能保存数据的串口工具保存成文件就能在电脑上看了, 格式为JPG
rawbuff:resize(60 * 1024)
log.info(rtos.meminfo("sys"))
log.info(rtos.meminfo("psram"))
end
end
end
end
-- 启动任务时传入依赖
sysplus.taskInitEx(main_task,taskName)
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
五、功能演示
5.1 扫码功能演示
首先将 TEST_MODE 宏置 1
然后将我们的摄像头安装到板子上,并烧录代码
参考:如何使用 LuaTools 给 Air8000 烧录软件,将准备好的软件烧录进 Air8000。
烧录完毕后可以看到日志中输出摄像头启动的打印。
按下 boot 按键(下载键),就进入了扫码模式
打开 https://cli.im/text 网址,生成一个二维码。
用摄像头扫码,扫描成功则可以在日志中看到扫描的信息
5.2 拍照功能演示
首先将 TEST_MODE 宏置 0
然后将我们的摄像头安装到板子上,并烧录代码
参考:如何使用 LuaTools 给 Air8000 烧录软件,将准备好的软件烧录进 Air8000。
烧录完毕后可以看到日志中输出摄像头启动的打印。
如果想让图片输出,就需要按照下图所示,将开发板的 uart1 通过串口线链接到电脑。
打开一个可以保存数据的串口工具,用来将拍照的图片保存成文件。这里演示的工具为 SSCOM。点我获取 SSCOM
按照图片上的方式选择相应的串口,取消时间戳和分包,并将接收到的数据保存为文件。
这时按下 boot 按键(下载键),即可开始拍照。
等文件传输完毕,也就是拍照完成后。打开之前串口保存的地址,可以看到文件已经有内容了。
将文件后缀修改为.jpg 格式。
双击打开,就可以看到我们所拍摄的照片了。
六、总结
至此,我们已使用 Air8000 整机开发板 演示了 camera 的扫码和拍照功能。