opencv-python实战项目三:温度计液位识别


一、简介:

液位检测在工业生产中具有重要意义,它关乎生产安全、效率和质量。传统的液位检测方法如浮子式、压力式等存在一定的局限性。随着图像处理技术的发展,利用摄像头结合传统图像处理方法进行液位识别逐渐成为一种趋势。本文将以一个简单的温度计温度识别为例子,带你了解如何使用传统图像处理技术实现液位识别。

二、温度计液位检测所用的方案:

本方案首先采用伽马变换对液位颜色进行增强处理,以提升液位与背景的对比度;接着利用Otsu二值化方法对增强后的图像进行分割,明确区分液位与背景;然后通过形态学变换去除图像中的文字和刻度,以获得干净的液位图;最终,根据像素映射关系,将液位高度准确映射回实际距离,从而实现液位的精确测量。

三、算法实现步骤

3.1液位高度标定

标定液位高度即确定温度计量程所代表的像素高度,标定方法为:计算温度计上下端量程所对应的y值,二者相减获得量程的高度差也就是下图蓝线所代表的像素值:
在这里插入图片描述

获取y值代码:

import cv2
##此代码可以返回鼠标点击的点位置,点在温度计量程上
# 鼠标回调函数
def mouse_callback(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:  # 检测到左键单击
        # 获取并打印鼠标点击位置的像素值
        pixel_value = image[y, x]
        print(f"位置 ({x}, {y}) 的像素值为: {pixel_value}")
# 读取图像
image = cv2.imread(r'F:\2024-07-20\11.jpg')
# 检查图像是否成功加载
if image is None:
    print("Error: 图像无法加载。请检查路径是否正确。")
else:
    # 创建窗口
    cv2.namedWindow('Image')
    # 设置鼠标回调函数
    cv2.setMouseCallback('Image', mouse_callback)
    # 显示图像
    while True:
        cv2.imshow('Image', image)
        # 按 'q' 键退出
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    # 关闭所有窗口
    cv2.destroyAllWindows()

3.2 伽马增强增强液柱信息

伽马变换是一种图像处理技术,它通过调整图像的亮度和对比度来改善视觉效果。简单来说,它改变了图像中每个像素的亮度级别:如果伽马值大于1,图像的暗部会变得更亮,而亮部则相对保持不变;如果伽马值小于1,则亮部会变得更亮,暗部则相对变暗。这种变换有助于使图像看起来更加自然,尤其是在光线不足或过亮的情况下。

实现代码:

def gamma_trans(img, gamma):  # 定义一个gamma校正函数
    # 创建一个查找表,用于将原始像素值映射到gamma校正后的像素值
    gamma_table = [np.power(x / 255.0, gamma) * 255.0 for x in range(256)]
    # 将查找表转换为numpy数组,并四舍五入到最近的整数
    gamma_table = np.round(np.array(gamma_table)).astype(np.uint8)
    # 使用OpenCV的LUT函数进行颜色映射
    return cv2.LUT(img, gamma_table)

效果如下:
在这里插入图片描述
左侧为增强前,右侧为增强后,增强后液柱的特征更明显

3.3 大津算法与形态学变换提取液位信息

大津算法(Otsu’s Method)是一种自动确定图像二值化阈值的方法。它的基本思想是寻找一个阈值,使得图像中前景和背景的类间方差最大,同时类内方差最小。简而言之,就是通过计算不同阈值下的类间方差,找到最优阈值,将图像分为前景和背景两部分,以达到最佳分割效果。大津算法适用于图像前景和背景对比度明显的情况,是一种广泛使用的图像分割技术.
形态学变换是图像处理中的一种基本操作,它基于数学形态学的理论,通过结构元素对图像进行一系列的形态操作。这些操作通常包括膨胀、腐蚀、开运算和闭运算等,用于提取图像中的有用信息,如边界、轮廓、连通区域等,同时可以去除噪声、平滑边缘、填充孔洞等。
根据大津二值化与形态学闭运算处理无用信息,获取液位信息,提取后的信息效果如下:
在这里插入图片描述

实现代码:

# 定义结构元素,用于形态学操作
kernel = np.ones((11, 11), np.uint8)
# 应用Otsu二值化
_, th = cv2.threshold(gam, 0, 255, cv2.THRESH_OTSU)
# 使用闭运算去除刻度线以及文字
close = cv2.morphologyEx(th, cv2.MORPH_CLOSE, kernel)

3.4 筛选图像轮廓选择液位处轮廓

代码如下(示例):

contours, _ = cv2.findContours(close_inv, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 按轮廓面积降序排序
contours = sorted(contours, key=cv2.contourArea, reverse=True)
max_contour = contours[0]  # 获取最大的轮廓

3.5 计算液位像素点高度并映射回实际值

points = max_contour[:, 0, :]  # 提取轮廓中的所有点
    # 按照y坐标对点进行排序
sorted_points = points[np.argsort(points[:, 1])]
    # 计算液位高度,并转换为实际温度
temp = value_pix2 - sorted_points[0][1]  # 液柱最上面的点的y值距离底边的像素值长度
temperature = temp * (value_true / value_pix) - 30  # 转换为温度值 30为温度计的下限零下三十度
print("温度为", temperature)

四、代码实现

import cv2
import numpy as np

# 定义一些常量,用于后续计算
value_pix2 = 475  # 图像底部固定的像素位置
value_pix = 394  # 图像底部和顶部之间的像素差,用于计算液位高度
value_true = 80  # 此款温度计总共有八十个刻度
def gamma_trans(img, gamma):  # 定义一个gamma校正函数
    # 创建一个查找表,用于将原始像素值映射到gamma校正后的像素值
    gamma_table = [np.power(x / 255.0, gamma) * 255.0 for x in range(256)]
    # 将查找表转换为numpy数组,并四舍五入到最近的整数
    gamma_table = np.round(np.array(gamma_table)).astype(np.uint8)
    # 使用OpenCV的LUT函数进行颜色映射
    return cv2.LUT(img, gamma_table)
# 读取图像,使用灰度模式
img = cv2.imread(r'F:\2024-07-20\11.jpg', 0)
# 定义结构元素,用于形态学操作
kernel = np.ones((11, 11), np.uint8)
# 应用gamma校正和模糊处理
gam = gamma_trans(img, 2.5)
gam = cv2.GaussianBlur(gam, (5, 5), 0)
# 应用Otsu二值化
_, th = cv2.threshold(gam, 0, 255, cv2.THRESH_OTSU)
# 使用闭运算去除刻度线以及文字
close = cv2.morphologyEx(th, cv2.MORPH_CLOSE, kernel)
# 反转图像,以便于后续轮廓检测
close_inv = 255 - close

# 查找并绘制轮廓
contours, _ = cv2.findContours(close_inv, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 按轮廓面积降序排序
contours = sorted(contours, key=cv2.contourArea, reverse=True)
if contours:
    max_contour = contours[0]  # 获取最大的轮廓
    points = max_contour[:, 0, :]  # 提取轮廓中的所有点
    # 按照y坐标对点进行排序
    sorted_points = points[np.argsort(points[:, 1])]
    # 计算液位高度,并转换为实际温度
    temp = value_pix2 - sorted_points[0][1]  # 液柱最上面的点的y值距离底边的像素值长度
    temperature = temp * (value_true / value_pix) - 30  # 转换为温度值
    print("温度为", temperature)
# 显示处理后的图像
cv2.imshow("ori", img)
cv2.imshow("gam", gam)
cv2.imshow("close", close)
# 等待按键后退出
cv2.waitKey(0)

五:效果:

在这里插入图片描述
由于像素误差,温度大概差了0.8度,可以通过图像超分或者对上液位轮廓点取均值进一步降低误差

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值