回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【花雕动手做】CanMV K230 AI 视觉识别模块之物体边缘检测 简单

头像 驴友花雕 2025.11.07 1 0

00 (2).jpg

什么是 CanMV K230?
CanMV K230是一款高性价比的RISC-V边缘AI平台,凭借低功耗、强视觉处理能力和开放的开发生态,成为嵌入式AI开发的理想选择,尤其适合需要快速部署视觉与AI功能的创客、中小企业及教育场景。CanMV 是一套 AI 视觉开发平台,K230 是其核心芯片。该模块结合了图像采集、AI推理、边缘计算等能力,适合嵌入式视觉应用开发。

CanMV:类似 OpenMV 的图像处理框架,支持 Python 编程,简化视觉识别开发流程。
K230 芯片:嘉楠科技推出的 AIoT SoC,采用 RISC-V 架构,内置第三代 KPU(AI加速单元),算力高达 6 TOPS,性能是 K210 的 13.7 倍。

 

00 (3).jpg

知识点
物体边缘检测是计算机视觉的基础核心任务,核心是识别图像中像素灰度值、颜色或纹理发生剧烈变化的区域,这些区域对应物体的轮廓边界(如物体与背景的分界、物体表面的纹理边缘),是后续线段 / 矩形 / 圆形检测、目标识别等任务的前提。
1、核心原理
边缘的本质是图像局部特征的突变,检测核心是通过算法放大这种突变并标记,主流逻辑分两类:
梯度检测:计算像素点在水平、垂直或对角线方向的灰度变化率(梯度),梯度值超过阈值则判定为边缘(如 Sobel、Prewitt 算子)。
边缘增强与阈值筛选:先通过滤波增强边缘信号、抑制噪声,再用阈值分割提取边缘(如 Canny 算子的 “双阈值” 筛选)。

2、主流算法(按效果和效率分类)

 

20-.jpg


3、实操示例(OpenCV 实现主流算法)
以下代码适配 K230 摄像头采集的实时帧,可直接移植使用,对比不同算法效果:

 

 

代码
import cv2
import numpy as np

# 初始化摄像头(K230的/dev/video0设备)
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

if not cap.isOpened():
   print("摄像头打开失败")
   exit()

while True:
   ret, frame = cap.read()
   if not ret:
       break
   gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

   # 1. Canny边缘检测(推荐首选)
   canny = cv2.Canny(gray, 50, 150)  # 双阈值:低阈值50,高阈值150

   # 2. Sobel边缘检测(水平+垂直合并)
   sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)  # 水平边缘
   sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)  # 垂直边缘
   sobel = cv2.convertScaleAbs(np.sqrt(sobel_x**2 + sobel_y**2))  # 合并边缘

   # 3. Laplacian边缘检测(需先降噪)
   blur = cv2.GaussianBlur(gray, (5, 5), 0)
   laplacian = cv2.Laplacian(blur, cv2.CV_64F, ksize=3)
   laplacian = cv2.convertScaleAbs(laplacian)

   # 拼接显示所有结果
   result = np.hstack((canny, sobel, laplacian))
   cv2.putText(result, "Canny | Sobel | Laplacian", (10, 30), 
               cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2)
   cv2.imshow("Edge Detection Comparison", result)

   if cv2.waitKey(1) == ord('q'):
       break

cap.release()
cv2.destroyAllWindows()

4、关键优化技巧(提升边缘质量)
预处理降噪:
所有算法前优先用高斯模糊(cv2.GaussianBlur),核大小设为 (3,3)~(7,7),平衡降噪和边缘保留。
对高噪声图像(如工业场景),用中值滤波(cv2.medianBlur)替代高斯模糊,抑制椒盐噪声。
参数调优:
Canny 算子:低阈值设为高阈值的 1/2~1/3(如高阈值 100→低阈值 50),高阈值根据图像亮度调整(暗图→50~80,亮图→100~200)。
Sobel/Laplacian:ksize(卷积核大小)选 3 或 5,值越大边缘越粗但抗噪声越强。
边缘后处理:
用形态学操作(如膨胀cv2.dilate)连接断裂的边缘,或腐蚀cv2.erode细化粗边缘。
对边缘图进行二值化(cv2.threshold),进一步过滤弱边缘噪声。
K230 平台适配:
用 NPU 加速高斯模糊和 Canny 算子(通过 Tengine-Lite 调用硬件加速接口),将单帧处理延迟从 CPU 的 30ms 降至 10ms 内。
针对 MIPI 摄像头采集的图像,先通过 ISP 工具调整曝光和白平衡,减少因光照不均导致的边缘模糊。

5、典型应用场景
工业检测:物体轮廓提取(如零件边缘是否完整)、缺陷检测(如金属表面划痕边缘识别)。
目标识别:作为预处理步骤,辅助提取物体特征(如人脸边缘、车辆轮廓)。
图像分割:为语义分割提供边缘线索(如区分前景物体和背景)。
机器人视觉:提取环境边缘(如墙壁、障碍物边界),辅助 SLAM 建图和避障。

 

21.jpg
22.jpg
23.jpg
24.jpg

【花雕动手做】CanMV K230 AI 视觉识别模块之物体边缘检测
项目测试实验代码

 

 

代码
#【花雕动手做】CanMV K230 AI 视觉识别模块之物体边缘检测

import time, os, sys, gc
from media.sensor import *
from media.display import *
from media.media import *

# 设置图像捕获分辨率 / Set image capture resolution
SENSOR_WIDTH = 1280    # 传感器最大支持宽度
SENSOR_HEIGHT = 960    # 传感器最大支持高度
FRAME_WIDTH = 640      # 实际处理帧宽度(平衡性能与质量)
FRAME_HEIGHT = 480     # 实际处理帧高度(平衡性能与质量)

# 显示屏分辨率 / Display resolution
DISPLAY_WIDTH = 640    # 显示宽度
DISPLAY_HEIGHT = 480   # 显示高度

def init_sensor():
    """初始化传感器 / Initialize sensor"""
    # sensor = Sensor(width=SENSOR_WIDTH, height=SENSOR_HEIGHT)  # 4:3分辨率 / 4:3 resolution
    sensor = Sensor()  # 创建传感器实例(使用默认配置)
    sensor.reset()     # 重置传感器到初始状态
    
    # 设置帧大小 / Set frame size
    # 使用640x480分辨率进行处理,相比1280x960减少75%计算量
    sensor.set_framesize(width=FRAME_WIDTH, height=FRAME_HEIGHT)
    
    # 设置像素格式为灰度图像 / Set pixel format to grayscale
    # 灰度图像单通道8位,相比RGB565减少50%内存占用,提高边缘检测速度
    sensor.set_pixformat(Sensor.GRAYSCALE)
    return sensor

def init_display():
    """初始化显示器 / Initialize display"""
    # 初始化ST7701物理屏幕,同时输出到IDE便于调试
    Display.init(Display.ST7701, to_ide=True)
    
    # 虚拟显示配置(已注释) / Virtual display config (commented)
    # 备用方案:使用虚拟显示,适合无物理屏幕环境
    # Display.init(Display.VIRT, sensor.width(), sensor.height())

def process_image(img):
    """
    处理图像 - 边缘检测核心算法 / Process image - core edge detection algorithm
    参数: img - 输入的灰度图像对象
    """
    # Canny边缘检测算法 / Canny edge detection algorithm
    # 参数说明:
    # image.EDGE_CANNY - 使用Canny边缘检测器
    # threshold=(50, 80) - 双阈值:低阈值50,高阈值80
    #   低于50:认为是非边缘
    #   高于80:认为是强边缘
    #   50-80之间:如果连接到强边缘则认为是边缘
    img.find_edges(image.EDGE_CANNY, threshold=(50, 80))

    # 简单边缘检测配置(已注释) / Simple edge detection config (commented)
    # 替代方案:使用简单的Sobel算子进行边缘检测
    # 参数说明:
    # image.EDGE_SIMPLE - 使用简单边缘检测
    # threshold=(100, 255) - 边缘强度阈值范围
    # img.find_edges(image.EDGE_SIMPLE, threshold=(100, 255))

def main():
    try:
        # 初始化设备 / Initialize devices
        sensor = init_sensor()     # 初始化摄像头传感器
        init_display()             # 初始化显示设备
        MediaManager.init()        # 初始化媒体管理器(分配媒体处理资源)
        sensor.run()               # 启动摄像头数据采集

        # 初始化时钟 / Initialize clock(用于性能监控)
        clock = time.clock()

        # 计算显示偏移量以居中显示 / Calculate display offsets for center alignment
        # 由于处理分辨率和显示分辨率相同(640x480),偏移量为0
        x_offset = round((DISPLAY_WIDTH - FRAME_WIDTH) / 2)  # (640-640)/2 = 0
        y_offset = round((DISPLAY_HEIGHT - FRAME_HEIGHT) / 2) # (480-480)/2 = 0

        # 主循环 - 实时边缘检测
        while True:
            clock.tick()  # 更新时钟,记录当前时间点(用于FPS计算)

            # 捕获和处理图像 / Capture and process image
            img = sensor.snapshot()  # 从摄像头捕获一帧图像
            process_image(img)       # 对图像进行边缘检测处理

            # 居中显示图像 / Display image in center
            # 由于分辨率相同,实际上就是全屏显示
            Display.show_image(img, x=x_offset, y=y_offset)

            # 显示FPS / Display FPS(性能监控)
            # 打印当前帧率,用于评估系统性能和算法效率
            print(clock.fps())

    except KeyboardInterrupt as e:
        # 处理用户中断(Ctrl+C)
        print("用户中断 / User interrupted: ", e)
    except Exception as e:
        # 处理其他所有异常
        print(f"发生错误 / Error occurred: {e}")
    finally:
        # 清理资源 / Cleanup resources(无论是否异常都会执行)
        if 'sensor' in locals() and isinstance(sensor, Sensor):
            sensor.stop()        # 停止摄像头采集
        Display.deinit()         # 关闭显示驱动
        MediaManager.deinit()    # 释放媒体资源
        gc.collect()             # 强制垃圾回收,释放内存碎片

if __name__ == "__main__":
    main()  # 程序入口点

代码结构
配置部分:
• 定义了两组分辨率:传感器捕获分辨率(1920x1080)和实际处理的帧分辨率(640x480),如果需要提升帧率,可以将实际处理的分辨率降低。
• 显示屏分辨率设置为640x480

初始化函数:
• init_sensor(): 配置摄像头传感器,设置分辨率和灰度图像格式
• init_display(): 初始化显示屏

图像处理:
• process_image(): 使用Canny算法进行边缘检测,阈值设置为50-80

主程序流程:
• 初始化所有设备(传感器、显示屏)
• 计算显示偏移量,使图像在屏幕上居中显示
• 进入主循环:
◦ 捕获图像
◦ 进行边缘检测处理
◦ 在屏幕上显示处理后的图像
◦ 显示当前FPS(每秒帧数)

错误处理:
• 包含了完整的异常处理机制
• 程序结束时会进行资源清理(停止传感器、清理显示、垃圾回收)

边缘检测函数
find_edge()
image.find_edges(edge_type[, threshold])
该函数将图像转换为黑白图像,仅保留边缘为白色像素。
• edge_type 可选值包括:
◦ image.EDGE_SIMPLE - 简单的阈值高通滤波算法
◦ image.EDGE_CANNY - Canny 边缘检测算法
• threshold 是包含低阈值和高阈值的二元元组。您可以通过调整该值来控制边缘质量,默认设置为 (100, 200)。
注意: 此方法仅支持灰度图像。

 

实验串口返回情况

 

27.jpg

实验场景图

 

26.jpg
28 (1).jpg
28 (2).jpg
28 (3).jpg
28 (4).jpg
28 (5).jpg
28 (6).jpg

评论

user-avatar
icon 他的勋章
    展开更多