121 lines
3.8 KiB
Python
121 lines
3.8 KiB
Python
|
|
import cv2
|
||
|
|
import numpy as np
|
||
|
|
import matplotlib.pyplot as plt
|
||
|
|
import json
|
||
|
|
|
||
|
|
# 读取图片
|
||
|
|
img_path = r"C:\Users\yangy\.cursor\projects\h-soft-projects-luxsin-dashboard/assets/c__Users_yangy_AppData_Roaming_Cursor_User_workspaceStorage_b134a9df77916b35c1e5b1ece8dc14fe_images_Arcona-avg-0b78da44-4aaa-465b-9b2b-fba051a28742.png"
|
||
|
|
img = cv2.imread(img_path)
|
||
|
|
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
||
|
|
img_copy = img.copy()
|
||
|
|
gray = cv2.cvtColor(img_copy, cv2.COLOR_RGB2GRAY)
|
||
|
|
|
||
|
|
print(f"图片尺寸:{img_copy.shape}")
|
||
|
|
height, width = gray.shape
|
||
|
|
|
||
|
|
# 定义图表区域(排除顶部标题和底部图例)
|
||
|
|
# 根据图片估算:顶部约 5%,底部约 8%
|
||
|
|
chart_top = int(height * 0.05)
|
||
|
|
chart_bottom = int(height * 0.92)
|
||
|
|
chart_left = int(width * 0.02)
|
||
|
|
chart_right = int(width * 0.98)
|
||
|
|
|
||
|
|
# 裁剪出图表区域
|
||
|
|
chart_roi = gray[chart_top:chart_bottom, chart_left:chart_right]
|
||
|
|
|
||
|
|
# 使用阈值提取白色线条
|
||
|
|
_, thresh = cv2.threshold(chart_roi, 200, 255, cv2.THRESH_BINARY)
|
||
|
|
|
||
|
|
# 形态学操作,连接断开的线条
|
||
|
|
kernel = np.ones((3,3), np.uint8)
|
||
|
|
dilated_thresh = cv2.dilate(thresh, kernel, iterations=2)
|
||
|
|
eroded_thresh = cv2.erode(dilated_thresh, kernel, iterations=1)
|
||
|
|
|
||
|
|
# 查找轮廓
|
||
|
|
contours, _ = cv2.findContours(eroded_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||
|
|
|
||
|
|
# 找到最大的连续轮廓(应该是频响曲线)
|
||
|
|
largest_contour = None
|
||
|
|
max_area = 0
|
||
|
|
|
||
|
|
for contour in contours:
|
||
|
|
area = cv2.contourArea(contour)
|
||
|
|
if area > max_area:
|
||
|
|
max_area = area
|
||
|
|
largest_contour = contour
|
||
|
|
|
||
|
|
print(f"最大轮廓面积:{max_area}")
|
||
|
|
|
||
|
|
# 提取频响曲线上的点
|
||
|
|
frequency_points = []
|
||
|
|
|
||
|
|
if largest_contour is not None:
|
||
|
|
# 对于每个 x 坐标,找到对应的 y 坐标(取平均值)
|
||
|
|
x_coords = {}
|
||
|
|
|
||
|
|
for point in largest_contour:
|
||
|
|
x, y = point[0]
|
||
|
|
# 转换回原图坐标
|
||
|
|
global_x = int(x) + chart_left
|
||
|
|
global_y = int(y) + chart_top
|
||
|
|
|
||
|
|
if global_x not in x_coords:
|
||
|
|
x_coords[global_x] = []
|
||
|
|
x_coords[global_x].append(global_y)
|
||
|
|
|
||
|
|
# 对每个 x,计算平均 y 值
|
||
|
|
for x in sorted(x_coords.keys()):
|
||
|
|
y_values = x_coords[x]
|
||
|
|
avg_y = sum(y_values) // len(y_values)
|
||
|
|
frequency_points.append([int(x), int(avg_y)])
|
||
|
|
|
||
|
|
print(f"提取的频响曲线点数:{len(frequency_points)}")
|
||
|
|
|
||
|
|
# 创建可视化结果
|
||
|
|
result = img_copy.copy()
|
||
|
|
|
||
|
|
# 绘制检测到的点
|
||
|
|
for i, (x, y) in enumerate(frequency_points):
|
||
|
|
cv2.circle(result, (x, y), 1, (255, 0, 0), -1)
|
||
|
|
|
||
|
|
# 显示结果
|
||
|
|
plt.figure(figsize=(20, 10))
|
||
|
|
plt.imshow(result)
|
||
|
|
plt.title(f'Extracted Frequency Response Curve ({len(frequency_points)} points)')
|
||
|
|
plt.axis('off')
|
||
|
|
plt.tight_layout()
|
||
|
|
plt.show()
|
||
|
|
|
||
|
|
# 保存点到 JSON 文件
|
||
|
|
output_data = {
|
||
|
|
"frequency_points": frequency_points,
|
||
|
|
"chart_area": {
|
||
|
|
"top": int(chart_top),
|
||
|
|
"bottom": int(chart_bottom),
|
||
|
|
"left": int(chart_left),
|
||
|
|
"right": int(chart_right)
|
||
|
|
},
|
||
|
|
"image_size": {
|
||
|
|
"width": int(width),
|
||
|
|
"height": int(height)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
with open('frequency_response_points.json', 'w', encoding='utf-8') as f:
|
||
|
|
json.dump(output_data, f, ensure_ascii=False, indent=2)
|
||
|
|
|
||
|
|
print(f"\n频响点位已保存到 frequency_response_points.json")
|
||
|
|
print(f"\n前 50 个点的坐标 (x, y):")
|
||
|
|
for i, point in enumerate(frequency_points[:50]):
|
||
|
|
print(f"{i+1}: {point}")
|
||
|
|
|
||
|
|
# 也保存为 CSV 格式,方便查看
|
||
|
|
with open('frequency_response_points.csv', 'w', encoding='utf-8') as f:
|
||
|
|
f.write("index,x,y\n")
|
||
|
|
for i, point in enumerate(frequency_points):
|
||
|
|
f.write(f"{i+1},{point[0]},{point[1]}\n")
|
||
|
|
|
||
|
|
print(f"\n点位也已保存到 frequency_response_points.csv")
|
||
|
|
else:
|
||
|
|
print("未找到频响曲线")
|