既出かもしれないが念のため。
OpenCVを終了させる方法が専らキーボード入力だったので、同時処理にあたってはOpenCVの自動終了化も行いました。
作業環境
- python3.6
- OpenCV
- Pyaudio
- google speech recognition:翻訳用
コードについて
顔認識をしながら音声認識をし、翻訳してテキストファイルに出力する動作を行います。出力後は顔認識が自動で終了します。
import pyaudio
import wave
import numpy as np
from datetime import datetime
import speech_recognition as sr
import multiprocessing
from multiprocessing import Process
import cv2
cascade_file = "./base_data/haarcascade_frontalface_alt2.xml"
cascade = cv2.CascadeClassifier(cascade_file)
# 音声処理部
def input_voice():
setting = 0
# 音データフォーマット
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
audio = pyaudio.PyAudio()
RATE = 44100
threshold = 0.1
print("recording......")
# 音の取込開始
audio = pyaudio.PyAudio()
stream = audio.open(format = FORMAT,
channels = CHANNELS,
rate = RATE,
input = True,
frames_per_buffer = chunk)
while True:
# 音データの取得
data = stream.read(chunk)
# ndarrayに変換
x = np.frombuffer(data, dtype="int16") / 32768.0
if x.max() > threshold:
# 2秒間の音データを取込
all = []
all.append(data)
for i in range(0, int(RATE / chunk * 4)):
data = stream.read(chunk)
all.append(data)
data = b''.join(all)
# 録音終了処理
stream.stop_stream()
stream.close()
audio.terminate()
# 録音データをファイルに保存
wav = wave.open("test.wav", 'wb')
wav.setnchannels(CHANNELS)
wav.setsampwidth(audio.get_sample_size(FORMAT))
wav.setframerate(RATE)
wav.writeframes(b''.join(all))
wav.close()
r = sr.Recognizer()
with sr.AudioFile("test.wav") as source:
audio = r.record(source)
try:
in_text = r.recognize_google(audio, language='ja-JP')
print(in_text)
except sr.UnknownValueError: # 翻訳エラー
in_text = "もう一回"
print("もう一回")
except sr.RequestError: # インターネット未接続で出るエラー
exit("実行終了:異常")
fileobj = open("./test.txt", "a", encoding = "utf-8")
fileobj.write(in_text)
fileobj.close()
break
def main():
voice = Process(target=input_voice)
voice.start()
cap = cv2.VideoCapture(0)
img_last = None
# voice()処理が完了(=False)するまで継続
while voice.is_alive() == True:
_, frame = cap.read()
frame = cv2.resize(frame, (800,400))
gray0 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray0, (9,9), 0)
img_b = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)[1]
if img_last is None:
img_last = img_b
continue
frame_diff = cv2.absdiff(img_last, img_b)
cnts = cv2.findContours(frame_diff, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[0]
face_listA = cascade.detectMultiScale(gray0, minSize = (150, 150))
for (x,y,w,h) in face_listA:
img = cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)#顔をキャプチャ
img_last = img_b
cv2.imshow("Diff Camera", frame)
# このコードを消すとなぜかフリーズする
if cv2.waitKey(1)==13: break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
同時処理を行うため、並列処理モジュールのmultiprocessingを使用していきます。threadingモジュールでも似たようなものを使えば問題なく実行できると思います。
さて、自動終了処理にはmultiprocessingのis_alive()
を使って常に子プロセス(今回はinput_voice())を監視しています。is_alive()は処理実行中にはTrueを返すため、whileで繰り返す条件を書き換えるだけで終了が自動化できました。
ここで注意なのが、if cv2.waitKey(1)==13: break
を削除してはいけない点。これを消すとカメラが正常に起動しないままOpenCVがフリーズします(何故こうなるのでしょうか……?)。
自動終了させる方法は今後も模索していきたいですね。
補足
音声認識については下記を参考に一定音量の基準を超えたら録音開始するものを使いました。
Pythonで音を監視して一定以上の音量を録音する