随着计算机视觉和机器学习技术的飞速发展,人机交互方式正在经历一场革命。传统的以键盘、鼠标和触摸屏为主的交互方式逐渐向更加自然和直观的方式转变。在这种背景下,我们提出了一个创新的交互项目,旨在通过声音和视觉识别技术,实现对电子游戏中射击动作的控制。
项目概念
本项目的核心概念是创建一个交互系统,该系统能够识别特定的音频信号(如玩具枪射击声音)和视觉图案(如玩具枪口处的红色方形纸),并将其转换为游戏中的射击指令。这种交互方式不仅提高了游戏的沉浸感,还为用户提供了一种新颖的游戏体验。
技术实现
项目的技术实现主要依赖以下几个方面:
声音识别:使用pyaudio库录制音频,并利用librosa提取声音特征,如梅尔倒谱系数(MFCC)、色度(Chroma)等。通过训练一个机器学习模型(如多层感知器,MLP),实现对特定声音的识别。
图像识别:利用OpenCV库捕获摄像头图像,并通过颜色空间转换和形态学操作识别出红色方形纸。通过计算图像中红色区域的中心点,控制鼠标移动到相应的屏幕位置。
人机交互:结合pynput库,实现鼠标的精确控制,包括鼠标移动和点击,以模拟射击游戏中的瞄准和射击动作。
步骤1 捕获和处理音频数据
import pyaudio
import os
import wave
import librosa
import numpy as np
from sys import byteorder
from array import array
from struct import pack
# 设置声音意识阈值
THRESHOLD = 500
# 块大小(可以通过设置chunksize大小分批读入)
CHUNK_SIZE = 1024
# 一帧占两字节(声音是以二进制存储的,paInt16基本上是一个有符号的16位二进制字符串)
FORMAT = pyaudio.paInt16
# 设置缓冲区大小
RATE = 16000
# 声音间隙时间3秒
SILENCE = 30
# 声音录制功能
def is_silent(snd_data):
# 如果低于“静默”阈值,则返回“真”
return max(snd_data) < THRESHOLD
# 设置平均音量
def normalize(snd_data):
# 设置最大值,创建一个最大为16G空间的虚拟磁盘
MAXIMUM = 16384
times = float(MAXIMUM)/max(abs(i) for i in snd_data)
r = array('h')
for i in snd_data:
r.append(int(i*times))
return r
# 修剪语音起点和终点的空白点
def trim(snd_data):
def _trim(snd_data):
snd_started = False
r = array('h')
for i in snd_data:
if not snd_started and abs(i)>THRESHOLD:
snd_started = True
r.append(i)
elif snd_started:
r.append(i)
return r
# 向左修剪
snd_data = _trim(snd_data)
# 向右修剪
snd_data.reverse()
snd_data = _trim(snd_data)
snd_data.reverse()
return snd_data
# 将静默添加到长度为“秒”(浮点)的“snd_data”的开始和结束
def add_silence(snd_data, seconds):
r = array('h', [0 for i in range(int(seconds*RATE))])
r.extend(snd_data)
r.extend([0 for i in range(int(seconds*RATE))])
return r
def record():
"""
从麦克风录制一个或多个单词,然后
将数据作为带符号的短字符数组返回。
使音频正常化,从开始和结束,并用0.5秒空白声音,
以确保VLC等可以播放它不会被砍掉。
"""
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT, channels=1, rate=RATE,
input=True, output=True,
frames_per_buffer=CHUNK_SIZE)
num_silent = 0
snd_started = False
r = array('h')
while 1:
snd_data = array('h', stream.read(CHUNK_SIZE))
if byteorder == 'big':
snd_data.byteswap()
r.extend(snd_data)
silent = is_silent(snd_data)
if silent and snd_started:
num_silent += 1
elif not silent and not snd_started:
snd_started = True
if snd_started and num_silent > SILENCE:
break
sample_width = p.get_sample_size(FORMAT)
stream.stop_stream()
stream.close()
p.terminate()
r = normalize(r)
r = trim(r)
r = add_silence(r, 0.5)
return sample_width, r
def record_to_file(path):
# 从麦克风记录并将结果数据输出到“路径”
sample_width, data = record()
data = pack('<' + ('h'*len(data)), *data)
wf = wave.open(path, 'wb')
wf.setnchannels(1)
wf.setsampwidth(sample_width)
wf.setframerate(RATE)
wf.writeframes(data)
wf.close()
i=30
if __name__ == "__main__":
while(1):
i=i+1
if(i%2==0):
print("请开始采集“射击”声音:")
file = "data/shoot-02-"+str(i)+".wav"
else:
print("请开始采集“拉枪机”声音:")
file = "data/loading-01-"+str(i)+".wav"
# 记录声音文件
record_to_file(file)
这个程序是一个声音录制工具,主要用于捕获和处理音频数据,以便进行进一步的声音分析或机器学习模型训练。以下是对程序的简要说明:
程序名称:声音录制与处理工具
主要功能:
声音录制:使用pyaudio库从麦克风实时录制声音。声音检测:通过设置声音意识阈值,程序能够识别并忽略静音部分。数据标准化:将录制的声音数据标准化,确保音量的一致性。声音修剪:去除录制声音的开始和结束的静音部分。添加静音:在录制的声音数据的开始和结束添加指定长度的静音,以避免播放时的截断问题。音频保存:将处理后的声音数据保存为WAV格式的音频文件。核心参数:
THRESHOLD:声音意识阈值,用于判断声音是否为静音。CHUNK_SIZE:每次从麦克风读取的音频数据块大小。FORMAT:音频数据的格式,这里使用pyaudio.paInt16表示16位PCM格式。RATE:音频采样率,设置为16000Hz。SILENCE:声音间隙时间,用于确定录制的结束点。程序流程:
初始化音频录制参数和配置。使用循环持续监听麦克风输入,并录制声音。对录制的声音数据进行检测,如果检测到声音强度超过设定阈值,则开始录制。录制完成后,对声音数据进行标准化处理,修剪静音部分,并在数据两端添加静音。将处理后的音频数据保存为WAV文件。使用场景:
该程序适用于需要录制特定声音样本并进行声音特征提取的场景,如声音识别系统的训练阶段。可以用于收集特定事件(如玩具枪射击声)的声音数据,为声音分类或事件检测算法提供训练数据。注意事项:
确保麦克风设备正常工作,以获得最佳的录音效果。调整THRESHOLD和SILENCE参数以适应不同的录音环境和声音特性。步骤2 训练模型
import soundfile # 读取音频文件
import numpy as np
import librosa # 提取语音特征
import glob #从文件系统中搜索符合特定规则的文件路径
import os
import pickle # 在训练后保存模型
from sklearn.model_selection import train_test_split # 用于拆分训练和测试
from sklearn.neural_network import MLPClassifier # 多层感知器模型
from sklearn.metrics import accuracy_score # 评估分类模型性能
def extract_feature(file_name, **kwargs):
"""
MFCC:梅尔倒谱系数
Chroma:色度
MEL Spectrogram Frequency:梅尔频谱图
Contrast:对比度
Tonnetz:调性网络
"""
mfcc = kwargs.get("mfcc")
chroma = kwargs.get("chroma")
mel = kwargs.get("mel")
contrast = kwargs.get("contrast")
tonnetz = kwargs.get("tonnetz")
with soundfile.SoundFile(file_name) as sound_file:
X = sound_file.read(dtype="float32")
sample_rate = sound_file.samplerate
if chroma or contrast:
stft = np.abs(librosa.stft(X))
result = np.array([])
if mfcc:
mfccs = np.mean(librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40).T, axis=0)
result = np.hstack((result, mfccs))
if chroma:
chroma = np.mean(librosa.feature.chroma_stft(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, chroma))
if mel:
mel = np.mean(librosa.feature.melspectrogram(y=X, sr=sample_rate).T,axis=0)
result = np.hstack((result, mel))
if contrast:
contrast = np.mean(librosa.feature.spectral_contrast(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, contrast))
if tonnetz:
tonnetz = np.mean(librosa.feature.tonnetz(y=librosa.effects.harmonic(X), sr=sample_rate).T,axis=0)
result = np.hstack((result, tonnetz))
return result
# 编写数据集上的所有声音类型
int2emotion = {
"01": "loading",
"02": "shoot",
"03": "background"
}
# 这里案例选择以下声音类型
AVAILABLE_EMOTIONS = {
"loading",
"shoot",
"background"
}
def load_data(test_size=0.2):
X, y = [], []
# 这里引入了数据集,需要注意数据集地址
for file in glob.glob("data/*.wav"):
# 获取音频文件的名称
basename = os.path.basename(file)
# 获得情感标签
emotion = int2emotion[basename.split("-")[1]]
print(emotion)
# 我们只允许设置AVAILABLE_EMOTIONS(可用情绪)
if emotion not in AVAILABLE_EMOTIONS:
continue
# 提取语音特征
features = extract_feature(file, mfcc=True, chroma=True, mel=True)
# 添加到数据
X.append(features)
y.append(emotion)
# 将数据拆分为训练和测试数据并返回
return train_test_split(np.array(X), y, test_size=test_size, random_state=7)
# 加载数据集,75%用于训练,25%用于测试
X_train, X_test, y_train, y_test = load_data(test_size=0.25)
#记录模型训练信息
# 打印一些详细信息
# 训练数据中的样本数
print("[+] Number of training samples:", X_train.shape[0])
# 测试数据中的样本数
print("[+] Number of testing samples:", X_test.shape[0])
#使用的功能数量
#这是提取的特征向量
#使用extract_features()函数
print("[+] Number of features:", X_train.shape[1])
#设置模型超参数
#模型结构是一个全连接神经网络,其中包含 300 个单元隐层的个数,批量大小为 256、500 次迭代,以及自适应学习率(这里模型参数不是最佳超参数,可以根据需求调整)
# 设置模型超参数
model_params = {
'alpha': 0.01,
'batch_size': 256,
'epsilon': 1e-08,
'hidden_layer_sizes': (300,),
'learning_rate': 'adaptive',
'max_iter': 500,
}
# 假设 X_train 包含训练样本,y_train 包含对应的标签
n_samples = X_train.shape[0] # 获取训练样本的数量
# 检查并调整 batch_size
if model_params['batch_size'] > n_samples:
print(f"Warning: batch_size is larger than the number of training samples. "
f"Clipping batch_size to {n_samples}.")
model_params['batch_size'] = n_samples
# 重新初始化模型
model = MLPClassifier(**model_params)
#使用加载的数据集来训练模型
# 训练模型
print("[*] Training the model...")
model.fit(X_train, y_train)
#计算模型准确度并打印,以此来衡量模型性能
# 预测25%的数据来衡量模型性能
y_pred = model.predict(X_test)
# 计算模型精度
accuracy = accuracy_score(y_true=y_test, y_pred=y_pred)
# 打印输出
print("Accuracy: {:.2f}%".format(accuracy*100))
# 保存模型
if not os.path.isdir("result"):
os.mkdir("result")
# 设置模型名称,并保存到指定文件夹
pickle.dump(model, open("result/mlp_classifier.model", "wb"))
这个程序是一个声音识别系统,用于训练和评估一个基于多层感知器(MLP)的声音分类模型。它通过分析音频文件中的声音特征来识别不同类型的声音,如射击声或背景声音等。以下是对程序的简要说明:
程序名称:声音识别系统
主要功能:
特征提取:使用librosa库从音频文件中提取多种声音特征,包括梅尔倒谱系数(MFCC)、色度(Chroma)、梅尔频谱图(Mel Spectrogram)、对比度(Contrast)和调性网络(Tonnetz)。
数据加载与预处理:通过glob模块搜索特定格式的音频文件,并使用soundfile读取音频数据。
声音分类:根据音频文件的命名规则,将声音分为不同的类别,如“loading”、“shoot”和“background”。
模型训练:使用sklearn的MLPClassifier来训练一个多层感知器模型,该模型能够根据声音特征对声音进行分类。
性能评估:使用准确度(accuracy score)来评估模型的性能。
模型保存:通过pickle模块将训练好的模型保存为文件,以便后续使用或部署。
核心参数:
model_params:模型的超参数设置,包括正则化系数alpha、批量大小batch_size、学习率learning_rate、隐藏层大小hidden_layer_sizes等。程序流程:
定义特征提取函数extract_feature,根据提供的参数提取音频特征。定义数据加载函数load_data,读取音频文件并根据文件名分配声音类别标签。对数据集进行拆分,形成训练集和测试集。打印训练和测试样本的数量以及特征的数量。根据设置的超参数初始化MLP模型。训练模型并打印训练进度。使用测试集评估模型的准确度。保存训练好的模型到文件系统。使用场景:
适用于需要对声音进行分类的应用,如智能语音助手、声音事件检测系统或游戏声音识别等。步骤3 音频录制与声音识别系统
#使用 pyaudio 来录制音频,使用 librosa 提取特征,使用 numpy 进行数值计算,最后使用 pickle 保存训练好的模型。
import pyaudio #一个用于音频输入和输出的跨平台 Python 库。它可以用来从麦克风录制音频或者播放音频。
import os #一个 Python 标准库模块,提供了与操作系统交互的功能,如文件路径操作等。
import wave #一个用于处理 WAV 音频格式的 Python 标准库模块。
import pickle #一个 Python 标准库模块,用于序列化和反序列化 Python 对象结构,通常用于保存和加载机器学习模型。
import numpy as np #一个强大的科学计算库,用于处理大型多维数组和矩阵,以及执行高级数学函数。
import soundfile #一个用于读写声音文件的库,支持多种音频格式。
import librosa #一个音乐和音频分析的 Python 库,提供了一系列用于音乐信息检索、特征提取和信号处理的函数。
from sys import byteorder #从 sys 模块导入 byteorder 属性,用于确定系统的字节序(大端或小端)。
from array import array #从 array 模块导入 array 类,用于创建和操作固定类型(如 'h' 表示有符号短整数)的数组。
from struct import pack #从 struct 模块导入 pack 函数,用于将 Python 值打包成 C 风格的二进制数据。
# 设置音频处理的阈值和参数
THRESHOLD = 500
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 16000
SILENCE = 30
# 判断音频数据是否为静音
def is_silent(snd_data):
# 如果低于默认阈值,则返回True
return max(snd_data) < THRESHOLD
# 标准化音频数据的音量
def normalize(snd_data):
# 设置平均输出音量
MAXIMUM = 16384 #设置最大振幅,MAXIMUM 设置为 16384,这是 16 位音频样本可能的最大正值(即 2**15 - 1,因为 16 位音频样本使用 -32768 到 32767 的范围)。
#计算一个缩放因子 times。首先通过列表推导式 abs(i) for i in snd_data 计算 snd_data 中所有样本的绝对值,然后使用 max 函数找到这些绝对值中的最大值。接着,将 MAXIMUM 除以这个最大值,得到一个缩放因子,用于将所有样本值缩放到不超过 MAXIMUM 的范围内。
times = float(MAXIMUM)/max(abs(i) for i in snd_data)
r = array('h')#创建一个新的数组 r,使用 'h' 类型码,表示有符号短整数(16位)。
#遍历原始音频样本数据 snd_data,将每个样本值乘以之前计算的缩放因子 times,然后转换为整数(因为音频样本是整数类型),并将结果追加到数组 r 中。
for i in snd_data:
r.append(int(i*times))
return r
# 修剪音频数据的开始和结束部分
def trim(snd_data):
# 修剪起点和终点的空白点
def _trim(snd_data):
snd_started = False
r = array('h')
for i in snd_data:
if not snd_started and abs(i)>THRESHOLD:
snd_started = True
r.append(i)
elif snd_started:
r.append(i)
return r
# 向左修剪
snd_data = _trim(snd_data)
# 向右修剪
snd_data.reverse()
snd_data = _trim(snd_data)
snd_data.reverse()
return snd_data
# 在音频数据的开始和结束添加指定长度的静音
def add_silence(snd_data, seconds):
# 在长度为“秒”(float)的“snd_data”的开始和结束处添加静音功能
r = array('h', [0 for i in range(int(seconds*RATE))])
r.extend(snd_data)
r.extend([0 for i in range(int(seconds*RATE))])
return r
# 从麦克风录制音频并返回处理后的音频数据
def record():
"""
从麦克风中录制一个或多个单词,并将数据作为数组返回。
(这里需要标准化音频,从开始和结束处消除静音,
并用0.5秒的空白声音填充,以确保VLC等可以在不被切断的情况下播放)
"""
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT, channels=1, rate=RATE,
input=True, output=True,
frames_per_buffer=CHUNK_SIZE)
num_silent = 0
snd_started = False
r = array('h')
while 1:
# 在检测到音频后开始,开始读取音频从一个流采样到一个数组,然后它进入一个if语句
snd_data = array('h', stream.read(CHUNK_SIZE))#读取音频数据,从麦克风录制 CHUNK_SIZE 大小的音频数据,并将其存储在 snd_data 数组中。这里 'h' 表示数据类型为 signed short (16位整数)。
if byteorder == 'big':#如果系统的字节序是大端序('big'),则将 snd_data 中的数据字节序进行交换,以确保与 pyaudio 所需的字节序一致。
snd_data.byteswap()
r.extend(snd_data)#添加到结果数组
#使用 is_silent 函数判断 snd_data 是否为静音,即数据的最大值是否小于设定的阈值 THRESHOLD。
silent = is_silent(snd_data)
#如果已经开始录制(snd_started 为 True)并且当前数据为静音,则增加静音计数 num_silent。如果尚未开始录制,且当前数据不是静音,则设置 snd_started 为 True。
if silent and snd_started:
num_silent += 1
elif not silent and not snd_started:
snd_started = True
#如果已经开始录制,并且连续静音的帧数超过 SILENCE 指定的阈值,则跳出循环,停止录制。
if snd_started and num_silent > SILENCE:
break
sample_width = p.get_sample_size(FORMAT)#获取样本宽度
#停止音频流并关闭与 pyaudio 的连接
stream.stop_stream()
stream.close()
#终止 pyaudio 实例
p.terminate()
#对录制的音频数据进行标准化、修剪静音部分,并在开始和结束添加0.5秒的静音。
r = normalize(r)
r = trim(r)
r = add_silence(r, 0.5)
return sample_width, r
def record_to_file(path):
# 从麦克风录制并将结果数据输出到“路径”
#调用 record 函数来录制音频,该函数返回两个值:样本宽度(每个样本的字节数)和音频样本数据数组。
sample_width, data = record()
#使用 struct.pack 函数将音频样本数据数组打包成字节串。格式化字符串 '<' + ('h'*len(data)) 指定了数据的字节序(小端)和数据类型('h' 表示有符号短整数)。*data 是解包后的音频样本数据,将它们作为参数传递给 pack 函数。
data = pack('<' + ('h'*len(data)), *data)
wf = wave.open(path, 'wb')#使用 wave 模块打开一个路径为 path 的文件用于写入('wb' 表示写入二进制模式)。
wf.setnchannels(1)# 设置声道数为单声道
wf.setsampwidth(sample_width) # 设置样本宽度
wf.setframerate(RATE)# 设置采样率
wf.writeframes(data)#将打包后的音频数据写入 WAV 文件。writeframes 方法接受字节串形式的音频数据。
wf.close()#完成音频数据的写入后,关闭 WAV 文件以确保所有数据都已正确保存到磁盘上。
#extract_feature 函数用于从音频文件中提取特征,这些特征随后被用于模型的预测。
def extract_feature(file_name, **kwargs):
"""
MFCC:梅尔倒谱系数
Chroma:色度
MEL Spectrogram Frequency:梅尔频谱图
Contrast:对比度
Tonnetz:调性网络
"""
mfcc = kwargs.get("mfcc")
chroma = kwargs.get("chroma")
mel = kwargs.get("mel")
contrast = kwargs.get("contrast")
tonnetz = kwargs.get("tonnetz")
with soundfile.SoundFile(file_name) as sound_file:
X = sound_file.read(dtype="float32")
sample_rate = sound_file.samplerate
if chroma or contrast:
stft = np.abs(librosa.stft(X))
result = np.array([])
if mfcc:
mfccs = np.mean(librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40).T, axis=0)
result = np.hstack((result, mfccs))
if chroma:
chroma = np.mean(librosa.feature.chroma_stft(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, chroma))
if mel:
mel = np.mean(librosa.feature.melspectrogram(y=X, sr=sample_rate).T,axis=0)
result = np.hstack((result, mel))
if contrast:
contrast = np.mean(librosa.feature.spectral_contrast(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, contrast))
if tonnetz:
tonnetz = np.mean(librosa.feature.tonnetz(y=librosa.effects.harmonic(X), sr=sample_rate).T,axis=0)
result = np.hstack((result, tonnetz))
return result
if __name__ == "__main__":
# 加载训练好保存的模型
model = pickle.load(open("result/mlp_classifier.model", "rb"))
while(1):
print("开始采集声音")
filename = "11.wav"
# 记录文件(开始说话)
record_to_file(filename)
# 提取特征并重新构建reshape
features = extract_feature(filename, mfcc=True, chroma=True, mel=True).reshape(1, -1)
# 预测
print("开始预测")
result = model.predict(features)[0]
# 显示结果
print("预测结果:", result)
这个程序是一个完整的音频处理和声音识别流程,包括音频录制、特征提取、声音事件预测以及结果展示。以下是对程序的简要说明:
程序名称:音频录制与声音识别系统
主要功能:
音频录制:使用pyaudio库从麦克风录制音频,并将录制的原始音频数据存储为WAV文件。
音频处理:
静音判断:通过is_silent函数检测音频数据是否为静音。音量标准化:使用normalize函数调整音频数据的音量至最大振幅。音频修剪:通过trim函数去除音频开始和结束的静音部分。添加静音:使用add_silence函数在音频的开始和结束添加静音,以改善播放体验。特征提取:使用librosa库从音频文件中提取多种声音特征,包括梅尔倒谱系数(MFCC)、色度(Chroma)、梅尔频谱图(Mel Spectrogram)、对比度(Contrast)和调性网络(Tonnetz)。
声音事件预测:加载预先训练好的机器学习模型,使用提取的声音特征进行预测,以识别声音事件。
结果展示:打印预测的事件结果。
核心参数:
THRESHOLD:判断音频数据是否为静音的阈值。CHUNK_SIZE:音频数据块的大小。FORMAT:音频数据的格式。RATE:音频采样率。SILENCE:连续静音帧数的阈值,用于结束录制。程序流程:
初始化音频处理参数。定义音频处理相关的函数,包括静音判断、音量标准化、音频修剪和添加静音。定义从麦克风录制音频并保存为WAV文件的函数。定义从音频文件中提取特征的函数。加载训练好的模型,并在主循环中:录制音频。提取录制音频的特征。使用模型进行预测。打印预测结果。使用场景:
适用于需要实时声音识别和响应的场景,如智能家居控制、会议记录摘要、声音事件监测等。步骤4 基于OpenCV的红色物体追踪与鼠标控制
import cv2
import numpy as np
from pynput.mouse import Controller
# 初始化鼠标控制器
mouse = Controller()
# 摄像头初始化
cap = cv2.VideoCapture(0)
# 红色阈值(HSV)
lower_red = np.array([0, 120, 65])
upper_red = np.array([5, 255, 255])
while True:
ret, frame = cap.read()
if not ret:
break
# 转换到HSV颜色空间
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 红色掩膜
mask = cv2.inRange(hsv, lower_red, upper_red)
# 形态学操作
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((5, 5), np.uint8))
# 寻找轮廓
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 找到最大的红色块
if contours:
largest_contour = max(contours, key=cv2.contourArea)
M = cv2.moments(largest_contour)
if M["m00"] != 0:
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
# 将摄像头坐标映射到屏幕坐标
screen_x = int(cx * (1920 / 640))
screen_y = int(cy * (1080 / 480))
# 移动鼠标到红色块的中心
mouse.position = (screen_x, screen_y)
# 显示结果
cv2.imshow('frame', frame)
cv2.imshow('mask', mask)
# 按'q'退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
这个程序是一个基于OpenCV库的简单计算机视觉应用,用于通过摄像头实时检测红色物体,并使用鼠标控制器根据物体位置移动鼠标光标。以下是对程序的简要说明:
程序名称:基于OpenCV的红色物体追踪与鼠标控制
主要功能:
摄像头初始化:使用cv2.VideoCapture从摄像头捕获视频流。颜色空间转换:将捕获的图像从BGR颜色空间转换到HSV颜色空间,以便于颜色识别。红色阈值设置:定义红色在HSV颜色空间中的下界和上界。红色掩膜:根据设置的阈值,创建一个掩膜来隔离红色区域。形态学操作:使用开运算(cv2.MORPH_OPEN)来去除红色区域中的噪声。轮廓检测:寻找掩膜中的轮廓,以识别红色物体的形状。物体定位:计算最大的红色轮廓块的中心点,作为物体的位置。鼠标控制:根据物体位置移动鼠标光标到相应位置。核心参数:
lower_red 和 upper_red:HSV颜色空间中红色物体的下界和上界。程序流程:
初始化鼠标控制器和摄像头。进入循环,不断读取摄像头捕获的帧。对每一帧进行颜色空间转换和红色掩膜操作。执行形态学操作以净化红色掩膜。检测掩膜中的轮廓,并找到最大的红色轮廓块。计算红色物体中心点,并将其映射到屏幕坐标。移动鼠标到计算出的坐标位置。显示原始帧和掩膜,以便用户观察。如果用户按下'q'键,则退出循环。使用场景:
适用于需要通过颜色识别来控制鼠标位置的场景,例如在某些游戏或演示中。注意事项:
确保摄像头设备正常工作,并且环境光线适合红色物体的识别。调整HSV阈值以适应不同的红色物体和光照条件。程序中的鼠标控制依赖于屏幕分辨率,确保使用的分辨率与程序中的映射比例相匹配。步骤5 音频视频交互控制系统(完整版)
import pyaudio
import wave
import pickle
import numpy as np
import cv2
from pynput.mouse import Controller,Button
from pynput.keyboard import Listener
from array import array
import os
import soundfile
import librosa
from sys import byteorder
from struct import pack
# 初始化鼠标控制器
mouse = Controller()
# 加载模型
model = pickle.load(open("result/mlp_classifier.model", "rb"))
# 视频处理参数
lower_red = np.array([0, 120, 65])
upper_red = np.array([5, 255, 255])
# 设置音频处理的阈值和参数
THRESHOLD = 50
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 16000
SILENCE = 30
# 判断音频数据是否为静音
def is_silent(snd_data):
# 如果低于默认阈值,则返回True
print(max(snd_data))
return max(snd_data) < THRESHOLD
# 标准化音频数据的音量
def normalize(snd_data):
# 设置平均输出音量
MAXIMUM = 16384 #设置最大振幅,MAXIMUM 设置为 16384,这是 16 位音频样本可能的最大正值(即 2**15 - 1,因为 16 位音频样本使用 -32768 到 32767 的范围)。
#计算一个缩放因子 times。首先通过列表推导式 abs(i) for i in snd_data 计算 snd_data 中所有样本的绝对值,然后使用 max 函数找到这些绝对值中的最大值。接着,将 MAXIMUM 除以这个最大值,得到一个缩放因子,用于将所有样本值缩放到不超过 MAXIMUM 的范围内。
times = float(MAXIMUM)/max(abs(i) for i in snd_data)
r = array('h')#创建一个新的数组 r,使用 'h' 类型码,表示有符号短整数(16位)。
#遍历原始音频样本数据 snd_data,将每个样本值乘以之前计算的缩放因子 times,然后转换为整数(因为音频样本是整数类型),并将结果追加到数组 r 中。
for i in snd_data:
r.append(int(i*times))
return r
# 修剪音频数据的开始和结束部分
def trim(snd_data):
# 修剪起点和终点的空白点
def _trim(snd_data):
snd_started = False
r = array('h')
for i in snd_data:
if not snd_started and abs(i)>THRESHOLD:
snd_started = True
r.append(i)
elif snd_started:
r.append(i)
return r
# 向左修剪
snd_data = _trim(snd_data)
# 向右修剪
snd_data.reverse()
snd_data = _trim(snd_data)
snd_data.reverse()
return snd_data
# 在音频数据的开始和结束添加指定长度的静音
def add_silence(snd_data, seconds):
# 在长度为“秒”(float)的“snd_data”的开始和结束处添加静音功能
r = array('h', [0 for i in range(int(seconds*RATE))])
r.extend(snd_data)
r.extend([0 for i in range(int(seconds*RATE))])
return r
# 从麦克风录制音频并返回处理后的音频数据
def record():
"""
从麦克风中录制一个或多个单词,并将数据作为数组返回。
(这里需要标准化音频,从开始和结束处消除静音,
并用0.5秒的空白声音填充,以确保VLC等可以在不被切断的情况下播放)
"""
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT, channels=1, rate=RATE,
input=True, output=True,
frames_per_buffer=CHUNK_SIZE)
num_silent = 0
snd_started = False
r = array('h')
snd_data = array('h', stream.read(CHUNK_SIZE))#读取音频数据,从麦克风录制 CHUNK_SIZE 大小的音频数据,并将其存储在 snd_data 数组中。这里 'h' 表示数据类型为 signed short (16位整数)。
if byteorder == 'big':#如果系统的字节序是大端序('big'),则将 snd_data 中的数据字节序进行交换,以确保与 pyaudio 所需的字节序一致。
snd_data.byteswap()
r.extend(snd_data)#添加到结果数组
#使用 is_silent 函数判断 snd_data 是否为静音,即数据的最大值是否小于设定的阈值 THRESHOLD。
start = is_silent(snd_data)
print(start)
while not start:
snd_started = True
# 在检测到音频后开始,开始读取音频从一个流采样到一个数组,然后它进入一个if语句
snd_data = array('h', stream.read(CHUNK_SIZE))#读取音频数据,从麦克风录制 CHUNK_SIZE 大小的音频数据,并将其存储在 snd_data 数组中。这里 'h' 表示数据类型为 signed short (16位整数)。
if byteorder == 'big':#如果系统的字节序是大端序('big'),则将 snd_data 中的数据字节序进行交换,以确保与 pyaudio 所需的字节序一致。
snd_data.byteswap()
r.extend(snd_data)#添加到结果数组
#使用 is_silent 函数判断 snd_data 是否为静音,即数据的最大值是否小于设定的阈值 THRESHOLD。
silent = is_silent(snd_data)
#如果已经开始录制(snd_started 为 True)并且当前数据为静音,则增加静音计数 num_silent。如果尚未开始录制,且当前数据不是静音,则设置 snd_started 为 True。
if silent and snd_started:
num_silent += 1
elif not silent and not snd_started:
snd_started = True
#如果已经开始录制,并且连续静音的帧数超过 SILENCE 指定的阈值,则跳出循环,停止录制。
if snd_started and num_silent > SILENCE:
break
if start:
stream.stop_stream()
stream.close()
return None,None
else:
sample_width = p.get_sample_size(FORMAT)#获取样本宽度
#停止音频流并关闭与 pyaudio 的连接
stream.stop_stream()
stream.close()
#终止 pyaudio 实例
p.terminate()
#对录制的音频数据进行标准化、修剪静音部分,并在开始和结束添加0.5秒的静音。
r = normalize(r)
r = trim(r)
r = add_silence(r, 0.5)
return sample_width, r
def record_to_file(path):
# 从麦克风录制并将结果数据输出到“路径”
#调用 record 函数来录制音频,该函数返回两个值:样本宽度(每个样本的字节数)和音频样本数据数组。
sample_width, data = record()
print(sample_width)
if sample_width is not None:
#使用 struct.pack 函数将音频样本数据数组打包成字节串。格式化字符串 '<' + ('h'*len(data)) 指定了数据的字节序(小端)和数据类型('h' 表示有符号短整数)。*data 是解包后的音频样本数据,将它们作为参数传递给 pack 函数。
data = pack('<' + ('h'*len(data)), *data)
wf = wave.open(path, 'wb')#使用 wave 模块打开一个路径为 path 的文件用于写入('wb' 表示写入二进制模式)。
wf.setnchannels(1)# 设置声道数为单声道
wf.setsampwidth(sample_width) # 设置样本宽度
wf.setframerate(RATE)# 设置采样率
wf.writeframes(data)#将打包后的音频数据写入 WAV 文件。writeframes 方法接受字节串形式的音频数据。
wf.close()#完成音频数据的写入后,关闭 WAV 文件以确保所有数据都已正确保存到磁盘上。
#extract_feature 函数用于从音频文件中提取特征,这些特征随后被用于模型的预测。
return True
else:
return False
def extract_feature(file_name, **kwargs):
"""
MFCC:梅尔倒谱系数
Chroma:色度
MEL Spectrogram Frequency:梅尔频谱图
Contrast:对比度
Tonnetz:调性网络
"""
mfcc = kwargs.get("mfcc")
chroma = kwargs.get("chroma")
mel = kwargs.get("mel")
contrast = kwargs.get("contrast")
tonnetz = kwargs.get("tonnetz")
with soundfile.SoundFile(file_name) as sound_file:
X = sound_file.read(dtype="float32")
sample_rate = sound_file.samplerate
if chroma or contrast:
stft = np.abs(librosa.stft(X))
result = np.array([])
if mfcc:
mfccs = np.mean(librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40).T, axis=0)
result = np.hstack((result, mfccs))
if chroma:
chroma = np.mean(librosa.feature.chroma_stft(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, chroma))
if mel:
mel = np.mean(librosa.feature.melspectrogram(y=X, sr=sample_rate).T,axis=0)
result = np.hstack((result, mel))
if contrast:
contrast = np.mean(librosa.feature.spectral_contrast(S=stft, sr=sample_rate).T,axis=0)
result = np.hstack((result, contrast))
if tonnetz:
tonnetz = np.mean(librosa.feature.tonnetz(y=librosa.effects.harmonic(X), sr=sample_rate).T,axis=0)
result = np.hstack((result, tonnetz))
return result
# 音频特征提取参数
feature_params = {
"mfcc": True,
"chroma": True,
"mel": True
}
# 音频录制和特征提取函数
def audio_process():
filename = "temp_audio.wav"
bs=record_to_file(filename)
print(bs)
if bs:
features = extract_feature(filename, **feature_params).reshape(1, -1)
result = model.predict(features)[0]
return result
else:
return None
# 视频处理函数
def video_process():
ret, frame = cap.read()
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_red, upper_red)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((5, 5), np.uint8))
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if contours:
largest_contour = max(contours, key=cv2.contourArea)
M = cv2.moments(largest_contour)
if M["m00"] != 0:
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
screen_x = int(cx * (1920 / 640))
screen_y = int(cy * (1080 / 480))
mouse.position = (screen_x, screen_y)
cv2.imshow('frame', frame)
cv2.waitKey(1)
# 主循环
try:
print("开始采集声音和图像")
cap = cv2.VideoCapture(0)
while True:
audio_result = audio_process()
print(audio_result)
if audio_result == "shoot":
mouse.click(Button.left, 1) # 鼠标点击
video_process() # 视频处理,控制鼠标移动
if cv2.waitKey(1) & 0xFF == ord('q'):
break
finally:
cap.release()
cv2.destroyAllWindows()
这个程序是一个集成了音频和视频处理的交互系统,旨在通过声音和图像识别来控制鼠标操作。以下是对程序的简要说明:
_深蓝_2024.06.29
云天老师,分享下源文件行不?