本帖最后由 dirty 于 2025-1-22 16:18 编辑
本篇讲述使用开发板做图像检测,包含边缘检测、线段检测、圆形检测、矩形检测,快速线性回归。
边缘检测
简单来说就是轮廓检测。CanMV集成了RGB565颜色块识别find_edges函数,位于 image 模块下,下面了解其相关API函数
...
功能:边缘检测,将图像变为黑白,边缘保留白色像素。
参数:
edge_type: 处理方式。
image.EDGE_SIMPLE : 简单的阈值高通滤波算法;
image.EDGE_SIMPLE : 简单的阈值高通滤波算法;
threshold:包含高、低阈值的二元组,默认是(100,200),仅支持灰度图像。
...
image.find_edges(edge_type[, threshold])
下面是对图像进行边缘检测代码
'''
边缘检测
'''
import time, os, sys, gc
from media.sensor import * #导入sensor模块,使用摄像头相关接口
from media.display import * #导入display模块,使用display相关接口
from media.media import * #导入media模块,使用meida相关接口
sensor = Sensor() #构建摄像头对象,将摄像头长宽设置为4:3
sensor.reset() #复位和初始化摄像头
sensor.set_framesize(width=320, height=240) #设置帧大小为LCD分辨率(320x240),默认通道0
#sensor.set_framesize(Sensor.FHD) #设置帧大小FHD(1920x1080),默认通道0
sensor.set_pixformat(Sensor.GRAYSCALE) #设置输出图像格式,默认通道0
#Display.init(Display.ST7701, to_ide=True) #同时使用3.5寸mipi屏和IDE缓冲区显示图像,800x480分辨率
Display.init(Display.VIRT, sensor.width(), sensor.height()) #只使用IDE缓冲区显示图像
print(sensor.width(), sensor.height())
MediaManager.init() #初始化media资源管理器
sensor.run() #启动sensor
clock = time.clock()
while True:
clock.tick()
img = sensor.snapshot() #拍摄一张图片
#使用 Canny 边缘检测器
img.find_edges(image.EDGE_CANNY, threshold=(50, 80))
# 也可以使用简单快速边缘检测,效果一般,配置如下
#img.find_edges(image.EDGE_SIMPLE, threshold=(100, 255))
#Display.show_image(img) #显示图片
#显示图片,仅用于LCD居中方式显示
Display.show_image(img, x=0,y=0)
print(clock.fps()) #打印FPS
运行,将手掌放于摄像头前方,可以检测到手掌轮廓,摄像头上方门框边缘部分也被检测到,效果图如下:
线段检测
K230对图像中的线段进行检测识别,并画图指示。CanMV集成了线段识别 find_line_segments 函数,位于 image 模块下,下面了解下其相关API
...
功能:线段识别函数
参数:
roi:识别区域(x,y,w,h),未指定则默认整张图片。
merge_distance:两条线段间可以相互分开而不被合并的最大像素;
max_theta_difference:将少于这个角度值的线段合并。
返回:返回一个 image.line 线段对象列表
...
image.find_line_segments([roi[, merge_distance=0[, max_theta_difference=15]]])
下面是线段检测代码:
'''
线段检测
说明:推荐使用320x240以下分辨率,分辨率过大会导致帧率下降。
'''
import time, os, sys
from media.sensor import * #导入sensor模块,使用摄像头相关接口
from media.display import * #导入display模块,使用display相关接口
from media.media import * #导入media模块,使用meida相关接口
enable_lens_corr = False # 设为True可以获得更直的线段
sensor = Sensor() #构建摄像头对象,将摄像头长宽设置为4:3
sensor.reset() #复位和初始化摄像头
sensor.set_framesize(width=320, height=240) #设置帧大小,默认通道0
sensor.set_pixformat(Sensor.RGB565) #设置输出图像格式,默认通道0
#Display.init(Display.ST7701, to_ide=True) #同时使用3.5寸mipi屏和IDE缓冲区显示图像,800x480分辨率
Display.init(Display.VIRT, sensor.width(), sensor.height()) #只使用IDE缓冲区显示图像
MediaManager.init() #初始化media资源管理器
sensor.run() #启动sensor
clock = time.clock()
while True:
clock.tick()
img = sensor.snapshot() #拍摄一张图片
if enable_lens_corr: img.lens_corr(1.8) # for 2.8mm lens...
# `merge_distance` 控制相近的线段是否合并. 数值 0 (默认值)表示不合并。数值
#为1时候表示相近1像素的线段被合并。因此你可以通过改变这个参数来控制检测到线
#段的数量。
# `max_theta_diff` 控制相差一定角度的线段合并,默认是15度,表示15度内的线
# 段都会合并
for l in img.find_line_segments(merge_distance = 0, max_theta_diff = 5):
img.draw_line(l.line(), color = (255, 0, 0), thickness=2)
print(l)
#Display.show_image(img) #显示图片
#显示图片,仅用于LCD居中方式显示
# Display.show_image(img, x=round((800-sensor.width())/2),y=round((480-sensor.height())/2))
Display.show_image(img, x=0,y=0)
print(clock.fps()) #打印FPS
这里在纸张上写上-XZ,运行检测结果如下,可以看到线段被标红:
圆形检测
K230对图像中的圆形进行检测识别,并画图指示。CanMV集成了圆形识别find_circles函数,位于image模块下,下面了解下其相关API.
...
功能:找圆函数
参数:
roi: 识别区域(x,y,w,h),未指定则默认整张图片。
threshold: 阈值。返回大于或等于threshold的圆,调整识别可信度。
x_stride y_stride : 霍夫变换时跳过x,y像素的量;
x_margin y_margin r_margin : 控制所检测圆的合并;
r_min r_max: 控制识别圆形的半径范围;
r_step:控制识别步骤。
返回:返回一个image.circle圆形对象,该圆形对象有4个值: x, y(圆心), r (半径)和magnitude(量级);量级越大说明识别到的圆可信度越高。
...
image.find_circles([roi[, x_stride=2[, y_stride=1[, threshold=2000[, x_margin=10[, y_margin=10
[, r_margin=10[, r_min=2[, r_max[, r_step=2]]]]]]]]]])
下面是圆形检测代码:
'''
实验名称:圆形检测
说明:推荐使用320x240以下分辨率,分辨率过大会导致帧率下降。
'''
import time, os, sys
from media.sensor import * #导入sensor模块,使用摄像头相关接口
from media.display import * #导入display模块,使用display相关接口
from media.media import * #导入media模块,使用meida相关接口
sensor = Sensor() #构建摄像头对象
sensor.reset() #复位和初始化摄像头
sensor.set_framesize(width=320, height=240) #设置帧大小,默认通道0
sensor.set_pixformat(Sensor.RGB565) #设置输出图像格式,默认通道0
#Display.init(Display.ST7701, to_ide=True) #同时使用3.5寸mipi屏和IDE缓冲区显示图像,800x480分辨率
Display.init(Display.VIRT, sensor.width(), sensor.height()) #只使用IDE缓冲区显示图像
MediaManager.init() #初始化media资源管理器
sensor.run() #启动sensor
clock = time.clock()
while True:
clock.tick()
img = sensor.snapshot() #拍摄一张图片
# 圆形类有 4 个参数值: 圆心(x, y), r (半径)和 magnitude(量级);
# 量级越大说明识别到的圆可信度越高。
# `threshold` 参数控制找到圆的数量,数值的提升会降低识别圆形的总数。
# `x_margin`, `y_margin`, and `r_margin`控制检测到接近圆的合并调节.
# r_min, r_max, and r_step 用于指定测试圆的半径范围。
for c in img.find_circles(threshold = 2000, x_margin = 10, y_margin= 10,
r_margin = 10,r_min = 2, r_max = 100, r_step = 2):
#画红色圆做指示
img.draw_circle(c.x(), c.y(), c.r(), color = (255, 0, 255),thickness=2)
print(c) #打印圆形的信息
#Display.show_image(img) #显示图片
#显示图片,仅用于LCD居中方式显示
Display.show_image(img, x=0,y=0)
print(clock.fps()) #打印FPS
这里用一个小圆盒,放于摄像头前方,调整下角度光线,可以看到物体两个圆形均被标记识别出,运行监测效果如下图所示:
矩形检测
K230对图像中的矩形进行检测识别,并画图指示。CanMV集成了矩形识别find_rects函数,位于image模块下,下面了解下其相关API
...
功能:矩形识别函数
参数:
roi: 识别区域(x,y,w,h),未指定则默认整张图片。
threshold: 阈值。返回大于或等于threshold的矩形,调整识别可信度。
返回:返回一个image.rect矩形对象列表。
...
image.find_rects([roi=Auto, threshold=10000])
矩形检测代码如下:
'''
矩形检测
说明:推荐使用320x240以下分辨率,分辨率过大会导致帧率下降。
'''
import time, os, sys
from media.sensor import * #导入sensor模块,使用摄像头相关接口
from media.display import * #导入display模块,使用display相关接口
from media.media import * #导入media模块,使用meida相关接口
sensor = Sensor() #构建摄像头对象
sensor.reset() #复位和初始化摄像头
sensor.set_framesize(width=320, height=240) #设置帧大小为LCD分辨率(800x480),默认通道0
sensor.set_pixformat(Sensor.RGB565) #设置输出图像格式,默认通道0
#Display.init(Display.ST7701, to_ide=True) #同时使用3.5寸mipi屏和IDE缓冲区显示图像,800x480分辨率
Display.init(Display.VIRT, sensor.width(), sensor.height()) #只使用IDE缓冲区显示图像
MediaManager.init() #初始化media资源管理器
sensor.run() #启动sensor
clock = time.clock()
while True:
clock.tick()
img = sensor.snapshot() #拍摄一张图片
# `threshold` 需要设置一个比价大的值来过滤掉噪声。
#这样在图像中检测到边缘亮度较低的矩形。矩形
#边缘量级越大,对比越强…
for r in img.find_rects(threshold = 10000):
img.draw_rectangle(r.rect(), color = (0, 0, 255),thickness=2) #画矩形显示
for p in r.corners(): img.draw_circle(p[0], p[1], 5, color = (0, 255, 0))#四角画小圆形
print(r)
#Display.show_image(img) #显示图片
#显示图片,仅用于LCD居中方式显示
Display.show_image(img, x=0,y=0)
print(clock.fps()) #打印FPS
这里在纸张上画上矩形,置于摄像头前方,运行可以看到矩形被识别标记,效果如下图所示:
快速线性回归(巡线)
快速线性回归的用途非常广泛,如比赛经常用到的小车、机器人巡线,可以通过线性回归的方式判断虚线和实线的轨迹。从而做出判断和响应。这里使用 K230对图像中的实线(或虚线)进行检测识别,并画图指示。CanMV集成了快速线性回归get_regression函数,位于image模块下,下面了解下其相关API
...
功能:线性回归计算.对图像所有阈值像素进行线性回归计算,通过最小二乘法进行,通常速度较快,但不能处理任何异常值;
参数:threshold: 必须是元组列表。 (lo, hi) 定义你想追踪的颜色范围。对于灰度图像,每个元组需要包含两个值:最小灰度值和最大灰度值。
返回:
...
image.get_regression(thresholds[, invert=False[, roi[, x_stride=2[, y_stride=1[,
area_threshold=10[, pixels_threshold=10[, robust=False]]]]]]])
为了提高处理效果,我们可以先将图像变成二值(黑白)图像,方法如下:
image.binary(thresholds[, invert=False[, zero=False[, mask=None[, to_bitmap=False[, copy=False]]]]])
巡线代码如下
'''
快速线性回归(巡线)
'''
import time, os, sys
from media.sensor import * #导入sensor模块,使用摄像头相关接口
from media.display import * #导入display模块,使用display相关接口
from media.media import * #导入media模块,使用meida相关接口
THRESHOLD = (0, 100) # 黑白图像的灰度阈值
BINARY_VISIBLE = True # 使用二值化图像你可以看到什么是线性回归。
# 这可能降低 FPS(每秒帧数).
sensor = Sensor() #构建摄像头对象
sensor.reset() #复位和初始化摄像头
sensor.set_framesize(width=320, height=240) #设置帧大小,默认通道0
sensor.set_pixformat(Sensor.GRAYSCALE) #设置输出图像格式,默认通道0
#Display.init(Display.ST7701, to_ide=True) #同时使用3.5寸mipi屏和IDE缓冲区显示图像,800x480分辨率
Display.init(Display.VIRT, sensor.width(), sensor.height()) #只使用IDE缓冲区显示图像
MediaManager.init() #初始化media资源管理器
sensor.run() #启动sensor
clock = time.clock()
while True:
clock.tick()
#image.binary([THRESHOLD])将灰度值在THRESHOLD范围变成了白色
img = sensor.snapshot().binary([THRESHOLD]) if BINARY_VISIBLE else sensor.snapshot()
# 返回一个类似 find_lines() 和find_line_segments()的对象.
# 有以下函数使用方法: x1(), y1(), x2(), y2(), length(),
# theta() (rotation in degrees), rho(), and magnitude().
#
# magnitude() 代表线性回归的指令,其值为(0, INF]。
# 0表示一个圆,INF数值越大,表示线性拟合的效果越好。
line = img.get_regression([(255,255) if BINARY_VISIBLE else THRESHOLD])
if (line):
img.draw_line(line.line(), color = 127,thickness=4)
print(line) #打印结果
#显示图片,仅用于LCD居中方式显示
Display.show_image(img, x=0,y=0)
print("FPS %f, mag = %s" % (clock.fps(), str(line.magnitude()) if (line) else "N/A"))
在纸张上画出轨迹,运行可以看到轨迹被白色线标记,效果如下图
至此,实现图像检测里的边缘检测、线段检测、圆形检测、矩形检测,快速线性回归(巡线)功能。
|