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)

其中,提取颜色范围值,请参照文档“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)

注:图像数据格式是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()

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

5. 总结

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

欢迎交流更多的方法。

参考:

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

猜你喜欢

转载自blog.csdn.net/xiaoyw/article/details/132918834