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("未找到频响曲线")