OpenMV 图像串口传输示例

2024-05-09 02:12

本文主要是介绍OpenMV 图像串口传输示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

注意:本程序根据 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, Trueelse:return img, False

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

  5. 主循环

output_image_path = 'received_image.jpg'while True:#key = int(input("请输入: "))key = 1if key == 0:breakwhile 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 Pinsensor.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,Trueelse:return img,False# 图像保存路径
output_image_path = 'received_image.jpg'while True:# 在需要延时的地方调用sleep()函数#time.sleep(0.01)  # 延时0.1秒# 循环接收并保存图像#key = int(input("请输入: "))key = 1if key == 0:breakwhile 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 汉字

这篇关于OpenMV 图像串口传输示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/972098

相关文章

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

Python函数作用域示例详解

《Python函数作用域示例详解》本文介绍了Python中的LEGB作用域规则,详细解析了变量查找的四个层级,通过具体代码示例,展示了各层级的变量访问规则和特性,对python函数作用域相关知识感兴趣... 目录一、LEGB 规则二、作用域实例2.1 局部作用域(Local)2.2 闭包作用域(Enclos

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

C++ 检测文件大小和文件传输的方法示例详解

《C++检测文件大小和文件传输的方法示例详解》文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解... 目录检测文件的大小✅ 方法一:使用 stat() 函数(推荐)✅ 用法示例:✅ 方法二:使用 fsee