openCVと音声認識を同時処理する

既出かもしれないが念のため。
OpenCVを終了させる方法が専らキーボード入力だったので、同時処理にあたってはOpenCVの自動終了化も行いました。
## 作業環境
* python3.6
* OpenCV
* Pyaudio
* google speech recognition：翻訳用


## コードについて
顔認識をしながら音声認識をし、翻訳してテキストファイルに出力する動作を行います。出力後は顔認識が自動で終了します。

```image_voice.py
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で音を監視して一定以上の音量を録音する](https://qiita.com/mix_dvd/items/dc53926b83a9529876f7 "Pythonで音を監視して一定以上の音量を録音する")