OpenMV 图像串口传输示例

news2025/1/12 0:49:56

注意:本程序根据 OpenMV采集图片通过串口发送,PC接收并保存为图片 更改。

一、例程说明

这个例程主要实现了以下功能:

1. OpenMV 端采集图像:使用OpenMV开发板上的摄像头采集实时图像数据。

2. 通过串口传输图像数据:将采集到的图像数据打包成字节流,通过串口发送到连接的PC端。

3. PC端接收并保存图像:PC端接收来自OpenMV的图像数据,并使用OpenCV库将其解码保存为图片文件。

整个过程模拟了一个简单的图像采集-传输-保存的应用场景。OpenMV负责图像采集和数据发送,PC端负责接收和保存图像。这种基于串口通信的图像传输方式,对于一些嵌入式设备与PC之间的图像交互非常有用。

通过这个示例程序,可以学习如何在OpenMV和PC端进行串口通信,以及如何处理和保存接收到的图像数据。这对于开发基于OpenMV的图像采集和传输应用很有帮助。

使用说明:先运行PC端,再打开OpenMv。

二、硬件说明

1. STM32 ARM SWD 仿真器调试器

        我最初用的是 STM32 ARM SWD 仿真器调试器中的串口 如下图:

        用这个传输速率较慢,它不支持 921600的波特率

2. TTL

        简易使用TTL能经量减少卡顿,减少传输时间。

3. openmv

三、硬件连接

四、程序编写

4.1 OpenMv代码

 1. 导入模块

import sensor
import image
import ustruct
import pyb
from pyb import Pin

程序导入了 sensor 模块、image 模块、ustruct 模块、pyb 模块和 Pin 类。其中,sensor 模块和 image 模块是用于控制 OpenMV 摄像头的模块,ustruct 模块用于打包和解包数据,pyb 模块用于控制 OpenMV 开发板的外设,Pin 类用于控制开发板的引脚。

 2. 初始化摄像头和串口

sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # or sensor.RGB565
sensor.set_framesize(sensor.QVGA) # or sensor.QVGA (or others)
sensor.skip_frames(time = 2000) # Let new settings take affect.

uart = pyb.UART(3, 921600)  # 选择合适的串口号和波特率

程序使用 sensor.reset() 函数初始化摄像头,并设置摄像头的像素格式为 RGB565,帧大小为 QVGA。然后,程序使用 pyb.UART() 函数初始化串口,选择合适的串口号和波特率。

注意:帧对传输速率的影响 VAG ( 图片最大,速度最慢 )

                                            QVAG ( 图片中等,速度中等 )                                           

                                            QQVAG ( 图片最小,速度最快 )

           如果 921600 波特率不行,建议减小波特率。

  3. 定义捕获和发送图像的函数

def capture_and_send_image():
    # 捕获图像
    img = sensor.snapshot()

    # 将图像转换为JPEG格式
    img_compressed = img.compress(quality=50)  #质量可以修改为 10 ~ 90

    # 计算图像大小
    size = ustruct.pack("<L", len(img_compressed))

    # 发送图像大小和数据
    uart.write(size)
    uart.write(img_compressed)

    # 等待接收到确认信号
    while uart.any() == 0:
        pass

    # 接收确认信号
    confirmation = uart.read(1)

    # 如果接收到的确认信号为 "#"
    if confirmation == b'#':
        # 发送停止信号 "#"
        uart.write(b'#')

定义一个名为 capture_and_send_image() 的函数,用于捕获图像并发送到串口。函数的主要步骤如下:

  • 使用 sensor.snapshot() 函数捕获实时图像数据。
  • 使用 img.compress() 函数将图像数据压缩为 JPEG 格式,质量为 50。
  • 使用 ustruct.pack() 函数将压缩后的图像大小打包为 4 字节的字节流。
  • 使用 uart.write() 函数将图像大小和压缩后的图像数据发送到串口。
  • 使用 uart.any() 函数等待串口接收到确认信号。
  • 使用 uart.read() 函数读取串口接收到的确认信号。
  • 如果接收到的确认信号为 #,则发送停止信号 #

  4. 主循环

while True:
    capture_and_send_image()

程序使用一个无限循环不断调用 capture_and_send_image() 函数,实现连续捕获和发送图像的功能。

4.2 PC端代码

主要功能是在 PC 端接收通过串口传输的图像数据,并将接收到的图像数据解码并显示出来。

  1. 导入所需的模块

from ast import Import
import cv2
import serial
import struct
import time
import numpy as np

代码导入了 ast 模块的 Import 类,cv2 模块用于图像处理和显示,serial 模块用于串口通信,struct 模块用于打包和解包数据,time 模块用于添加延时,numpy 模块用于处理图像数据。

  2. 打开串口

ser = serial.Serial('COM4', 921600)

代码使用 serial.Serial() 函数打开串口,并指定串口号和波特率。需要将 'COM4' 替换为你实际使用的串口号,当然波特率也同openmv一致。

  3. 显示图像的函数

def imshow(img):
    cv2.imshow("Received Image", img)
    cv2.waitKey(1)
    key = cv2.waitKey(1)
    if key == 32:  # 空格退出
        cv2.destroyAllWindows()
        while True:
            pass

这个函数用于解码并显示图像。它使用 cv2.imshow() 函数显示图像,使用 cv2.waitKey() 函数等待按键输入。如果按下空格键,窗口将关闭。

  4. 接收和保存图像的函数

def receive_and_save_image(output_path, file_preserve):
    size_data = ser.read(4)
    size = struct.unpack("<L", size_data)[0]

    image_data = ser.read(size)

    img = cv2.imdecode(np.frombuffer(image_data, dtype=np.uint8), cv2.IMREAD_COLOR)

    if file_preserve == 1:
        with open(output_path, 'wb') as file:
            file.write(image_data)

    ser.write(b'#')

    stop_signal = ser.read(1)
    if stop_signal == b'#':
        return img, True
    else:
        return img, False

这个函数用于接收通过串口传输的图像数据,并将图像数据解码为图像。它首先读取图像大小,然后根据大小读取图像数据。接下来,使用 cv2.imdecode() 函数将图像数据解码为图像。如果 file_preserve 参数为 1,则将图像数据保存到指定的文件路径。然后,发送确认信号 # 到串口,并等待接收停止信号。如果接收到停止信号 #,则返回解码后的图像和 True;否则返回解码后的图像和 False

  5. 主循环

output_image_path = 'received_image.jpg'

while True:
    #key = int(input("请输入: "))
    key = 1
    if key == 0:
        break
    
    while key == 1:
        img, uart_img_key = receive_and_save_image(output_image_path, 0)
        if uart_img_key:
            imshow(img)
            break

这个循环用于不断接收和显示图像。在循环内部,调用 receive_and_save_image() 函数接收图像,并将返回的图像数据传递给 imshow() 函数进行显示。如果接收到的图像数据有效,即 uart_img_key 为 True,则退出内部循环。

这里key可以换成输入,来进行调试。

 6. 关闭串口和窗口

ser.close()
cv2.destroyAllWindows()

在循环结束后,关闭串口和窗口。

五、总代码

5.1 OpenMv

import sensor
import image
import ustruct
import pyb
from pyb import Pin


sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # or sensor.RGB565
sensor.set_framesize(sensor.QVGA) # or sensor.QVGA (or others)
sensor.skip_frames(time = 2000) # Let new settings take affect.

# 初始化相机
#sensor.reset()
#sensor.set_pixformat(sensor.RGB565)
#sensor.set_framesize(sensor.VGA)  # 分辨率可以修改为QQVGA、QVGA等
#sensor.skip_frames(time=500)

# 初始化串口
#uart = pyb.UART(3, 115200)  # 选择合适的串口号和波特率
uart = pyb.UART(3, 921600)  # 选择合适的串口号和波特率

# 初始化I/O
#p_in = Pin('P9', Pin.IN, Pin.PULL_UP)#设置p_in为输入引脚,并开启上拉电阻
# value = p_in.value() # get value, 0 or 1#读入p_in引脚的值

# 捕获并发送图像
def capture_and_send_image():
    # 捕获图像
    img = sensor.snapshot()

    # 将图像转换为JPEG格式
    img_compressed = img.compress(quality=50)  #质量可以修改为 10 ~ 90

    # 计算图像大小
    size = ustruct.pack("<L", len(img_compressed))

    # 发送图像大小和数据
    uart.write(size)
    uart.write(img_compressed)

    # 等待接收到确认信号
    while uart.any() == 0:
        pass

    # 接收确认信号
    confirmation = uart.read(1)

    # 如果接收到的确认信号为 "#"
    if confirmation == b'#':
        # 停止发送图像
        #while uart.any():
        #if uart.any():
        #    uart.readchar()

        # 发送停止信号 "#"
        uart.write(b'#')

# 主循环
while True:
    capture_and_send_image()  # 捕获并发送图片

5.2 PC端

#coding:GBK
from ast import Import
import cv2
import serial
import struct
import time
import numpy as np

# 打开串口
ser = serial.Serial('COM4', 921600)  # 将 COM1 替换为你的串口号和相应的波特率
#ser = serial.Serial('COM3', 115200)  # 将 COM1 替换为你的串口号和相应的波特率
 

def imshow (img):
    # 解码图像数据
    #img = cv2.imdecode(np.frombuffer(image_data, dtype=np.uint8), cv2.IMREAD_COLOR)

    # 显示图像
    cv2.imshow("Received Image", img)
    cv2.waitKey(1)
    key = cv2.waitKey(1)
    if key == 32: #空格退出
        cv2.destroyAllWindows()
        while True:
            pass
    



# 接收图像并保存
#file_preserve = 1 保存图片文件
def receive_and_save_image(output_path, file_preserve):
    # 读取图像大小
    size_data = ser.read(4)
    size = struct.unpack("<L", size_data)[0]

    # 读取图像数据
    image_data = ser.read(size)
    
    # 解码图像数据
    img = cv2.imdecode(np.frombuffer(image_data, dtype=np.uint8), cv2.IMREAD_COLOR)
    

    # 保存图像
    if file_preserve == 1:
        with open(output_path, 'wb') as file:
            file.write(image_data)

    # 发送确认信号 "#"
    ser.write(b'#')

    # 接收停止信号
    stop_signal = ser.read(1)
    if stop_signal == b'#':
        #imshow(image_data)
        return img,True
    else:
        return img,False

# 图像保存路径
output_image_path = 'received_image.jpg'


while True:
    # 在需要延时的地方调用sleep()函数
    #time.sleep(0.01)  # 延时0.1秒
    # 循环接收并保存图像
    #key = int(input("请输入: "))
    key = 1
    if key == 0:
        break
    
    while key == 1:
        img, uart_img_key = receive_and_save_image(output_image_path, 0, 0)
        if uart_img_key:
            imshow(img)
            break

# 关闭串口
ser.close()
cv2.destroyAllWindows()

六、相关资料

1. OpenMV采集图片通过串口发送,PC接收并保存为图片

2. OpenMv详细参数

3. Visual Studio Installer 安装python库

4. Visual Studio Installer 运行python 汉字

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1654525.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Github使用教程(流畅登录)

『教程』手把手教你流畅访问Github_哔哩哔哩_bilibili 根据以上视频整理。 1)uu.163.com 下载加速器 2&#xff09;搜索学术资源 3&#xff09;会弹出这个网页 4&#xff09;此时再从github上下载项目会变快 5&#xff09;下载完成后&#xff0c;结束加速。 视频中还分享…

Springboot+vue项目健身房课程预约平台

开发语言&#xff1a;Java 开发工具:IDEA /Eclipse 数据库:MYSQL5.7 应用服务:Tomcat7/Tomcat8 使用框架:springbootvue JDK版本&#xff1a;jdk1.8 本系统主要实现了首页、个人中心、用户管理、教练管理、会员卡管理、购买会员管理、课程类型管理、课程信息管理、课程购买…

Spring Task及订单状态定时处理

1&#xff1a;Spring Task概念&#xff1a; Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑 定时任务的理解 定时任务即系统在特定时间执行一段代码&#xff0c;它的场景应用非常广泛&#xff1a; 购买游戏的月卡会员后&a…

数据结构-线性表-链表-2.3-6

有一个带头结点的单链表L&#xff0c;设计一个算法使其元素递增有序。 void sort(Linklist &L){LNode *pL->next,*pre;LNode *rp->next;p->nextNULL;pr;while(p){rp->next;preL;while(pre->next!NULL&&pre->next->data<p->data){prepre…

最新AI实景自动无人直播软件:智能讲解、一键开播,享受24小时自动专业直播体验

在现今数字化时代&#xff08;ai无人直播下载&#xff1a;hzzxar&#xff09;直播行业越来越受到人们的关注和喜爱。随着人工智能的不断发展&#xff0c;AI实景自动无人直播软件应运而生&#xff0c;为商家提供了更便捷、高效的直播方式。本文将介绍如何利用这一创新技术&#…

Flutter笔记:美工设计.导出视频到RIVE

Flutter笔记 美工设计.导出视频到RIVE - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28…

图像处理之SVD检测显示屏缺陷(C++)

图像处理之SVD检测显示屏缺陷&#xff08;C&#xff09; 文章目录 图像处理之SVD检测显示屏缺陷&#xff08;C&#xff09;前言一、SVD算法简介二、代码实现总结 前言 显示屏缺陷检测是机器视觉领域的一处较广泛的应用场景&#xff0c;显示屏主要有LCD和OLED&#xff0c;缺陷类…

4.5_shell的执行流控制

##1.for语句## &#xff08;1&#xff09;for语句作用 为循环执行动作 &#xff08;2&#xff09;for语句结构 for 定义变量 do 使用变量&#xff0c;执行动作 done 结束标志 &#xff08;3&#xff09;for语句的基本格式 格式1 格式1&#xff1a;#!/b…

现身说法暑期三下乡社会实践团一个好的投稿方法胜似千军万马

作为一名在校大学生,去年夏天我有幸参与了学院组织的暑期大学生三下乡社会实践活动,这段经历不仅让我深入基层,体验了不一样的生活,更是在新闻投稿的实践中,经历了一次从传统到智能的跨越。回忆起那段时光,从最初的邮箱投稿困境,到后来智慧软文发布系统的高效运用,每一步都刻印…

(六)JSP教程——out对象

out对象是在JSP中经常使用到的对象&#xff0c;它本质上是一个输出流&#xff0c;前面已经多次使用&#xff0c;我们经常使用它的print()和println()方法&#xff0c;这些方法主要用于实现客户端数据的输出。通过out对象也可以直接向客户端发送一个由程序动态生成的HTML文件。 …

PPPoE实验新手必备:从0到1的网络配置指南!

5月18日&#xff0c;思科华为初级网工课程&#xff0c;等你免费试听 V&#xff1a;glab-mary 今天带大家学习一下华为PPPoE实验配置 01、实验拓扑 02、实验需求 1.完成PPP封装 2.完成PPP的PAP验证 3.完成PPP的CHAP验证 4.完成R1和R2之间的PPPOE 03、实验步骤 a . PPP封…

内存卡罢工,数据危机?别急,有救!

在日常生活和工作中&#xff0c;我们越来越依赖于各种电子设备来存储重要数据。其中&#xff0c;内存卡因其便携性和大容量而广受欢迎。然而&#xff0c;当内存卡突然损坏打不开时&#xff0c;我们该如何应对&#xff1f;本文将为您详细解析这一问题&#xff0c;并提供有效的解…

c语言实现贪吃蛇小游戏————附全代码!!!

目录 1.Win32 API 1.1控制台应用程序 1.2控制台的名称&#xff0c;控制台窗口大小 1.3设置控制台光标位置 COORD - 光标坐标 GetStdHandle - 获取句柄 SetConsoleCursorPosition - 设置光标位置 封装一个设置光标的函数 1.4设置控制台光标的属性 CONSOLE_CURSOR_INFO …

Cargo - 构建 rust项目、管理依赖包

文章目录 关于 Cargo构建项目创建工程编译运行buildclean 管理依赖添加依赖updatecheck计时 manual rust 安装可参考&#xff1a;https://blog.csdn.net/lovechris00/article/details/124808034 关于 Cargo Cargo 官方文档 &#xff1a; https://doc.rust-lang.org/cargo/crat…

泛型编程四:容器

文章目录 前言一、序列容器verctor 总结 前言 STL有六大部件&#xff0c;容器、算法、仿函数、迭代器、适配器和分配器。除了算法是函数模板&#xff0c;其他都是类模板。容器可以分为序列容器和关联容器。常见的序列容器有vector、array、deque、list、forward-list&#xff…

;【排列【

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

【Kolmogorov-Arnold网络 替代多层感知机MLPs】KAN: Kolmogorov-Arnold Networks

KAN: Kolmogorov-Arnold Networks 论文地址 代码地址 知乎上的讨论&#xff08;看一下评论区更正&#xff09; Abstract Inspired by the Kolmogorov-Arnold representation theorem, we propose Kolmogorov-Arnold Networks (KANs) as promising alternatives to Multi-Layer…

1.使用uniapp搭建微信小程序项目并引入前端组件资源

文章目录 1. 项目配置1.1. 新建vue3项目1.2. 关联云空间1.3. 运行到微信开发者工具 2. 前端组件2.1. uniCloud的内置组件和扩展组件2.2. uView3.02.3. 在uniapp项目引入uview3 1. 项目配置 1.1. 新建vue3项目 由于我们要使用vue3而不是vue2&#xff0c;所以要选好版本&#x…

移动端底层事件(如左滑返回事件)在同一个路由下不同页面需要不同的处理要怎样才能做到统一处理?

目录 一、问题 二、解决方法 三、总结 tiips:如嫌繁琐&#xff0c;直接移步总结即可&#xff01; 一、问题 1.测试提了个bug:进入了一个模块A里面的子页面 a1,左滑后按照用户预期应该是返回到模块A,结果回到了app首页。 二、解决方法 1.一开始&#xff1a;啊&#xff0c;…

分布式与一致性协议之ZAB协议(七)

ZAB协议 ZAB协议:如何处理读写请求 你应该有这样的体会&#xff0c;如果你想了解一个网络服务&#xff0c;执行的第一个功能肯定是写操作&#xff0c;然后才会执行读操作。比如&#xff0c;你要了解ZooKeeper&#xff0c;那么肯定会在zkClient.sh命令行中执行写操作(比如crea…