Files
dashboard/convert_to_frequency_db.py
T

164 lines
5.7 KiB
Python
Raw Normal View History

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)
height, width = gray.shape
print(f"图片尺寸:{height}x{width}")
# 定义图表区域
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_height = chart_bottom - chart_top
chart_width = chart_right - chart_left
print(f"图表区域:top={chart_top}, bottom={chart_bottom}, left={chart_left}, right={chart_right}")
print(f"图表尺寸:{chart_width}x{chart_height}")
# 频率轴映射(对数刻度)
# 从图中可以看到:20Hz 在最左边,20kHz 在最右边
# 使用对数刻度映射
freq_min = 20 # Hz
freq_max = 20000 # Hz
# dB 轴映射(线性刻度)
# 从图中可以看到:顶部约 120dB,底部约 70dB
db_max = 120 # 图表顶部对应的 dB 值(y 坐标最小)
db_min = 70 # 图表底部对应的 dB 值(y 坐标最大)
# 提取白色线条
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
frequency_data = []
if largest_contour is not None:
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 值,并转换为频率和 dB 值
for x in sorted(x_coords.keys()):
y_values = x_coords[x]
avg_y = sum(y_values) // len(y_values)
# 计算在图表中的相对位置
relative_x = x - chart_left
relative_y = avg_y - chart_top
# 转换为频率(对数刻度)
# log10(f) = log10(f_min) + (relative_x / chart_width) * (log10(f_max) - log10(f_min))
log_freq = np.log10(freq_min) + (relative_x / chart_width) * (np.log10(freq_max) - np.log10(freq_min))
frequency_hz = 10 ** log_freq
# 转换为 dB 值(线性刻度,注意 y 轴是反向的)
db_value = db_max - (relative_y / chart_height) * (db_max - db_min)
frequency_data.append({
"pixel_x": int(x),
"pixel_y": int(avg_y),
"frequency_hz": round(frequency_hz, 2),
"db_value": round(db_value, 2)
})
print(f"\n提取的频响曲线点数:{len(frequency_data)}")
# 创建可视化结果
result = img_copy.copy()
for point in frequency_data:
cv2.circle(result, (point["pixel_x"], point["pixel_y"]), 1, (255, 0, 0), -1)
plt.figure(figsize=(20, 10))
plt.imshow(result)
plt.title(f'Extracted Frequency Response ({len(frequency_data)} points)')
plt.axis('off')
plt.tight_layout()
plt.show()
# 保存详细数据到 JSON
output_data = {
"metadata": {
"image_size": {"width": width, "height": height},
"chart_area": {
"top": chart_top,
"bottom": chart_bottom,
"left": chart_left,
"right": chart_right
},
"frequency_range": {"min": freq_min, "max": freq_max},
"db_range": {"min": db_min, "max": db_max}
},
"data_points": frequency_data
}
with open('frequency_response_detailed.json', 'w', encoding='utf-8') as f:
json.dump(output_data, f, ensure_ascii=False, indent=2)
print(f"\n详细数据已保存到 frequency_response_detailed.json")
# 显示前 50 个点
print(f"\n前 50 个频响点位(像素坐标 -> 实际值):")
print(f"{'序号':<6} {'X':<8} {'Y':<8} {'频率 (Hz)':<12} {'dB 值':<8}")
print("-" * 50)
for i, point in enumerate(frequency_data[:50]):
print(f"{i+1:<6} {point['pixel_x']:<8} {point['pixel_y']:<8} {point['frequency_hz']:<12.2f} {point['db_value']:<8.2f}")
# 保存为 CSV 格式
with open('frequency_response.csv', 'w', encoding='utf-8') as f:
f.write("index,pixel_x,pixel_y,frequency_hz,db_value\n")
for i, point in enumerate(frequency_data):
f.write(f"{i+1},{point['pixel_x']},{point['pixel_y']},{point['frequency_hz']},{point['db_value']}\n")
print(f"\nCSV 数据已保存到 frequency_response.csv")
# 绘制频率响应曲线图
frequencies = [p["frequency_hz"] for p in frequency_data]
db_values = [p["db_value"] for p in frequency_data]
plt.figure(figsize=(15, 8))
plt.semilogx(frequencies, db_values, linewidth=1)
plt.grid(True, which='both', linestyle='-', alpha=0.7)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude (dB)')
plt.title('Extracted Frequency Response Curve')
plt.xlim(20, 20000)
plt.ylim(70, 120)
plt.tight_layout()
plt.savefig('frequency_response_curve.png', dpi=150)
plt.show()
print(f"\n频响曲线图已保存到 frequency_response_curve.png")
else:
print("未找到频响曲线")