一、引言

庐山派 K230 是一款功能强大的开发板,具备丰富的硬件资源和多样化的接口,为开发者提供了广阔的应用开发空间。本文将围绕庐山派 K230 开发板,详细阐述如何实现按键(触摸)拍照并保存到 TF 卡、图像边缘检测以及多通道显示等功能。通过对代码的深入分析和详细注释,帮助开发者更好地理解和掌握相关技术,为后续的开发工作奠定基础。

二、功能概述

本次开发主要实现了以下几个核心功能:

  1. 按键与触摸拍照:用户既可以通过物理按键,也可以通过触摸屏幕的特定区域来触发拍照功能,拍摄的照片将被保存到 TF 卡中。
  2. 图像边缘检测:对摄像头捕获的图像进行边缘检测处理,增强图像的特征信息,以便后续的图像分析和处理。
  3. 多通道显示:利用摄像头的多个通道同时捕获不同分辨率和格式的图像,并在显示屏上进行多窗口显示,提供更丰富的视觉信息。

三、代码实现与详细解释

3.1 导入必要的库

import time, os, sys
from media.sensor import *
from media.display import *
from media.media import *
from machine import Pin
from machine import FPIOA
import time
from machine import Timer
from machine import TOUCH
from machine import WDT

  • time:用于处理时间相关的操作,如延时、计时等。
  • os:提供了与操作系统进行交互的功能,如文件操作、系统退出点设置等。
  • sys:包含了一些与 Python 解释器和系统相关的变量和函数。
  • media.sensor:用于操作摄像头传感器,实现图像的捕获和配置。
  • media.display:负责显示屏的初始化和图像的显示。
  • media.media:提供媒体管理相关的功能。
  • machine.Pin:用于控制开发板的 GPIO 引脚。
  • machine.FPIOA:用于引脚功能的配置。
  • machine.Timer:用于创建和管理定时器。
  • machine.TOUCH:用于处理触摸事件。
  • machine.WDT:用于实现看门狗定时器,确保系统的稳定性。

3.2 初始化硬件参数

sensor_id = 2
sensor = None

picture_width = 800
picture_height = 480
tp = TOUCH(0)
# 创建FPIOA对象,用于初始化引脚功能配置
fpioa = FPIOA()

# 设置引脚功能,将指定的引脚配置为普通GPIO功能
fpioa.set_function(62,FPIOA.GPIO62)
fpioa.set_function(20,FPIOA.GPIO20)
fpioa.set_function(63,FPIOA.GPIO63)
fpioa.set_function(53,FPIOA.GPIO53)

# 实例化Pin62, Pin20, Pin63为输出,分别用于控制红、绿、蓝三个LED灯
LED_R = Pin(62, Pin.OUT, pull=Pin.PULL_NONE, drive=7)  # 红灯
LED_G = Pin(20, Pin.OUT, pull=Pin.PULL_NONE, drive=7)  # 绿灯
LED_B = Pin(63, Pin.OUT, pull=Pin.PULL_NONE, drive=7)  # 蓝灯
# 按键引脚为53,按下时为高电平,所以这里设置为下拉并设置为输入模式
button = Pin(53, Pin.IN, Pin.PULL_DOWN)  # 使用下拉电阻
# 初始化时先关闭所有LED灯
LED_R.high()  # 关闭红灯
LED_G.high()  # 关闭绿灯
LED_B.high()  # 关闭蓝灯

status = 0
flag_button = 0
# 显示模式选择:可以是 "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'")

  • sensor_id:指定摄像头传感器的 ID。
  • picture_width 和 picture_height:定义拍摄照片的宽度和高度。
  • tp:实例化触摸模块对象。
  • fpioa:创建 FPIOA 对象,用于配置引脚功能。
  • LED_RLED_GLED_B:分别控制红、绿、蓝三个 LED 灯的引脚对象。
  • button:按键引脚对象,设置为下拉输入模式。
  • DISPLAY_MODE:选择显示模式,根据不同的模式设置显示的宽度和高度。

3.3 定时器与看门狗初始化

def LED_toggle(timer):
    """
    定时器回调函数,用于周期性地切换绿灯的状态
    :param timer: 定时器对象
    """
    LED_G.value(not LED_G.value())

# 创建一个软件定时器实例,-1 表示使用软件定时器
tim = Timer(-1)
# 配置定时器为周期模式(PERIODIC),每隔2000毫秒(2秒)调用一次 LED_toggle 函数
tim.init(period=2000, mode=Timer.PERIODIC, callback=LED_toggle)
# 实例化 WDT1,超时时间设置为 3 秒
wdt1 = WDT(1, 8)
  • LED_toggle:定时器的回调函数,用于周期性地切换绿灯的状态,作为系统运行的一个简单指示。
  • tim:创建软件定时器对象,设置为周期模式,每隔 2 秒调用一次 LED_toggle 函数。
  • wdt1:实例化看门狗定时器,超时时间设置为 3 秒,用于确保系统在出现异常时能够自动复位。

3.4 摄像头与显示初始化

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
    sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)

    # 通道2  320*240
    sensor.set_framesize(Sensor.QVGA, chn = CAM_CHN_ID_1)
    sensor.set_pixformat(Sensor.GRAYSCALE, chn = CAM_CHN_ID_1)
    # 通道3  320*240
    sensor.set_framesize(Sensor.QVGA, chn = CAM_CHN_ID_2)
    sensor.set_pixformat(Sensor.RGB565, chn = CAM_CHN_ID_2)

    # 根据模式初始化显示器
    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()

    # 丢掉前面100帧数据,防止摄像头还不稳定
    #for i in range(100):
    #    sensor.snapshot()

    fps = time.clock()
    number = 1
    read_number = 1
  • sensor:创建摄像头对象,并进行初始化和配置,包括图像尺寸、像素格式、镜像和翻转设置等。
  • Display.init:根据选择的显示模式初始化显示器。
  • MediaManager.init:初始化媒体管理器。
  • sensor.run:启动摄像头传感器。
  • fps:用于计算帧率。
  • number:用于记录保存照片的编号。

3.5 主循环处理

    while True:
        fps.tick()  # 更新帧率计数器
        os.exitpoint()  # 检查系统退出点

        img = sensor.snapshot(chn=CAM_CHN_ID_0)  # 捕获通道0的图像

        # 在图像上绘制两个同心圆
        img.draw_circle(720, 240, 25, color=(255, 255, 255), thickness = 1, fill=True)
        img.draw_circle(720, 240, 40, color=(200, 200, 200), thickness = 10)

        # 捕获通道1的图像
        src_img = sensor.snapshot(chn=CAM_CHN_ID_1)
        # 对通道1的图像进行拉普拉斯边缘检测
        src_img.laplacian(2,mul=0.2)
        # 在屏幕上显示通道1经过处理后的图像
        Display.show_image(src_img, x = 0,layer = Display.LAYER_OSD1,alpha = 80)

        sr_img = sensor.snapshot(chn=CAM_CHN_ID_2)
        #Display.show_image(sr_img, x = 800-320,layer = Display.LAYER_OSD0,alpha = 80)

        p = tp.read(1)  # 读取触摸事件
        if p!=():
            print(p)
            x, y, event = p[0].x, p[0].y, p[0].event

            if event == 2 or event == 3:
                # 在触摸位置绘制十字标记
                img.draw_cross(x, y, color = (255, 0, 0), size = 10, thickness = 6)
            if 720 - 40 < x < 720 + 40 and 240 - 40 < y < 240 + 40 and event == 2:
                # 当触摸特定区域时,拍摄照片并保存到 TF 卡
                img = sensor.snapshot()
                img = sensor.snapshot(chn=CAM_CHN_ID_0)
                img.save("/data/img_%d.bmp"%number)
                number = number + 1
                print("已按下")
                time.sleep(1)

        Display.show_image(img)  # 显示通道0的图像

        # 按键消抖
        if button.value() == 1:
            time.sleep_ms(10)  # 延时10毫秒进行消抖
            current_time = time.ticks_ms()  # 获取当前时间(单位:毫秒)
            if button.value() == 1:
                while button.value() == 1:
                    pass  # 等待按键释放
            if time.ticks_ms() - current_time <= 500:
                # 短按按键,拍摄照片并保存到 TF 卡
                src_img = sensor.snapshot(chn=CAM_CHN_ID_0)
                src_img.save("/data/img_%d.bmp"%number)
                number = number + 1
                print("保存成功")
                print(time.ticks_ms() - current_time)
            elif  time.ticks_ms() - current_time > 500:
                # 长按按键,显示上一张保存的照片
                test_img = image.Image("/data/img_%d.bmp"%(number - 1))
                #test_img.histeq()  #直方图均衡化
                Display.show_image(test_img)
                print("显示成功")
                #print(time.ticks_ms()-current_time)

        # 喂狗操作,重置 WDT 计时器
        wdt1.feed()
        # 打印帧率到控制台
       # 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()
  • fps.tick():更新帧率计数器,用于计算帧率。
  • os.exitpoint():检查系统退出点,确保程序可以安全退出。
  • sensor.snapshot():从摄像头的不同通道捕获图像。
  • img.draw_circle() 和 img.draw_cross():在图像上绘制图形,用于标记特定位置。
  • src_img.laplacian():对通道 1 的图像进行拉普拉斯边缘检测。
  • Display.show_image():在显示屏上显示图像。
  • 触摸事件处理:当触摸屏幕特定区域时,拍摄照片并保存到 TF 卡。
  • 按键事件处理:通过按键消抖处理,短按按键拍摄照片保存,长按按键显示上一张保存的照片。
  • wdt1.feed():喂狗操作,重置看门狗定时器,避免系统因超时复位。
  • try-except-finally:捕获异常并进行相应的处理,确保程序在出现异常或用户手动停止时能够安全退出,释放相关资源。

四、总结

通过以上代码的实现,我们成功利用庐山派 K230 开发板完成了按键(触摸)拍照保存到 TF 卡、图像边缘检测以及多通道显示等功能。这些功能展示了庐山派 K230 开发板在图像处理和硬件控制方面的强大能力,为后续的应用开发提供了坚实的基础。开发者可以根据实际需求对代码进行进一步的扩展和优化,实现更多复杂的功能。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐