快速线性回归
1.实验目的
实现K230对图像中的直线进行线性回归。
2.实验原理
2.1 原理解析
快速线性回归的原理是基于最小二乘法(Least Squares Method),其核心思想是:
在一组二维平面点中,寻找一条直线 y=ax+by = ax + by=ax+b,使所有点到该直线的“垂直距离的平方和”最小。
这种方法在图像处理中也很常用,比如在 CanMV 中的 get_regression(),它会在图像上的非零像素点集合中,寻找一条最优拟合直线。
在图像上,我们对所有非零像素(或满足阈值的像素)的位置 (x,y)(x, y)(x,y) 执行最小二乘法,即:
- 把每个符合条件的像素看作一个点;
 - 然后对这些点拟合出一条最佳线性模型;
 - 结果中返回的是线段坐标、斜率角度 θ、极坐标形式 rho、以及拟合质量指标 
magnitude。 
2.2 API
get_regression 函数用于从图像中检测回归线,即拟合数据点的直线。通常用于标记数据的趋势或方向。
- 语法
 
line = img.get_regression(threshold=1000, min_length=10, max_distance=5)
- 
参数解释
- threshold:直线的最小长度。默认值是 
1000。 - min_length: 拟合线的最小长度。默认值是 
10。 - max_distance: 允许的数据点到回归线的最大距离。默认值是 
5。 
 - threshold:直线的最小长度。默认值是 
 - 
返回值
返回一个包含回归线信息的
Line对象,表示拟合的直线。 
3.代码解析
获取当前图像帧
            img = sensor.snapshot()
进行二值化
            if BINARY_VISIBLE:
                img = img.binary([THRESHOLD])
线性回归检测
            line = img.get_regression([(255, 255)] if BINARY_VISIBLE else [THRESHOLD])
绘制灰色直线
            if line:
                img.draw_line(line.line(), color=127)
显示图像结果
          Display.show_image(img)
4.示例代码
'''
本程序遵循GPL V3协议, 请遵循协议
实验平台: DshanPI CanMV
开发板文档站点	: https://eai.100ask.net/
百问网学习平台   : https://www.100ask.net
百问网官方B站    : https://space.bilibili.com/275908810
百问网官方淘宝   : https://100ask.taobao.com
'''
import time, os, gc, sys
from media.sensor import *   # 摄像头接口
from media.display import *  # 图像显示接口
from media.media import *    # 媒体资源管理接口
# 设置检测图像尺寸(必须16字节对齐)
DETECT_WIDTH = ALIGN_UP(800, 16)
DETECT_HEIGHT = 480
# 设置灰度图像二值化的阈值范围(识别暗色区域)
THRESHOLD = (0, 100)
# 是否显示二值图像(便于观察回归线检测依据)
BINARY_VISIBLE = True
sensor = None  # 摄像头对象(全局变量)
# 摄像头初始化函数
def camera_init():
    global sensor
    # 创建摄像头对象,并设置图像尺寸
    sensor = Sensor(width=DETECT_WIDTH, height=DETECT_HEIGHT)
    sensor.reset()  # 复位摄像头配置
    # 可选配置:图像镜像和翻转(根据实际安装方向)
    # sensor.set_hmirror(False)
    # sensor.set_vflip(False)
    # 设置摄像头输出图像格式和尺寸
    sensor.set_framesize(width=DETECT_WIDTH, height=DETECT_HEIGHT)
    sensor.set_pixformat(Sensor.GRAYSCALE)  # 设置图像格式为灰度图
    # 使用虚拟显示器(例如IDE窗口)进行图像显示
    Display.init(Display.ST7701, width=DETECT_WIDTH, height=DETECT_HEIGHT, fps=100, to_ide=True)
    # 初始化媒体管理器,处理图像资源
    MediaManager.init()
    # 启动摄像头
    sensor.run()
# 摄像头资源释放函数
def camera_deinit():
    global sensor
    sensor.stop()  # 停止摄像头图像采集
    Display.deinit()  # 关闭显示器
    os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)  # 允许系统进入休眠点
    time.sleep_ms(100)  # 等待硬件处理完成
    MediaManager.deinit()  # 释放媒体资源
# 图像采集与线性回归检测
def capture_picture():
    fps = time.clock()  # 初始化帧率计时器
    while True:
        fps.tick()  # 每帧开始计时
        try:
            os.exitpoint()  # 检查系统是否请求退出
            global sensor
            img = sensor.snapshot()  # 获取当前图像帧
            # 根据阈值进行二值化(便于线性回归识别)
            if BINARY_VISIBLE:
                img = img.binary([THRESHOLD])
            # 执行线性回归检测(返回一条最佳拟合的线段)
            # 返回对象具有 x1/y1, x2/y2(线段两端点坐标),theta/rho(极坐标形式),length(), magnitude() 等方法
            # magnitude() 表示回归线拟合的好坏,值越大越准确
            line = img.get_regression([(255, 255)] if BINARY_VISIBLE else [THRESHOLD])
            # 若存在有效线段,则绘制在图像上
            if line:
                img.draw_line(line.line(), color=127)  # 绘制灰色直线
            # 打印帧率和线性拟合质量(magnitude)
            print("FPS %f, mag = %s" % (fps.fps(), str(line.magnitude()) if line else "N/A"))
            # 在 IDE 或屏幕上显示图像结果
            Display.show_image(img)
            # 删除图像,手动回收内存
            del img
            gc.collect()
        except KeyboardInterrupt as e:
            # 用户主动中断程序
            print("用户中止程序:", e)
            break
        except BaseException as e:
            # 捕获其他异常
            print(f"发生异常:{e}")
            break
# 主程序入口
def main():
    os.exitpoint(os.EXITPOINT_ENABLE)  # 启用系统退出检测
    camera_is_init = False
    try:
        print("初始化摄像头")
        camera_init()
        camera_is_init = True
        print("开始图像采集和线性回归")
        capture_picture()
    except Exception as e:
        print(f"发生异常:{e}")
    finally:
        if camera_is_init:
            print("释放摄像头资源")
            camera_deinit()
# 程序主入口
if __name__ == "__main__":
    main()
5.实验结果
 点击运行代码后,可以在显示屏上看到快速线性回归的结果。
