如何用Python将图像形式的ECG转换为数值格式?
ECG图像转数值格式的Python实现方案
核心思路
针对带网格的ECG图像,不能直接提取原始像素值,需要先校准网格刻度,再提取波形坐标并转换为临床标准的数值(mV/秒)。
具体步骤与代码实现
1. 依赖库安装
先安装必要工具库:
pip install opencv-python numpy matplotlib
2. 图像预处理
对图像做灰度化、二值化和降噪,突出波形与网格:
import cv2 import numpy as np import matplotlib.pyplot as plt # 读取本地ECG图像(替换为你的图像路径) img = cv2.imread('ecg_image.jpg') # 灰度转换 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 自适应二值化,解决光照不均问题 binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 形态学降噪,去除小噪点 kernel = np.ones((2,2), np.uint8) cleaned = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
3. 校准网格刻度
ECG标准网格为小格1mm×1mm,对应纵向0.1mV、横向0.04秒(走纸速度25mm/s),先计算图像中每个小格的像素数:
# 提取水平网格线,计算纵向像素/mm horizontal_lines = cv2.HoughLinesP(cleaned, 1, np.pi/180, threshold=50, minLineLength=img.shape[1]//2, maxLineGap=5) y_coords = sorted([line[0][1] for line in horizontal_lines]) vertical_pixel_per_mm = y_coords[1] - y_coords[0] # 提取垂直网格线,计算横向像素/mm vertical_lines = cv2.HoughLinesP(cleaned, 1, np.pi/180, threshold=50, minLineLength=img.shape[0]//2, maxLineGap=5) x_coords = sorted([line[0][0] for line in vertical_lines]) horizontal_pixel_per_mm = x_coords[1] - x_coords[0] # 计算刻度转换系数 mv_per_pixel = 0.1 / vertical_pixel_per_mm # 单像素对应mV值 sec_per_pixel = 0.04 / horizontal_pixel_per_mm # 单像素对应秒值
4. 提取ECG波形并转换为数值
筛选波形轮廓,提取坐标后转换为标准数值:
# 查找图像轮廓,过滤掉网格线(保留细波形) contours, _ = cv2.findContours(cleaned, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 按面积、长度筛选波形轮廓(可根据图像调整阈值) wave_contours = [cnt for cnt in contours if cv2.contourArea(cnt) < 500 and cv2.arcLength(cnt, False) > 100] # 提取波形坐标并按时间顺序排序 wave_points = [] for cnt in wave_contours: for point in cnt: x, y = point[0] wave_points.append((x, y)) # 按x轴排序,保证时间序列正确 wave_points.sort(key=lambda p: p[0]) # 转换为临床数值:时间(秒)、电压(mV) base_y = y_coords[0] # 以第一条水平网格线为0mV基准 time_values = [x * sec_per_pixel for x, y in wave_points] # 图像y轴向下,需反转计算电压值 voltage_values = [(base_y - y) * mv_per_pixel for x, y in wave_points]
5. 结果验证
可视化转换后的波形,对比原图像:
plt.figure(figsize=(12, 6)) # 原图像展示 plt.subplot(211) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title('Original ECG Image') # 转换后波形展示 plt.subplot(212) plt.plot(time_values, voltage_values, color='red') plt.xlabel('Time (s)') plt.ylabel('Voltage (mV)') plt.title('Converted ECG Waveform') plt.tight_layout() plt.show()
注意事项
- 若图像倾斜,需先添加倾斜校正:用霍夫变换检测角度,旋转图像。
- 网格线提取不准确时,可调整霍夫变换的阈值参数,或手动指定网格区域。
- 波形轮廓筛选的阈值需根据实际图像调整,避免误把网格线识别为波形。
内容的提问来源于stack exchange,提问作者Hunter Ziuter
相关产品推荐
相关产品推荐

