• python解析曲线数据图方法一则


    我们在数据分析工作中,经常遇到没有直接数据的情况,对于曲线图情况,我们需要解析曲线图中的数据。

    例如下图,根据文档我们获知横坐标取值范围为(0,175),纵坐标取值范围(0,156)。如何把曲线转换为可操作的数据呢,具体步骤如下:
    在这里插入图片描述

    1. 用画图工具抠图,按曲线图坐标边界抠出待处理图形,例如windows系统上的“画图”功能即可;
    2. 使用OpenCV提供的API,详见“Opencv-python去图标与水印方案实践”,采用直接提取曲线的方案;
    3. 使用OpenCV提供的图像灰度处理及二值化API,得到目标图;
    4. 解析二值化的灰度图像得出数据。

    1. 用画图工具抠图

    在这里插入图片描述
    我们把抠出来的图,另存为:heart1.JPG。

    2. OpenCV直接提取曲线的方案

    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    img=cv2.imread('img\heart1.JPG')
    
    h,w,l=img.shape
    
    for j in range(h):
        for k in range(w):
            if img[j][k][0] <135 or img[j][k][0] >175 or img[j][k][1] <185 or img[j][k][1] >220 or img[j][k][2] <45 or img[j][k][2] >129:
                img[j][k][0] = 255
                img[j][k][1] = 255 
                img[j][k][2] = 255
                
    plt.imshow(img,cmap=plt.cm.gray)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    其中,提取颜色范围值,请参照文档“Opencv-python去图标与水印方案实践”。

    3. 使用OpenCV图像灰度处理及二值化API

    image_gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)  # 转换成灰度图
    plt.imshow(image_gray,cmap=plt.cm.gray)
    # 二值化
    thresh, new_img = cv2.threshold(image_gray, 200, 255, cv2.THRESH_BINARY)
    
    cv2.imshow('NEW_IMG', new_img)
    cv2.waitKey()
    new_img = new_img.astype(np.int16)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注:图像数据格式是uint8,最大值255,需要转换为int16,存储实际坐标值。

    OpenCV提供的图像二值化API,threshold()方法参数:

    • 图片矩阵
    • 阈值
    • 图片中的最大值
    • 二值化的方式

    二值化的方式:

    THRESH_BINARY高于阈值改为255,低于阈值改为0
    THRESH_BINARY_INV高于阈值改为0,低于阈值改为255
    THRESH_TRUNC截断,高于阈值改为阈值,最大值失效
    THRESH_TOZERO高于阈值不改变,低于阈值改为0
    THRESH_TOZERO_INV高于阈值该为0,低于阈值不改变

    在这里插入图片描述

    4. 解析二值化的灰度图像得出数据

    解析数据的原理:

    首先,明确坐标系统,图像数据(二维),从(0,0)开始对应实际图形(0,h),其中h是最大高度,可以理解为纵向坐标倒序。

    其次,解析图数据,对于图中曲线黑色,数值为0,直接标记为纵轴的坐标(注意倒序),其他设置为0,由此获得二维矩阵待处理。

    接着,按坐标均值定义为目标数据。

    r,c = new_img.shape
    for i in range(r):
        for j in range(c):
            if new_img[i][j]==255:
                new_img[i][j]=0
            else:
                new_img[i][j]=280 - i + 1
    
    dat = new_img.mean(axis=0, keepdims=False,where=new_img>0)
    
    #滤除手工抠图边界无数据情况
    mask = np.isnan(dat)
    dat = np.delete(dat, np.where(mask))
    dat = dat*156/np.max(dat)
    # 解析出数据,未进行度量单位转换
    new_dat = dat.astype(np.int16)
    
    # 绘图回放数据
    plt.rcParams['font.sans-serif'] = ['SimHei']     # 设置正常显示中文
    plt.rcParams['axes.unicode_minus']=False # 解决不显示负号 
    plt.figure(figsize=(12,6))
    plt.xlim(0,570)
    x_lable = ['0','30','60','90','120','150','180']
    pos_list = [0, 94, 188, 281, 375, 469,563]
    
    plt.xticks(pos_list, x_lable)
    #ax = plt.axes()
    #ax.xaxis.set_major_locator(ticker.FixedLocator((name_list)))
    #ax.xaxis.set_major_formatter(ticker.FixedFormatter((x_lable)))
    plt.ylim(0,180)
    plt.plot(new_dat)
    plt.ylabel("心率")
    
    plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    绘图回放数据,结果如下:
    在这里插入图片描述

    5. 总结

    解析曲线数据图还是比较麻烦,首先是图像处理技术,我们常见的曲线图一般都较为干净,好处理些。在解析过程中,需要进行坐标转换,也就是数据的度量单位。

    欢迎交流更多的方法。

    参考:

    肖永威. Opencv-python去图标与水印方案实践. CSDN博客. 2023.09

  • 相关阅读:
    2022杭电多校联赛第十场 题解
    如何在线把pdf转换成word呢?
    vue 验证码 图片点击
    通过内网穿透,在Windows 10系统下搭建个人《我的世界》服务器公网联机
    【实用工具】谷歌浏览器插件开发指南
    【云原生】五年博主教你用阿里云Serverless免费额度搭建个人应用服务, 还不赶快上车。
    MATLAB学习
    Django REST framework 简介
    【面试经典150 | 栈】简化路径
    Linux笔记系列
  • 原文地址:https://blog.csdn.net/xiaoyw/article/details/132918834