【嘉楠科技 CanMV K230测评】机器视觉进阶-Find something(边缘、直线、圆形、矩形)
[复制链接]
前面介绍了基于K230相关外设以及机器视觉相关的基础,像是摄像头的使用以及图像的显示和画图相关的内容。下面会逐渐开始机器视觉真正的内容,循序渐进的进行,首先是常见的边缘检测、直线检测等等,后面跟着例程学习颜色相关、码类识别以及后续的AI相关的内容。
边缘检测
边缘检测使用image.find_edges(edge_type[, threshold])函数,可以选择的边缘检测算法有两种,Simple和Canny两种。其中Canny检测算法更好一些。而后面的高低阈值参数设置,与Canny检测算法中的双阈值确定边界有关。阈值设置较高,则只能检测出较为明显的边缘,阈值设置较低,则可以检测出大部分的边缘。
代码演示如下,其基本内容为图像的采集和显示,主要就是在snapshot和show_image之间插入了find_edges函数。除此之外重要的是,边缘检测是需要图像转换为黑白图像,因此在输出图像格式的位置,应该选择的参数为GRAYSCALE。
- import time, os, sys, gc
-
- from media.sensor import *
- from media.display import *
- from media.media import *
-
- try:
-
- sensor = Sensor(width=1280, height=960)
- sensor.reset()
- sensor.set_framesize(width=320, height=240)
- sensor.set_pixformat(Sensor.GRAYSCALE)
-
- Display.init(Display.VIRT, sensor.width(), sensor.height())
-
- MediaManager.init()
-
- sensor.run()
-
- clock = time.clock()
-
- while True:
-
- os.exitpoint()
-
-
-
-
- clock.tick()
-
- img = sensor.snapshot()
-
-
- img.find_edges(image.EDGE_CANNY, threshold=(10, 20))
-
- Display.show_image(img)
-
-
-
-
-
- print(clock.fps())
-
-
-
-
- except KeyboardInterrupt as e:
- print("user stop: ", e)
- except BaseException as e:
- print(f"Exception {e}")
- finally:
-
- if isinstance(sensor, Sensor):
- sensor.stop()
-
- Display.deinit()
- os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
- time.sleep_ms(100)
-
- MediaManager.deinit()
-
下面使用同一张素材,对参数中的高低阈值进行更改,观察不同的效果。
素材原图及素材灰度图:
高阈值200、低阈值100:
高阈值20、低阈值10:
高阈值200、低阈值10:
可以明显的看出,阈值设置为10和20的时候,检测出的边缘数量远大于阈值设置为100和200的时候。可以更加清楚的看到人脸的轮廓。但是对应也产生了更多“噪声”,因此选择一个合适的阈值是十分重要的。
线段检测
线段检测使用的函数为image.find_line_segments([roi[, merge_distance=0[, max_theta_difference=15]]]),其返回值为一个线段对象列表image.line。其中参数roi为识别的区域范围,若无指定则默认是整张图片;merge_distance为两条线段不被合并的最大像素值;max_theta_difference两条线段不被合并的最大角度值。
代码展示如下。
- import time, os, sys
-
- from media.sensor import *
- from media.display import *
- from media.media import *
-
- enable_lens_corr = False
-
- try:
-
- sensor = Sensor(width=1280, height=960)
- sensor.reset()
- sensor.set_framesize(width=320, height=240)
- sensor.set_pixformat(Sensor.RGB565)
-
-
- Display.init(Display.VIRT,320,240)
-
- MediaManager.init()
-
- sensor.run()
-
- clock = time.clock()
-
- while True:
-
- os.exitpoint()
-
-
-
-
- clock.tick()
-
- img = sensor.snapshot()
-
- if enable_lens_corr: img.lens_corr(1.8)
-
-
-
-
-
-
-
-
- for l in img.find_line_segments(merge_distance = 5, max_theta_diff = 15):
-
- img.draw_line(l.line(), color = (255, 0, 0), thickness=2)
- print(l)
-
-
-
-
- Display.show_image(img, x=0,y=0)
-
- print(clock.fps())
-
-
-
-
- except KeyboardInterrupt as e:
- print("user stop: ", e)
- except BaseException as e:
- print(f"Exception {e}")
- finally:
-
- if isinstance(sensor, Sensor):
- sensor.stop()
-
- Display.deinit()
- os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
- time.sleep_ms(100)
-
- MediaManager.deinit()
-
在这个代码中,在拍摄图片和显示图片之间加入了find_line_segments函数。并将返回的数据存储在了l中。然后再将l列表中的信息,画成线表示在图片上,并将l列表的信息打印在串行终端。
下面进行效果的演示。
原图:
检测后效果:
可以看到公路上的线段就可以被识别出来,且在左下角的串行终端中进行了线段数据的打印。
圆形检测
圆形检测使用的函数为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]]]]]]]]]]),其返回值为一个圆形对象,有四个参数值,分别为圆心的X和Y,半径以及量级(量级数值越大圆的可信度越高)。其中参数roi为识别的区域范围,若无指定则默认是整张图片;threshold为阈值,返回大于或等于量级大于这个数值的圆;x_stride和y_stride为检测过程中跳过的像素量;x_margin 、y_margin、 r_margin为所检测圆的合并;r_min和r_max用于控制识别圆形的半径范围;r_step用于控制识别的步骤。
代码演示。
- import time, os, sys
-
- from media.sensor import *
- from media.display import *
- from media.media import *
-
- try:
-
- sensor = Sensor(width=1280, height=960)
- sensor.reset()
- sensor.set_framesize(width=320, height=240)
- sensor.set_pixformat(Sensor.RGB565)
-
- Display.init(Display.VIRT, 320, 240)
-
- MediaManager.init()
-
- sensor.run()
-
- clock = time.clock()
-
- while True:
-
- os.exitpoint()
-
-
-
-
- clock.tick()
-
- img = sensor.snapshot()
-
-
-
-
-
- for c in img.find_circles(threshold = 1300, x_margin = 10, y_margin= 10,
- r_margin = 10,r_min = 5, r_max = 50, r_step = 2):
-
- img.draw_circle(c.x(), c.y(), c.r(), color = (255, 0, 0),thickness=2)
-
- print(c)
-
-
-
-
- Display.show_image(img, x=0,y=0)
-
- print(clock.fps())
-
-
-
-
- except KeyboardInterrupt as e:
- print("user stop: ", e)
- except BaseException as e:
- print(f"Exception {e}")
- finally:
-
- if isinstance(sensor, Sensor):
- sensor.stop()
-
- Display.deinit()
- os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
- time.sleep_ms(100)
-
- MediaManager.deinit()
-
效果演示。
原图:
检测后结果展示:
矩形检测
K230中进行矩形检测的算法采用的是二维码检测中的image.find_rects([roi=Auto, threshold=10000]),其中的参数roi表示的是检测的区域,不配置的话就是默认整张图片。threshold参数用来配置阈值,只有超过这个阈值的矩形,才会被识别并显示出来。使用这个函数同样也会返回一个列表,列表的信息有矩形的起点横纵坐标以及矩形的长度和宽度以及矩形的量级(即前面参数配置中对应的threshold)。
代码:
- import time, os, sys
-
- from media.sensor import *
- from media.display import *
- from media.media import *
-
- try:
-
- sensor = Sensor(width=1280, height=960)
- sensor.reset()
- sensor.set_framesize(width=320, height=240)
- sensor.set_pixformat(Sensor.RGB565)
-
- Display.init(Display.ST7701, to_ide=True)
-
-
- MediaManager.init()
-
- sensor.run()
-
- clock = time.clock()
-
- while True:
-
- os.exitpoint()
-
-
-
-
- clock.tick()
-
- img = sensor.snapshot()
-
-
-
-
-
- for r in img.find_rects(threshold = 40000):
- img.draw_rectangle(r.rect(), color = (255, 0, 0),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, x=round((800-sensor.width())/2),y=round((480-sensor.height())/2))
-
- print(clock.fps())
-
-
-
-
- except KeyboardInterrupt as e:
- print("user stop: ", e)
- except BaseException as e:
- print(f"Exception {e}")
- finally:
-
- if isinstance(sensor, Sensor):
- sensor.stop()
-
- Display.deinit()
- os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
- time.sleep_ms(100)
-
- MediaManager.deinit()
效果演示:
原图:
效果图:
|