67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
import cv2
|
||
import numpy as np
|
||
from matplotlib import pyplot as plt
|
||
from scipy.signal import find_peaks
|
||
|
||
cap = cv2.VideoCapture(1) # 使用摄像头0,通常更稳定
|
||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) # 降低分辨率提高处理速度
|
||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
|
||
|
||
# 预先创建图形窗口,避免重复创建
|
||
fig, ax = plt.subplots(figsize=(10, 4))
|
||
plt.ion()
|
||
ax.set_title('Saturation Channel Histogram')
|
||
ax.set_xlabel('Saturation Value')
|
||
ax.set_ylabel('Pixel Count')
|
||
ax.set_xlim(0, 255)
|
||
|
||
while True:
|
||
ret, frame = cap.read()
|
||
if not ret:
|
||
print("Failed to grab frame")
|
||
break
|
||
|
||
cv2.imshow("Camera Feed", frame)
|
||
|
||
# 直接提取饱和度通道,避免完整HSV转换
|
||
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
||
s = hsv[:, :, 1]
|
||
s = s[s > 0] # 只保留非零饱和度值,减少噪声
|
||
# 使用更高效的直方图计算
|
||
hist = cv2.calcHist([s], [0], None, [256], [0, 256])
|
||
hist = hist.flatten() # 转换为一维数组
|
||
|
||
# 峰值检测 - 找到直方图中的峰值
|
||
peaks, properties = find_peaks(hist,
|
||
# height=np.max(hist) * 0.1, # 峰值高度至少是最大值的10%
|
||
distance=5, # 峰值之间的最小距离
|
||
prominence=np.max(hist) * 0.05) # 峰值的突出度
|
||
|
||
# 清除旧数据并绘制新直方图
|
||
ax.clear()
|
||
ax.plot(hist, 'b-', linewidth=1)
|
||
|
||
# 标注峰值
|
||
if len(peaks) > 0:
|
||
ax.text(0.5, 1.05, f'Found {len(peaks)} peaks')
|
||
ax.plot(peaks, hist[peaks], 'ro', markersize=8, label=f'Peaks ({len(peaks)})')
|
||
# 在峰值处添加文字标注
|
||
for i, peak in enumerate(peaks):
|
||
ax.annotate(f'Peak {i+1}\n({peak}, {int(hist[peak])})',
|
||
xy=(peak, hist[peak]),
|
||
xytext=(peak, hist[peak] + np.max(hist) * 0.1),
|
||
ha='center', va='bottom',
|
||
bbox=dict(boxstyle='round,pad=0.3', facecolor='yellow', alpha=0.7),
|
||
arrowprops=dict(arrowstyle='->', color='red'))
|
||
|
||
|
||
plt.draw()
|
||
plt.pause(0.1) # 确保图形更新
|
||
|
||
key = cv2.waitKey(1) & 0xFF
|
||
if key == ord('q'):
|
||
break
|
||
|
||
cap.release()
|
||
cv2.destroyAllWindows()
|
||
plt.close('all') |