You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提取图像中曲线的像素坐标并调用scipy.find_peaks计算峰值点

问题描述

我有如下图像:
输入图像描述

我需要完成2个步骤:
步骤1: 获取图中每条曲线每个像素对应的(x,y)坐标,最终输出与曲线数量相等的数组,每个数组由对应曲线所有像素的{'x': x, 'y': y}对象组成。
步骤2: 将每条曲线对应的像素坐标数组输入scipy.find_peaks接口,计算得到每条曲线的峰值(即最大点)。

我目前已编写的代码如下:

from PIL import Image
import cv2

img_gray = cv2.imread('photo.jpg', cv2.IMREAD_GRAYSCALE)
img_binary = cv2.threshold(img_gray, 150, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite('save.jpg', img_binary)

image = cv2.imread('save.jpg')
cv2.imwrite('save.jpg', image)


im = Image.open("save.jpg")
im = im.convert('RGB')

col_black = (0, 0, 0)
col_white = (255, 255, 255)

for y in range(im.size[1]):
    for x in range(im.size[0]):
        if sum(im.getpixel((x, y))) < 128:
            im.putpixel((x, y), (0, 0, 0))
        else:
            im.putpixel((x, y), (255, 255, 255))

point_start_array = []
for x in range(im.size[0]):
    for y in range(im.size[1]):
        if im.getpixel((x, y)) == col_black and im.getpixel((x, y + 1)) == col_white:
            if len(point_start_array) > 4:
                break
            else:
                point_start_array.append({'x': x, 'y': y})

print(point_start_array)

当前输出:[{'x': 19, 'y': 161}, {'x': 19, 'y': 238}, {'x': 19, 'y': 260}, {'x': 19, 'y': 269}, {'x': 19, 'y': 282}]
输入图像描述

请问是否可以针对每条曲线分别提取x坐标数组和y坐标数组,传入scipy.find_peaks接口计算得到峰值?


回答

可以实现,完整的实现逻辑和代码如下:

核心思路

你当前的代码已经正确提取到了5条曲线在最左侧x=19处的起点坐标,接下来只需要逐列向右追踪每条曲线的所有像素点,就可以得到每条曲线的完整坐标数组,之后传入find_peaks接口即可计算峰值。
需要注意:图像的y坐标是从上到下递增的,波形的峰值对应图像里更小的y值,所以计算峰值前需要把y数组反转,或者调整find_peaks的参数适配坐标规则。

完整可运行代码

from PIL import Image
import cv2
from scipy.signal import find_peaks
import numpy as np

# 预处理部分和你的原有逻辑一致
img_gray = cv2.imread('photo.jpg', cv2.IMREAD_GRAYSCALE)
img_binary = cv2.threshold(img_gray, 150, 255, cv2.THRESH_BINARY)[1]
cv2.imwrite('save.jpg', img_binary)

im = Image.open("save.jpg").convert('RGB')
width, height = im.size
col_black = (0,0,0)

# 第一步:提取所有曲线的起点(优化原有逻辑避免越界)
point_start_array = []
for y in range(height-1):
    if im.getpixel((19, y)) == col_black and im.getpixel((19, y+1)) != col_black:
        point_start_array.append(y)
# 按y值从小到大排序,对应从上到下的5条曲线
point_start_array.sort()
curve_num = len(point_start_array)
print(f"检测到{curve_num}条曲线,起点y坐标:{point_start_array}")

# 第二步:逐列追踪每条曲线的所有点
curves = [[] for _ in range(curve_num)]
# 先初始化起点x=19的坐标
for i in range(curve_num):
    curves[i].append({'x':19, 'y':point_start_array[i]})

# 逐列向右遍历
search_range = 10 # 同一条曲线相邻列y值不会差太多,设置搜索范围避免串线
for x in range(20, width):
    # 对每条曲线,在上一个点的y附近找当前x列的黑色像素
    for i in range(curve_num):
        last_y = curves[i][-1]['y']
        # 确定搜索上下界,避免越界
        y_min = max(0, last_y - search_range)
        y_max = min(height-1, last_y + search_range)
        # 找当前列范围内的黑色像素
        found_y = None
        for y in range(y_min, y_max+1):
            if im.getpixel((x,y)) == col_black:
                found_y = y
                break
        if found_y is not None:
            curves[i].append({'x':x, 'y':found_y})

# 第三步:对每条曲线计算峰值
for idx, curve in enumerate(curves):
    # 提取y数组,因为图像y向下递增,所以取反变成向上递增,符合波形的数值大小逻辑
    y_arr = np.array([-p['y'] for p in curve])
    # 找峰值,可根据实际情况调整height、distance等参数
    peaks, _ = find_peaks(y_arr, distance=20)
    # 取最大的峰值(如果有多个的话)
    if len(peaks) > 0:
        max_peak_idx = peaks[np.argmax(y_arr[peaks])]
        peak_point = curve[max_peak_idx]
        print(f"第{idx+1}条曲线的峰值坐标:x={peak_point['x']}, y={peak_point['y']}")
    else:
        print(f"第{idx+1}条曲线未检测到峰值")

代码说明

  • 调整了起点提取逻辑,避免出现数组越界报错
  • 相邻列搜索时加了10像素的范围限制,避免曲线交叉的时候把不同曲线的点串到一起
  • 计算峰值时把y值取反,适配图像坐标和实际波形数值的对应关系,你也可以根据自己的坐标需求调整
  • find_peaks的参数可以根据你的曲线实际情况调整,比如设置height阈值过滤噪声峰值,distance限制相邻峰值的最小距离

内容的提问来源于stack exchange,提问作者Vadim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 08:15:01