75|0

509

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【嘉楠K230开发板】图像检测 [复制链接]

  本帖最后由 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"))

      在纸张上画出轨迹,运行可以看到轨迹被白色线标记,效果如下图

 

      至此,实现图像检测里的边缘检测、线段检测、圆形检测、矩形检测,快速线性回归(巡线)功能。

 

点赞 关注
个人签名

保持热爱

 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表