# esp32cam-openmv **Repository Path**: danmu_admin/esp32cam-openmv ## Basic Information - **Project Name**: esp32cam-openmv - **Description**: esp32cam下的OPENMV快速教程 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 41 - **Forks**: 8 - **Created**: 2022-04-11 - **Last Updated**: 2025-04-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ESP32CAM的使用 目前该固件下的OPENMV相关的功能只有以下功能 1. 寻找色块 (可以完成巡线小车功能,但是请务必配合LCD屏幕调试,切记切记!) 2. 寻找矩形、圆形 3. 寻找人脸、人眼 4. 二维码识别 注意: 1. LCD屏幕和esp32原有的SD卡冲突,请外界SPI的SD卡通过接CS共同使用; 2. 无法使用openmv的IDE,需要使用摄像头功能的务必使用LCD屏幕进行调试; 3. st7789的屏幕请务必购买320x240分辨率;实在没有也可以向往一样买240x280(反正初始化也是320x240,只是舍弃了一部分显示);若使用其他分辨率 可以使用resize方法将图像变成相对应的分辨率`ee=camera.capture().resize(128,96)#修改大小 128X96的分辨率` ## 基础入门 ``` import camera camera.init(0,format=2) camera.init(0,format=camera.GRAYSCALE) #默认灰度图 camera.init(0,format=3) camera.init(0,format=camera.JPEG) #JPG格式 # 相关格式 # JPEG -- 3 # YUV422 -- 1 # GRAYSCALE -- 2 # RGB565 -- 0 camera.framesize(5) #320X240 设置分辨率 img=camera.capture() import uos from machine import SDCard #FAT 格式的存储卡 uos.mount(SDCard(),'/sd') uos.listdir() uos.chdir('/sd') uos.listdir() fg=open("a.jpg","w") fg.write(img) fg.close() #thonny 使用直接右击下载文件,直接查看,本地空间,OPENMV下的esp32cam有1MB的可用空间,单纯micropython下有2MB的空间 #闪关灯 #GPIO4 为LED补光灯,若长时间使用会有严重的发热问题 from machine import Pin flash=Pin(4,Pin.OUT) flash.on() #打开闪关灯 flash.off() #关闭闪关灯 ``` ## openmv初体验 img参数直接打印为: 分辨率 文件类型 文件大小 在非jpg下 建设使用320x240 的分辨率(默认分辨率) 可用分辨率: **需要250ms (推荐分辨率 可以4FPS)** * camera.framesize(5) 5 :::: {"w":320, "h":240, "type"="grayscale", "size":76800} ::: 267 ms * camera.framesize(6) 6 :::: {"w":400, "h":296, "type"="grayscale", "size":118400} ::: 249 ms **需要750ms** * camera.framesize(7) 7 :::: {"w":480, "h":320, "type"="grayscale", "size":153600} ::: 770 ms * camera.framesize(8) 8 :::: {"w":640, "h":480, "type"="grayscale", "size":307200} ::: 722 ms * camera.framesize(9) 9 :::: {"w":800, "h":600, "type"="grayscale", "size":480000} ::: 686 ms **需要2000ms(不建议使用)** * camera.framesize(10) 10 :::: {"w":1024, "h":768, "type"="grayscale", "size":786432} ::: 2019 ms * camera.framesize(11) 11 :::: {"w":1280, "h":720, "type"="grayscale", "size":921600} ::: 1819 ms * camera.framesize(12) 12 :::: {"w":1280, "h":1024, "type"="grayscale", "size":1310720} ::: 2126 ms * camera.framesize(13) 13 :::: {"w":1600, "h":1200, "type"="grayscale", "size":1920000} ::: 1968 ms JPG模式下全分辨率可用,但是使用OPENMV建议处理分辨率为320x240 或 400x296 ### ESP32CAM 处理步骤 1. 设定相机参数 2. 拍照 3. 使用OPENMV处理 使用img(*拍摄完的对象*)进行处理 使用help(img)查看其方法 和openmv的stm32设备下,除了拍照方面不同,其他方面都差不多,文档地址: [book.openmv.cc](https://book.openmv.cc/) 大家做相应的替换 ### 二维码识别: img.find_qrcodes() 若识别到二维码,就会返回扫描的相关数据。 但是二维码需要使用灰度图片 ``` import time,camera camera.init(0,format=2) camera.init(0,format=camera.GRAYSCALE) while True: img=camera.capture() e=img.find_qrcodes() if e: print(e) time.sleep(0.5) ``` ### 画图 每个函数都需要用到的参数 color=[r,g,b],简单点用白色 [255,255,255] #### 画线 ee.draw_line((10,10,20,30),color=[255,255,255]) #线段元组 x1 y1 x2 y2 #### 画矩形 ee.draw_rectangle((24,47,20,30),color=[155,55,55])#矩形元组x y w h #### 画圆 ee.draw_circle(50,40,30,color=[255,255,255]) #x y r半斤 #### 画十字线 ee.draw_cross(80,50,size=15,color=[255,255,255]) #x y size=十字线段长度 #### 文字 ee.draw_string(70,10,"openmv esp32",color=[255,255,255]) #x y 文字信息 #### 显示模块 因为没有USB,所以不能使用OPENMV IDE,但是我们可以曲线救国(勉强能用),建议使用ST7789 的LCD屏幕 320x240的分辨率,20元左右(SSD1351 的OLED屏幕),直接接收RGB565的数据,建议使用分辨率320x240(128x128,目前draw.py里面的分辨率是128x96(因为手头上只有这个屏幕))。需要注意的是,ESP32CAM在非JPG下仅能4FPS的速度,外接屏幕只有2.5-3FPS(需要压缩图片到合适的分辨率),勉勉强强吧;俗话说:1帧能玩,2帧流畅,3帧电竞。这个还是挺能打的。 强烈建议使用ST7789的LCD屏幕 使用原生320x240分辨率 **使用时请先上传 st7789py.py 到你的ESP32cam** |ST7789 |ESP32CAM| |-|-| |SCK|12| |SDA|13| |REST|15| |DC|14| |BLK|2| |VCC|3v3| |GND|GND| ``` import st7789py as st7789 from machine import SPI,Pin,UART import machine import time import gc import camera #LCD 初始化 spi = SPI(2, baudrate=20000000, polarity=1, sck=Pin(12), mosi=Pin(13)) tft = st7789.ST7789(spi, 320, 240, reset=Pin(15, Pin.OUT), dc=Pin(14, Pin.OUT),backlight=Pin(2,Pin.OUT)) tft.rotation(1) tft.fill(st7789.BLUE) camera.init(0,format=0) while True: s=time.ticks_ms() ea=camera.capture() fps=1000/(time.ticks_ms()-s) ea.draw_string(200,200,str(fps)[0:3]+"fps",color=[255,2,25]) tft.blit_buffer(ea.to_bytes(), 0, 0, 320, 240) ``` #### ssd1351显示 导入ssd1351.py使用。 接线 |SSD1351 |ESP32CAM| |-|-| |DIN|14| |CLK|2| |DC|15| |CS|13| |RES|12| ``` from machine import Pin,SPI from ssd1351 import Display import camera spi = SPI(2, baudrate=14500000, sck=Pin(2), mosi=Pin(14)) display = Display(spi, dc=Pin(15), cs=Pin(13), rst=Pin(12),width=128,height=128) camera.init(0,format=0) ee=camera.capture().resize(128,96)#修改大小 128X128的屏幕没买,手头上只有128x96屏幕 ee.draw_line((10,10,20,30),color=[255,255,255]) #线段元组 x1 y1 x2 y2 ee.draw_rectangle((24,47,20,30),color=[155,55,55])#矩形元组x y w h ee.draw_circle(50,40,30,color=[255,255,255]) #x y r ee.draw_cross(80,50,size=15,color=[255,255,255]) #x y 十字线段长度 ee.draw_string(70,10,"openmv esp32",color=[255,255,255]) display.draw_image_ram(ee.to_bytes(), 0, 30, 128, 96) ``` ### 寻找色块 #### 基本认识 Lab颜色空间中,L亮度;a的正数代表红色,负端代表绿色;b的正数代表黄色,负端代表蓝色。openmv是基于LAB来寻找色块的。 因为没有USB口所以不能像其他openmv设备一样使用openmv IDE进行快速调价。仅能使用预估识别几个大体颜色。 #### find_blobs 函数 * 第一个重要参数就是thresholds(颜色的阈值),为列表,列表中含有颜色范围的元组colors= (minL, maxL, minA, maxA, minB, maxB) * 第二个参数roi感兴趣区域(x,y,w,h) 位置,长宽 * x_stride 就是查找的色块的x方向上最小宽度的像素,默认为2,如果你只想查找宽度10个像素以上的色块,那么就设置这个参数为10: * y_stride 就是查找的色块的y方向上最小宽度的像素,默认为1,如果你只想查找宽度5个像素以上的色块,那么就设置这个参数为5: * 反转阈值,把阈值以外的颜色作为阈值进行查找 * area_threshold 面积阈值,如果色块被框起来的面积小于这个值,会被过滤掉 * pixels_threshold 像素个数阈值,如果色块像素数量小于这个值,会被过滤掉 merge 合并,如果设置为True,那么合并所有重叠的blob为一个。 注意:这会合并所有的blob,无论是什么颜色的。如果你想混淆多种颜色的blob,只需要分别调用不同颜色阈值的find_blobs。 ##### blobs 返回值 返回一个blobs的列表,其中有匹配的对象 ``` for blob in blobs: pass ``` * blob.rect() 返回这个色块的外框——矩形元组(x, y, w, h),可以直接在image.draw_rectangle中使用。 * blob.x() 返回色块的外框的x坐标(int),也可以通过blob[0]来获取。 * blob.y() 返回色块的外框的y坐标(int),也可以通过blob[1]来获取。 * blob.w() 返回色块的外框的宽度w(int),也可以通过blob[2]来获取。 * blob.h() 返回色块的外框的高度h(int),也可以通过blob[3]来获取。 * blob.pixels() 返回色块的像素数量(int),也可以通过blob[4]来获取。 * blob.cx() 返回色块的外框的中心x坐标(int),也可以通过blob[5]来获取。 * blob.cy() 返回色块的外框的中心y坐标(int),也可以通过blob[6]来获取。 * blob.rotation() 返回色块的旋转角度(单位为弧度)(float)。如果色块类似一个铅笔,那么这个值为0~180°。如果色块是一个圆,那么这个值是无用的。如果色块完全没有对称性,那么你会得到0~360°,也可以通过blob[7]来获取。 * blob.code() 返回一个16bit数字,每一个bit会对应每一个阈值。举个例子: * blobs = img.find_blobs([red, blue, yellow], merge=True) 如果这个色块是红色,那么它的code就是0001,如果是蓝色,那么它的code就是0010。注意:一个blob可能是合并的,如果是红色和蓝色的blob,那么这个blob就是0011。这个功能可以用于查找颜色代码。也可以通过blob[8]来获取。 * blob.count() 如果merge=True,那么就会有多个blob被合并到一个blob,这个函数返回的就是这个的数量。如果merge=False,那么返回值总是1。也可以通过blob[9]来获取。 * blob.area() 返回色块的外框的面积。应该等于(w * h) * blob.density() 返回色块的密度。这等于色块的像素数除以外框的区域。如果密度较低,那么说明目标锁定的不是很好。 比如,识别一个红色的圆,返回的blob.pixels()是目标圆的像素点数,blob.area()是圆的外接正方形的面积。 #### 寻找黑色(巡线小车) 其中黑色是最简答的颜色,也是各自竞赛用的最多的。 。。。。。。。。。。。。。。。。。。。 ### 寻找人脸 已更新face.py 性能过低,320x240分辨率识别人脸性能再0.1FPS,使用resize方法到128x96,基本可以达到3FPS左右 ### 寻找图形 find_rects() find_circle() 使用寻找图形,请勿使用resize(), 坑:用resize()之后再find_rects()会导致重启,另一个无此bug