10浏览
查看: 10|回复: 3

[项目] 【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框

[复制链接]
【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框图1

什么是 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 倍。


【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框图2

驴友花雕  中级技神
 楼主|

发表于 昨天 17:37

【花雕动手做】CanMV K230 AI视觉模块之绘制关键点图框

绘制关键点的draw_keypoints方法

1、什么是关键点?
这里的关键点(keypoints)是指图像中的特征点,通常是图像中比较显著或者独特的点,具体来说:

2、特征点的特性:
这些点通常是图像中的角点、边缘交叉点等具有显著特征的位置
它们在图像的不同视角下都容易被识别
这些点的周围像素值变化较大,使其具有独特性
实际应用中的关键点可能是:

3、物体的角点
纹理丰富区域的特征点
图案中的显著交叉点
物体轮廓上的重要点

4、用途:
目标跟踪
物体识别
图像匹配
运动检测
由于寻找关键点对性能消耗较大,所以我们减少了识别的区域,只识别屏幕最中心的部分的关键点

5、寻找关键点
  1. image.find_keypoints([roi[, threshold=20[, normalized=False[, scale_factor=1.5[, max_keypoints=100[, corner_detector=image.CORNER_AGAST]]]]]])
复制代码

该函数从指定的 ROI 元组 (x, y, w, h) 中提取 ORB 关键点。您可以使用 image.match_descriptor 函数比较两组关键点以获取匹配区域。若未发现关键点,则返回 None。

roi 是感兴趣区域的矩形元组 (x, y, w, h)。若未指定,默认 ROI 为整个图像。操作范围仅限于该区域内的像素。
threshold 控制提取关键点的数量(取值范围为 0-255)。对于默认的 AGAST 角点检测器,该值应设为约 20;对于 FAST 角点检测器,该值应设为约 60 至 80。阈值越低,提取的角点越多。
normalized 是布尔值。若为 True,则在多分辨率下关闭关键点提取。若您不关心处理扩展问题,且希望算法运行更快,则将其设置为 True。
scale_factor 是一个大于 1.0 的浮点数。较高的比例因子运行速度较快,但图像匹配效果相对较差。理想值介于 1.35 和 1.5 之间。
max_keypoints 是关键点对象能够容纳的最大关键点数量。若关键点对象过大导致内存问题,请适当降低该值。
corner_detector 是提取关键点所使用的角点检测器算法。可选值为 image.CORNER_FAST 或 image.CORNER_AGAST。FAST 角点检测器速度较快,但准确度较低。
注意: 此方法仅支持灰度图像。

6、绘制关键点
  1. image.draw_keypoints(keypoints[, color[, size=10[, thickness=1[, fill=False]]]])
复制代码

在图像上绘制特征点。

color:指定颜色,适用于灰度或 RGB565 图像。默认为白色。对于灰度图像,可以传递灰度值(0-255);对于 RGB565 图像,可以传递反向字节序的 RGB565 值。
size:控制特征点的大小。
thickness:控制线条的粗细(以像素为单位)。
fill:如果为 True,则填充特征点。
返回图像对象,以便后续方法可以链式调用。

该方法不支持压缩图像和 Bayer 格式图像

7、项目测试实验代码

  1. #【花雕动手做】CanMV K230 AI视觉识别模块之使用draw_keypoints()方法绘制关键点
  2. """
  3. Camera preview demo
  4. 摄像头预览演示
  5. This script initializes camera sensor, displays preview and handles cleanup
  6. 本脚本初始化摄像头传感器、显示预览并处理清理工作
  7. """
  8. import sys
  9. import uos as os
  10. import time
  11. from media.sensor import *
  12. from media.display import *
  13. from media.media import *
  14. def init_sensor():
  15.     """
  16.     Initialize camera sensor with specified configuration
  17.     使用指定配置初始化摄像头传感器
  18.    
  19.     返回:
  20.         Sensor: 初始化好的传感器对象
  21.     """
  22.     # Create sensor instance with resolution 1280x960
  23.     # 创建分辨率为1280x960的传感器实例
  24.     sensor = Sensor()
  25.     # Reset sensor to default state
  26.     # 将传感器重置为默认状态(恢复默认参数)
  27.     sensor.reset()
  28.     # Configure channel 1 output format to 640x480 RGB565
  29.     # 配置通道1输出格式为640x480 RGB565(彩色图像)
  30.     # RGB565格式:每个像素16位(5位红色,6位绿色,5位蓝色)
  31.     sensor.set_framesize(width=640, height=480, chn=CAM_CHN_ID_1)
  32.     sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_1)
  33.     # Configure channel 0 output format to 640x480 GRAYSCALE  
  34.     # 配置通道0输出格式为640x480 GRAYSCALE(灰度图像)
  35.     # 灰度图像更适合特征点检测算法
  36.     sensor.set_framesize(width=640, height=480, chn=CAM_CHN_ID_0)
  37.     sensor.set_pixformat(Sensor.GRAYSCALE, chn=CAM_CHN_ID_0)
  38.     return sensor
  39. def main():
  40.     """
  41.     Main function to run camera preview
  42.     运行摄像头预览的主函数
  43.     """
  44.     sensor = None  # 传感器对象初始化为None
  45.    
  46.     # 定义感兴趣区域(ROI) - Region of Interest
  47.     # 格式: (x, y, width, height)
  48.     # 从(220,140)开始,宽200像素,高200像素的正方形区域
  49.     roi = (220, 140, 200, 200)
  50.    
  51.     try:
  52.         # Initialize camera sensor
  53.         # 初始化摄像头传感器
  54.         sensor = init_sensor()
  55.         # Initialize display with ST7701 driver
  56.         # 使用ST7701驱动初始化显示器
  57.         # 分辨率640x480,to_ide=True表示同时输出到IDE和硬件屏幕
  58.         Display.init(Display.ST7701, width=640, height=480, to_ide=True)
  59.         # Initialize media management
  60.         # 初始化媒体管理(管理摄像头、显示等硬件资源)
  61.         MediaManager.init()
  62.         # Start sensor operation
  63.         # 启动传感器运行(开始捕获图像)
  64.         sensor.run()
  65.         # Main loop to capture and display frames
  66.         # 捕获和显示帧的主循环
  67.         while True:
  68.             # Capture color frame from channel 1 for display
  69.             # 从通道1捕获彩色帧用于显示
  70.             # RGB565格式,适合人眼观看
  71.             img = sensor.snapshot(chn=CAM_CHN_ID_1)
  72.             # Capture grayscale frame from channel 0 for keypoint detection
  73.             # 从通道0捕获灰度帧用于关键点检测
  74.             # 灰度图像计算量小,更适合计算机视觉算法
  75.             img_g = sensor.snapshot(chn=CAM_CHN_ID_0)
  76.             
  77.             # Draw ROI rectangle on the color image
  78.             # 在彩色图像上绘制ROI矩形框
  79.             # color=(173, 216, 230): 浅蓝色
  80.             # fill=False: 不填充,只绘制边框
  81.             # thickness=3: 线宽3像素
  82.             img.draw_rectangle(roi, color=(173, 216, 230), fill=False, thickness=3)
  83.             # Find keypoints in the grayscale image within ROI
  84.             # 在灰度图像的ROI区域内查找关键点
  85.             keypoints = img_g.find_keypoints(
  86.                 threshold=30,        # 特征点检测阈值,值越小检测越敏感
  87.                 scale_factor=1.2,    # 尺度因子,用于构建图像金字塔
  88.                 max_keypoints=30,    # 最大特征点数量,限制计算复杂度
  89.                 roi=roi              # 指定感兴趣区域,只在该区域内检测
  90.             )
  91.             # If keypoints are detected
  92.             # 如果检测到特征点
  93.             if keypoints:
  94.                 # Print keypoints information for debugging
  95.                 # 打印特征点信息用于调试
  96.                 print(keypoints)
  97.                
  98.                 # Draw keypoints on the color image
  99.                 # 在彩色图像上绘制特征点
  100.                 img.draw_keypoints(
  101.                     keypoints,        # 特征点列表,包含每个特征点的坐标和分数
  102.                     color=(255, 0, 0), # 红色 (RGB格式)
  103.                     size=8,           # 特征点显示大小(像素)
  104.                     thickness=4,      # 绘制线条的粗细
  105.                     fill=True         # 填充特征点(实心圆点)
  106.                 )
  107.                
  108.             # Display captured frame with keypoints
  109.             # 显示带有关键点的捕获帧
  110.             Display.show_image(img)
  111.     except KeyboardInterrupt:
  112.         # Handle user interruption (Ctrl+C)
  113.         # 处理用户中断(Ctrl+C)
  114.         print("User interrupted the program")
  115.         print("用户中断了程序")
  116.     except Exception as e:
  117.         # Handle other exceptions
  118.         # 处理其他异常
  119.         print(f"An error occurred: {str(e)}")
  120.         print(f"发生错误: {str(e)}")
  121.     finally:
  122.         # Cleanup section - always executed
  123.         # 清理部分 - 始终执行
  124.         
  125.         # Stop sensor if initialized
  126.         # 如果传感器已初始化则停止
  127.         if isinstance(sensor, Sensor):
  128.             sensor.stop()
  129.         # Deinitialize display
  130.         # 反初始化显示(释放显示资源)
  131.         Display.deinit()
  132.         # Enable sleep mode
  133.         # 启用睡眠模式(节能)
  134.         os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
  135.         time.sleep_ms(100)  # 等待100毫秒确保资源释放完成
  136.         # Release media resources
  137.         # 释放媒体资源
  138.         MediaManager.deinit()
  139. if __name__ == "__main__":
  140.     # Program entry point
  141.     # 程序入口点
  142.     main()
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 17:45

【花雕动手做】CanMV K230 AI视觉模块之绘制关键点图框

解读这段CanMV K230关键点检测代码的技术细节和实现原理:

整体架构分析
1. 双通道并行处理架构
python
  1. # 关键的双通道配置
  2. sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_1)    # 显示通道
  3. sensor.set_pixformat(Sensor.GRAYSCALE, chn=CAM_CHN_ID_0) # 处理通道
复制代码

技术优势:
性能优化:灰度图像处理计算量仅为彩色图像的1/3
实时性保证:算法处理和显示渲染并行进行
资源利用:充分利用硬件多通道能力

核心技术深度解析
1. 关键点检测算法原理
find_keypoints() 方法底层可能使用的算法:

python
  1. # 基于FAST角点检测算法的实现原理
  2. def fast_corner_detector(image, threshold):
  3.     """
  4.     FAST (Features from Accelerated Segment Test) 算法
  5.     """
  6.     keypoints = []
  7.     for y in range(3, image.height-3):
  8.         for x in range(3, image.width-3):
  9.             # 获取中心像素强度
  10.             center = image[y][x]
  11.             
  12.             # 检查16个周边像素
  13.             circle_pixels = get_bresenham_circle(x, y)
  14.             
  15.             # 快速测试:检查连续N个像素是否都大于或小于中心像素
  16.             if fast_test(circle_pixels, center, threshold):
  17.                 # 计算角点得分
  18.                 score = compute_corner_score(circle_pixels, center)
  19.                 keypoints.append(Keypoint(x, y, score))
  20.    
  21.     return non_maximum_suppression(keypoints)
复制代码

ORB特征点检测流程:

text
1. oFast角点检测
   └── 构建图像金字塔
   └── 多尺度角点检测
   └── Harris角点响应计算

2. rBRIEF描述符计算
   └── 方向归一化
   └── 二进制描述符生成
   └── 特征点排序和筛选
2. 参数调优分析
python
  1. keypoints = img_g.find_keypoints(
  2.     threshold=30,        # 角点检测阈值
  3.     scale_factor=1.2,    # 图像金字塔尺度因子
  4.     max_keypoints=30,    # 最大特征点数量
  5.     roi=roi              # 感兴趣区域
  6. )
复制代码


【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框图1

3. ROI技术实现原理
python
  1. roi = (220, 140, 200, 200)  # (x, y, width, height)
  2. ROI内存访问优化:
  3. c
  4. // 底层C实现可能类似这样
  5. for(int y = roi_y; y < roi_y + roi_height; y++) {
  6.     for(int x = roi_x; x < roi_x + roi_width; x++) {
  7.         // 只处理ROI区域内的像素
  8.         process_pixel(image[y][x]);
  9.     }
  10. }
复制代码

计算量对比:
全图检测:640×480 = 307,200 像素
ROI检测:200×200 = 40,000 像素
性能提升:约87%的计算量减少

图像处理流水线分析
1. 数据流架构
text
摄像头传感器
    ↓
双通道输出
    ├── 通道0 (GRAYSCALE) → 特征检测 → 关键点坐标
    └── 通道1 (RGB565) → 显示渲染 ← 绘制关键点
    ↓
显示输出

2. 内存管理策略
python
  1. # 图像缓冲区内存占用分析
  2. gray_buffer = 640 * 480 * 1  # 307,200 字节 (300KB)
  3. rgb_buffer  = 640 * 480 * 2  # 614,400 字节 (600KB)
  4. total_memory = gray_buffer + rgb_buffer  # 约900KB
  5. # 关键点数据结构
  6. class Keypoint:
  7.     x: int16          # 2字节
  8.     y: int16          # 2字节  
  9.     score: float32    # 4字节
  10.     angle: float32    # 4字节
  11.     size: float32     # 4字节
  12.     # 总计: 16字节/关键点 × 30 = 480字节
复制代码

算法性能优化技术
1. 图像金字塔优化
python
  1. # 多尺度检测的实现
  2. def build_image_pyramid(image, scale_factor, levels):
  3.     pyramid = [image]
  4.     for i in range(1, levels):
  5.         # 高斯模糊 + 下采样
  6.         blurred = gaussian_blur(pyramid[i-1])
  7.         downsampled = resize(blurred, scale_factor)
  8.         pyramid.append(downsampled)
  9.     return pyramid
复制代码

2. 非极大值抑制(NMS)
python
  1. def non_maximum_suppression(keypoints, radius=3):
  2.     """
  3.     移除相邻区域内响应较低的特征点
  4.     """
  5.     suppressed = []
  6.     keypoints.sort(key=lambda kp: kp.score, reverse=True)
  7.    
  8.     for kp in keypoints:
  9.         is_local_max = True
  10.         for existing in suppressed:
  11.             if distance(kp, existing) < radius and kp.score <= existing.score:
  12.                 is_local_max = False
  13.                 break
  14.         if is_local_max:
  15.             suppressed.append(kp)
  16.    
  17.     return suppressed
复制代码

实际应用场景扩展
1. 实时目标跟踪
python
  1. class FeatureTracker:
  2.     def __init__(self):
  3.         self.prev_keypoints = None
  4.         self.prev_descriptors = None
  5.    
  6.     def track(self, current_frame):
  7.         current_keypoints = current_frame.find_keypoints(roi=tracking_roi)
  8.         
  9.         if self.prev_keypoints:
  10.             # 特征点匹配
  11.             matches = self.match_features(self.prev_descriptors,
  12.                                         current_keypoints.descriptors)
  13.             # 计算运动向量
  14.             motion = self.calculate_motion(matches)
  15.             return motion
  16.         
  17.         self.prev_keypoints = current_keypoints
  18.         return None
复制代码

2. 视觉里程计
python
  1. def visual_odometry(prev_frame, curr_frame):
  2.     prev_kps = prev_frame.find_keypoints()
  3.     curr_kps = curr_frame.find_keypoints()
  4.    
  5.     # 特征匹配
  6.     matches = feature_matcher.match(prev_kps, curr_kps)
  7.    
  8.     # 本质矩阵估计
  9.     E, mask = cv.findEssentialMat(prev_pts, curr_pts, camera_matrix)
  10.    
  11.     # 姿态恢复
  12.     _, R, t, mask = cv.recoverPose(E, prev_pts, curr_pts, camera_matrix)
  13.    
  14.     return R, t  # 旋转和平移矩阵
复制代码

错误处理和鲁棒性分析
1. 异常处理机制
python
  1. try:
  2.     # 主要处理逻辑
  3.     sensor.run()
  4.     while True:
  5.         img = sensor.snapshot(chn=CAM_CHN_ID_1)
  6.         # ... 处理代码
  7. except KeyboardInterrupt:
  8.     # 用户主动中断 - 友好退出
  9. except Exception as e:
  10.     # 其他异常 - 防止系统崩溃
  11. finally:
  12.     # 资源清理 - 确保资源释放
复制代码

2. 算法鲁棒性考虑
python
  1. def robust_keypoint_detection(image):
  2.     # 1. 图像质量检查
  3.     if image.is_too_dark() or image.is_too_bright():
  4.         adjust_exposure()
  5.    
  6.     # 2. 特征点数量验证
  7.     keypoints = image.find_keypoints()
  8.     if len(keypoints) < 5:  # 特征点太少
  9.         # 调整检测参数或返回错误
  10.         return adjust_and_retry(image)
  11.    
  12.     # 3. 特征点分布检查
  13.     if not is_uniformly_distributed(keypoints):
  14.         # 特征点聚集在某些区域
  15.         return redistribute_keypoints(keypoints)
  16.    
  17.     return keypoints
复制代码

性能基准测试
根据代码参数估算性能:
处理分辨率:200×200 ROI
特征点数量:最多30个
预计帧率:15-30 FPS(取决于硬件)
内存占用:约900KB图像缓冲区 + 算法临时内存

技术总结
这段关键点检测代码展示了:
嵌入式视觉系统设计:双通道并行处理架构
实时算法优化:ROI限制、参数调优、内存管理
计算机视觉基础:特征点检测算法原理
系统集成能力:摄像头、显示、算法的协同工作
工程实践:异常处理、资源管理、性能考量

这是一个典型的嵌入式计算机视觉应用,为更复杂的目标识别、SLAM、AR等应用提供了基础技术支撑。代码在性能、功能和可维护性之间取得了很好的平衡。

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 昨天 17:49

【花雕动手做】CanMV K230 AI视觉模块之绘制关键点图框

实验场景图

【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框图1

【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框图3

【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框图2

【花雕动手做】CanMV K230 AI 视觉模块之绘制关键点图框图4
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail