基于opencv的斜光测距及python实现

1.前言

最近做了一个基于opencv的斜光测距的小项目,东西不多,但是很有意思,值得拿出来学一学。项目里面需要比较精确的定位功能,将前人matlab代码移植到python上,并且做了一些优化,简化逻辑(毕竟我是专业的程序员),也用了tkinter界面包装了一下,最后通过pyinstaller打包成程序给同事使用。

2.原理

在这里插入图片描述

通过使用不同的亮点位置和对应的高度进行多元线性回归建模,再对新的亮点位置进行高度预测。

在这里插入图片描述

如图分别是14,14.5,15,15.5对应的四张光点位置图。

3.获取亮点位置

def get_box(image):
    # 将图像转换为灰度图像
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 应用高斯模糊来减少噪声
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    max_val = np.max(blurred)
    _, binary = cv2.threshold(blurred, max_val/2, 255, cv2.THRESH_BINARY)
    # 形态学开运算去除噪声
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
    # 找到轮廓
    contours, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 如果找到轮廓,计算质心
    if contours:
        largest_contour = max(contours, key=cv2.contourArea)
        M = cv2.moments(largest_contour)
        if M["m00"] != 0:
            cx = int(M["m10"] / M["m00"])
            cy = int(M["m01"] / M["m00"])
        else:
            cx, cy = 0, 0
        centroid = (cx, cy)
        # 计算边界框
        x, y, w, h = cv2.boundingRect(largest_contour)
        p=10
        bbox = (x-p, y-p, w+2*p, h+2*p)
        # 在图像上绘制质心和边界框
        output_image = image.copy()
        cv2.circle(output_image, centroid, 5, (0, 255, 0), -1)
        x,y,w,h=bbox
        cv2.rectangle(output_image, (x, y), (x + w, y + h), (0, 255, 0), 2)
        print(f"亮点的中心位置: {centroid},亮点的边界框: {bbox}")
        return centroid,bbox,output_image
    else:
        return None

4.建模

不想再安装其它的python包了,就基于numpy写的LineRegression。

class LinearRegression:
    def __init__(self):
        self.theta = None

    def fit(self, X, y):
        """
        训练线性回归模型

        参数:
        X:自变量数据,形状为 (m, n),其中 m 是样本数量,n 是特征数量
        y:因变量数据,形状为 (m, 1)
        """
        # 在 X 前面加一列1,以便于计算截距项
        X_b = np.c_[np.ones((X.shape[0], 1)), X]

        # 使用正规方程求解回归系数
        self.theta = np.linalg.inv(X_b.T @ X_b) @ X_b.T @ y

    def predict(self, X):
        """
        对新样本进行预测

        参数:
        X:自变量数据,形状为 (m, n),其中 m 是样本数量,n 是特征数量

        返回值:
        y_pred:预测的因变量数据,形状为 (m, 1)
        """
        if self.theta is None:
            raise ValueError("模型未经过训练,请先调用 fit 方法")

        # 在 X 前面加一列1,以便于计算截距项
        X_b = np.c_[np.ones((X.shape[0], 1)), X]

        # 使用训练得到的回归系数进行预测
        y_pred = X_b @ self.theta

        return y_pred

建模效果
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.全部代码

项目地址:https://gitee.com/zhang_jie_sc/auto-focus

import re
import cv2
import numpy as np
import os

from matplotlib import pyplot as plt


def get_box(image):
    # 将图像转换为灰度图像
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 应用高斯模糊来减少噪声
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    max_val = np.max(blurred)
    _, binary = cv2.threshold(blurred, max_val/2, 255, cv2.THRESH_BINARY)
    # 形态学开运算去除噪声
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
    # 找到轮廓
    contours, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 如果找到轮廓,计算质心
    if contours:
        largest_contour = max(contours, key=cv2.contourArea)
        M = cv2.moments(largest_contour)
        if M["m00"] != 0:
            cx = int(M["m10"] / M["m00"])
            cy = int(M["m01"] / M["m00"])
        else:
            cx, cy = 0, 0
        centroid = (cx, cy)
        # 计算边界框
        x, y, w, h = cv2.boundingRect(largest_contour)
        p=10
        bbox = (x-p, y-p, w+2*p, h+2*p)
        # 在图像上绘制质心和边界框
        output_image = image.copy()
        cv2.circle(output_image, centroid, 5, (0, 255, 0), -1)
        x,y,w,h=bbox
        cv2.rectangle(output_image, (x, y), (x + w, y + h), (0, 255, 0), 2)
        print(f"亮点的中心位置: {centroid},亮点的边界框: {bbox}")
        return centroid,bbox,output_image
    else:
        return None

def get_files(dir):
    img_path_list = [f for f in os.listdir(dir) if
                     f.startswith('Point') and f.endswith('.jpg')]  # 获取该文件夹中所有jpg格式的图像
    val_list=[]
    for p in img_path_list:
        # 使用正则表达式匹配_后.前的0或0.5
        match = re.search(r'_(\d+(\.\d+)?)\.', p)
        if match:
            val=match.group(1)
            val_list.append(float(val))
        else:
            raise ValueError('{0}文件名错误,无法提取位置i学那些'.format(p))
    return img_path_list,val_list

def merge_intersecting_boxes(boxes):
    merged_boxes = []

    # 计算包含所有框的大框
    x_min = min(box[0] for box in boxes)
    y_min = min(box[1] for box in boxes)
    x_max = max(box[0] + box[2] for box in boxes)
    y_max = max(box[1] + box[3] for box in boxes)
    big_box = (x_min, y_min, x_max - x_min, y_max - y_min)

    # 返回大框和空的合并框列表
    return big_box, merged_boxes

def r2_score(y_true,y_pred):
    # 计算相关系数
    corr = np.corrcoef(y_true, y_pred)[0, 1]
    # 计算 R 方值
    r2 = corr ** 2
    return r2

def plot_image_and_r2_zzz(image, x, y,r2,theta):
    # 将 BGR 格式转换为 RGB 格式
    image = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2RGB)
    # 创建一个图形和两个子图
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5), gridspec_kw={'top': 0.85})
    # 设置窗口标题方式二
    fig.canvas.manager.window.title("建模结果")
    # 在第一个子图中显示图片
    ax1.imshow(image)
    ax1.axis('off')
    ax1.set_title('Box')

    # 在第二个子图中显示拟合直线
    ax2.plot(x, y, 'o', label='Data')
    ax2.plot(x, x, label='Fitted Line')
    # 将每个数字转换为字符串,保留五位小数
    theta_str = "(k1={:.4f}, k2={:.4f}, b={:.4f})".format(*theta)
    ax2.set_title('Fitted Line (theta={}, r2={:.5f})'.format(theta_str,r2))
    # 添加轴标签
    ax2.set_xlabel('y_true')
    ax2.set_ylabel('y_pred')
    ax2.legend()
    # 显示图形
    plt.tight_layout()
    plt.show()

class LinearRegression:
    def __init__(self):
        self.theta = None

    def fit(self, X, y):
        """
        训练线性回归模型

        参数:
        X:自变量数据,形状为 (m, n),其中 m 是样本数量,n 是特征数量
        y:因变量数据,形状为 (m, 1)
        """
        # 在 X 前面加一列1,以便于计算截距项
        X_b = np.c_[np.ones((X.shape[0], 1)), X]

        # 使用正规方程求解回归系数
        self.theta = np.linalg.inv(X_b.T @ X_b) @ X_b.T @ y

    def predict(self, X):
        """
        对新样本进行预测

        参数:
        X:自变量数据,形状为 (m, n),其中 m 是样本数量,n 是特征数量

        返回值:
        y_pred:预测的因变量数据,形状为 (m, 1)
        """
        if self.theta is None:
            raise ValueError("模型未经过训练,请先调用 fit 方法")

        # 在 X 前面加一列1,以便于计算截距项
        X_b = np.c_[np.ones((X.shape[0], 1)), X]

        # 使用训练得到的回归系数进行预测
        y_pred = X_b @ self.theta

        return y_pred

if __name__=='__main__':
    file_dir="./20240531_113524"
    img_path_list, locs = get_files(file_dir)
    coors = []
    boxs = []
    for i, image_name in enumerate(img_path_list):  # 逐一读取图像
        item = cv2.imread(os.path.join(file_dir, image_name))
        cneter, box, _ = get_box(item)
        coors.append(list(cneter))
        boxs.append(box)
    merge_box, _ = merge_intersecting_boxes(boxs)
    # 使用线性回归拟合数据
    matx = np.array(coors)
    arr_x = matx[:, 0]
    reg = LinearRegression()
    reg.fit(matx, locs)
    y_true = np.array(locs)
    y_pred = reg.predict(matx)
    r2 = r2_score(y_true, y_pred)
    # 输出 R^2 值
    draw_img = cv2.imread(os.path.join(file_dir, img_path_list[0]), cv2.IMREAD_COLOR)
    x, y, w, h = merge_box
    cv2.rectangle(draw_img, (x, y), (x + w, y + h), (0, 255, 0), 2)
    plot_image_and_r2_zzz(draw_img, y_true, y_pred, r2, reg.theta)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/771274.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何选择快手矩阵系统:打造高效短视频营销的指南

快手作为中国领先的短视频社交平台,为内容创作者和品牌提供了广阔的展示舞台。为了更高效地管理和扩展在快手上的影响力,快手矩阵系统成为了一个重要的工具。本文将指导您如何选择一个合适的快手矩阵系统,以优化您的内容管理和营销策略。 快…

Kotlin和Java的一些不同点

1.Kotlin 的变量是没有默认值的(因此要求初始化),Java的成员变量是有默认值的 Java的成员变量: String name; // 默认值是 null int count; // 默认值是 0不过其实 Java 也只是成员变量有默认值,局部变量也是没有默…

中俄汽车产业链合作前景广阔,东方经济论坛助力双边合作与创新

随着中国汽车零部件企业的竞争力和创新能力不断增强,中国汽车及零部件行业在俄罗斯的市场份额和品牌影响力显著提升,中俄两国在汽车产业链上的合作展现出巨大的潜力和广阔的前景。2024年5月,俄罗斯乘用车新车销量达到12.8万辆,同比…

【计算机网络仿真】b站湖科大教书匠思科Packet Tracer——实验15 网络故障导致的路由环路问题

一、实验目的 1.验证因网络故障而导致的静态路由的路由环路问题; 二、实验要求 1.使用Cisco Packet Tracer仿真平台; 2.观看B站湖科大教书匠仿真实验视频,完成对应实验。 三、实验内容 1.构建网络拓扑; 2.验证网络故障导致的…

LTSPICE仿真电路:(十九)磁珠的一些简单仿真

1.作用 简单来说就是用来滤波的,将高频信号转化为热量滤除掉,低频有用信号正常通过 2.参数 上图几个参数比较简单,就是字面上的意思,更重要的就是频率阻抗图 不同曲线代表不同型号的磁珠,实际上除了额定电流外&#…

Spring框架的学习SpringMVC(1)

1.什么是MVC (1)MVC其实就是软件架构的一种设计模式,它将软件的系统分为,(视图,模型,控制器)三个部分 1.1View(视图) 视图也就是,在浏览器显示的那一个部分,是后端数据的呈现 1.…

某DingTalk企典 - Token

⚠️前言⚠️ 本文仅用于学术交流。 学习探讨逆向知识,欢迎私信共享学习心得。 如有侵权,联系博主删除。 请勿商用,否则后果自负。 网址 aHR0cHM6Ly9kaW5ndGFsay5jb20vcWlkaWFuLw 浅聊一下 没毛病,就这字段,有效期…

二叉树与堆相关的时间复杂度问题

目录 满二叉树与完全二叉树高度h和树中节点个数N的关系 向上调整算法: 介绍: 复杂度推导: 向下调整算法: 介绍: 复杂度推导: 向上调整建堆: 介绍: 复杂度推导:…

9.x86游戏实战-汇编指令mov

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 工具下载: 链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

怎么找到DNS服务器的地址?

所有域都注册到域名名称服务器(DNS)点,以解析域名应指向的IP地址。此查找类似于在查找个人名称并查找其电话号码时的电话簿如何运行。如果DNS服务器设置错误或指向错误的名称服务器,则域可能无法加载相应的网页。 如何查找当前的…

【python基础】—calendar模块

文章目录 前言一、calendar模块方法1.firstweekday()2.setfirstweekday(firstweekday)3.isleap(year)4.leapdays(y1, y2)5.weekday(year, month, day)6.monthrange(year, month)7.weekheader(n)8.monthcalendar(year, month)9.prmonth(theyear, themonth, w0, l0)10.prcal(year…

堆结构、堆排序

堆 是完全二叉树,类似这种样式的 而这种有右子节点,没左子节点的就不是完全二叉树 分为大根堆和小根堆 大根堆是二叉树里每一颗子树的父节点都是这颗子树里最大的,即每一棵子树最大值是头节点的值 小根堆相反 把数组中从0开始的一段数人…

【等保2.0是什么意思?等保2.0的基本要求有哪些? 】

一、等保2.0是什么意思? 等保2.0又称“网络安全等级保护2.0”体系,它是国家的一项基本国策和基本制度。在1.0版本的基础上,等级保护标准以主动防御为重点,由被动防守转向安全可信,动态感知,以及事前、事中…

Stable Diffusion图像的脸部细节控制——采样器全解析

文章目录 艺术地掌控人物形象好易智算原因分析为什么在使用Stable Diffusion生成全身图像时,脸部细节往往不够精细? 解决策略 局部重绘采样器总结 艺术地掌控人物形象 在运用Stable Diffusion这一功能强大的AI绘图工具时,我们往往会发现自己…

开源的基于图像识别本地实名认证系统(本项目不借助任何api) v1.0

前言: 本项目主要是代替昂贵的实名认证服务api或者sdk,目前仍然存在很多缺点 一、具体介绍 1.组成: 人脸识别服务器分为两部分: (1)、http服务端 server.py共有四个函数: DrawFaceinIdCard:用户上传身份证图片后,服务端会对身份证进行抠人像和ocr处理…

澳蓝荣耀时刻,6款产品入选2024年第一批《福州市名优产品目录》

近日,福州市工业和信息化局公布2024年第一批《福州市名优产品目录》,澳蓝自主研发生产的直接蒸发冷却空调、直接蒸发冷却组合式空调机组、间接蒸发冷水机组、高效间接蒸发冷却空调机、热泵式热回收型溶液调湿新风机组、防火湿帘6款产品成功入选。 以上新…

正交的拉丁方阵(MOLS)

在组合数学中,如果两个同阶的拉丁方阵叠加后,每个位置上的有序对条目都是唯一的,则这两个拉丁方阵被称为正交的。 如果一组同阶的拉丁方阵中,任意两个方阵都是正交的,则这组方阵被称为一组相互正交的拉丁方阵&#xf…

Prometheus 监控Kubelet的运行状态

kubelet通过/metrics暴露自身的指标数据。kubelet有两个端口都提供了这个url,一个是安全端口(10250),一个是非安全端口(10255,kubeadm安装的集群该端口是关闭的)。安全端口使用https协议&#x…

SpringMVC的架构有什么优势?——控制器(一)

文章目录 控制器(Controller)1. 控制器(Controller):2. 请求映射(Request Mapping):3. 参数绑定(Request Parameters Binding):4. 视图解析器(View Resolver):5. 数据绑定(Data Binding):6. 表单验证(Form Validation)…

02-部署LVS-DR群集

1.LVS-DR工作原理 LVS-DR模式,Director Server作为群集的访问入口,不作为网购使用,节点Director Server 与 Real Server 需要在同一个网络中,返回给客户端的数据不需要经过Director Server 为了响应对整个群集的访问,…
最新文章