You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Python OpenCV将等高线像素坐标转换为日期-金额配对序列

使用Python OpenCV将等高线像素坐标转换为日期-金额配对序列

看起来你已经成功提取了图表里曲线的像素坐标,卡在了怎么把这些冰冷的像素值映射成实际的日期和金额对吧?我来一步步帮你打通这个环节,咱们用你提供的测试图来落地解决。

核心思路:找到坐标轴的参考锚点

要把像素坐标转成实际数值,关键是先获取坐标轴刻度对应的像素位置——这是计算转换因子的基础。咱们先从手动获取参考点入手(之后再聊自动优化的方法)。

第一步:确定测试图的参考锚点

先看你上传的测试图:

  • X轴是从JanJun,共6个月份,跨度5个月
  • Y轴是从$0$120k,总金额范围120000美元
  • 注意:OpenCV的坐标系是左上角为原点,Y轴向下递增,所以Y像素值越大,对应的实际金额越低,这点要特别注意!

我用画图工具查了测试图的关键像素位置(你也可以自己用画图/PS工具确认):

坐标轴元素实际值对应像素坐标
X轴起始(Jan)1月(85, 490)
X轴结束(Jun)6月(615, 490)
Y轴顶部($120k)$120000(70, 75)
Y轴底部($0)$0(70, 490)

第二步:计算转换因子

有了参考点,咱们就能算出每像素对应的实际值:

X轴(日期)转换

X轴总像素宽度:x_total_pixel = 615 - 85 = 530
X轴总时间跨度:5个月(Jan到Jun)
所以每像素对应的月份偏移量month_per_pixel = 5 / 530 ≈ 0.00943
对于任意曲线的X像素x_p,对应的月份可以用:
month_offset = (x_p - 85) * month_per_pixel
actual_month = 1 + month_offset
(比如x_p=85对应1月,x_p=615对应1+5=6月,完全匹配)

Y轴(金额)转换

Y轴总像素高度:y_total_pixel = 490 - 75 = 415
Y轴总金额跨度:120000美元
每像素对应的金额dollar_per_pixel = 120000 / 415 ≈ 289.16
因为OpenCV的Y轴向下递增,所以实际金额计算要反过来:
actual_amount = 120000 - (y_p - 75) * dollar_per_pixel
(比如y_p=75对应120000,y_p=490对应120000 - 415*289.16 ≈ 0,正确)

第三步:整合到你的现有代码

咱们把转换逻辑加到你已有的代码里,最后还能直接导出到Excel:

import cv2 as vision
import numpy as np
import pandas as pd  # 用来存数据并导出Excel

extracted_image = r"your_filepath_here.png"  # 替换成你的文件路径
    
# 加载图像
image = vision.imread(extracted_image) 

if image is None:
    print("Error: 无法加载图像,请检查文件路径。")
    exit()

# 转换为HSV并提取黑色曲线(保留你原有的逻辑)
hsv_image = vision.cvtColor(image, vision.COLOR_BGR2HSV)
lower_bound = np.array([0,0,0])
upper_bound = np.array([50,50,50])
mask = vision.inRange(hsv_image, lower_bound, upper_bound)
contours, _ = vision.findContours(mask, vision.RETR_EXTERNAL, vision.CHAIN_APPROX_SIMPLE)

black_contour = None
if contours:
    black_contour = max(contours, key=vision.contourArea)

# 定义参考锚点(根据测试图手动获取的)
# X轴:Jan(1月) -> x=85, Jun(6月)->x=615
X_REF_START = 85
X_REF_END = 615
X_MONTH_START = 1
X_MONTH_END = 6

# Y轴:$120k -> y=75, $0->y=490
Y_REF_TOP = 75
Y_REF_BOTTOM = 490
Y_AMOUNT_TOP = 120000
Y_AMOUNT_BOTTOM = 0

# 计算转换因子
x_total_pixel = X_REF_END - X_REF_START
x_month_range = X_MONTH_END - X_MONTH_START
month_per_pixel = x_month_range / x_total_pixel

y_total_pixel = Y_REF_BOTTOM - Y_REF_TOP
y_amount_range = Y_AMOUNT_TOP - Y_AMOUNT_BOTTOM
dollar_per_pixel = y_amount_range / y_total_pixel

# 处理曲线坐标并转换
date_amount_pairs = []
if black_contour is not None:
    vision.drawContours(image, [black_contour], -1, (0,0,255), 2)
    coordinates = black_contour[:,0,:] 
    print("转换后的日期-金额序列:")
    for (x,y) in coordinates:
        # 转换X为月份,处理边界情况
        if x < X_REF_START:
            actual_month = X_MONTH_START
        elif x > X_REF_END:
            actual_month = X_MONTH_END
        else:
            actual_month = X_MONTH_START + (x - X_REF_START) * month_per_pixel
        
        # 转换Y为金额,处理边界情况
        if y < Y_REF_TOP:
            actual_amount = Y_AMOUNT_TOP
        elif y > Y_REF_BOTTOM:
            actual_amount = Y_AMOUNT_BOTTOM
        else:
            # 注意Y轴方向反转
            actual_amount = Y_AMOUNT_TOP - (y - Y_REF_TOP) * dollar_per_pixel
        
        # 保留两位小数,提升可读性
        actual_month = round(actual_month, 2)
        actual_amount = round(actual_amount, 2)
        date_amount_pairs.append( (actual_month, actual_amount) )
        print(f"月份:{actual_month}, 金额:${actual_amount}")
else:
    print("未找到黑色曲线轮廓。")

# 导出数据到Excel
if date_amount_pairs:
    df = pd.DataFrame(date_amount_pairs, columns=["月份", "累计金额($)"])
    df.to_excel("累计支出计划.xlsx", index=False)
    print("已成功导出数据到Excel文件!")

# 可视化结果
vision.imshow("Cumulative Spend Plan", image)
vision.waitKey(0)
vision.destroyAllWindows()

进阶优化:自动识别坐标轴刻度

上面用的是手动获取参考点,如果你想完全自动化,可以结合OCR工具(比如pytesseract)来识别坐标轴上的刻度文字,再定位它们的像素位置:

  1. 提取坐标轴区域(比如X轴底部的文字区域、Y轴左侧的文字区域)
  2. pytesseract识别刻度的数字/文字
  3. 找到每个刻度对应的像素坐标,自动计算参考点

注意事项

  1. 参考点准确性:如果你的图表有不同的刻度,需要重新获取对应的参考像素
  2. 冗余坐标处理:曲线的坐标可能有大量冗余点,可以用cv2.approxPolyDP来简化轮廓,减少不必要的坐标点
  3. 边界情况处理:如果曲线的X/Y像素超出了参考范围,要做截断处理(比如X小于Jan的像素就按Jan算)

备注:内容来源于stack exchange,提问作者BP130

火山引擎 最新活动