python - 使用 OpenCV 和 PyAudio 同步音频和视频

标签 python opencv pyaudio

我已经让 OpenCV 和 PyAudio 正常工作,但是我不确定如何将它们同步在一起。我无法从 OpenCV 获取帧率,也无法测量帧变化的调用时间。然而,对于 PyAudio,它的基础是获取特定的采样率。我将如何以相同的速率同步它们。我假设有一些标准或某种方式的编解码器可以做到这一点。 (我试过谷歌,我得到的只是关于口型同步的信息:/)。

OpenCV 帧率

from __future__ import division
import time
import math
import cv2, cv

vc = cv2.VideoCapture(0)
# get the frame
while True:

    before_read = time.time()
    rval, frame = vc.read()
    after_read  = time.time()
    if frame is not None:
        print len(frame)
        print math.ceil((1.0 / (after_read - before_read)))
        cv2.imshow("preview", frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    else:
        print "None..."
        cv2.waitKey(1)

# display the frame

while True:
    cv2.imshow("preview", frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

抓取和保存音频

from sys import byteorder
from array import array
from struct import pack

import pyaudio
import wave

THRESHOLD = 500
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 44100

def is_silent(snd_data):
    "Returns 'True' if below the 'silent' threshold"
    print "\n\n\n\n\n\n\n\n"
    print max(snd_data)
    print "\n\n\n\n\n\n\n\n"
    return max(snd_data) < THRESHOLD

def normalize(snd_data):
    "Average the volume out"
    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):
    "Trim the blank spots at the start and end"
    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

    # Trim to the left
    snd_data = _trim(snd_data)

    # Trim to the right
    snd_data.reverse()
    snd_data = _trim(snd_data)
    snd_data.reverse()
    return snd_data

def add_silence(snd_data, seconds):
    "Add silence to the start and end of 'snd_data' of length 'seconds' (float)"
    r = array('h', [0 for i in xrange(int(seconds*RATE))])
    r.extend(snd_data)
    r.extend([0 for i in xrange(int(seconds*RATE))])
    return r

def record():
    """
    Record a word or words from the microphone and 
    return the data as an array of signed shorts.

    Normalizes the audio, trims silence from the 
    start and end, and pads with 0.5 seconds of 
    blank sound to make sure VLC et al can play 
    it without getting chopped off.
    """
    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:
        # little endian, signed short
        snd_data = array('h', stream.read(1024))
        if byteorder == 'big':
            snd_data.byteswap()

        print "\n\n\n\n\n\n"
        print len(snd_data)
        print snd_data

        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 > 1:
            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):
    "Records from the microphone and outputs the resulting data to '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()

if __name__ == '__main__':
    print("please speak a word into the microphone")
    record_to_file('demo.wav')
    print("done - result written to demo.wav")

最佳答案

我认为您最好使用 GSreamer 或 ffmpeg,或者如果您使用的是 Windows,则使用 DirectShow。这些库可以处理音频和视频,并且应该有某种多路复用器来允许您正确地混合视频和音频。

但是如果你真的想用 Opencv 做这个,你应该能够使用 VideoCapture 来获取帧率,你试过使用 this 吗? ?

fps = cv.GetCaptureProperty(vc, CV_CAP_PROP_FPS)

另一种方法是将 fps 估计为帧数除以持续时间:

nFrames  = cv.GetCaptureProperty(vc, CV_CAP_PROP_FRAME_COUNT)
           cv.SetCaptureProperty(vc, CV_CAP_PROP_POS_AVI_RATIO, 1)
duration = cv.GetCaptureProperty(vc, CV_CAP_PROP_POS_MSEC)
fps = 1000 * nFrames / duration;

我不确定我是否理解您在这里尝试做的事情:

before_read = time.time()
rval, frame = vc.read()
after_read  = time.time()

在我看来,执行 after_read - before_read 只测量 OpenCV 加载下一帧所花费的时间,它不测量 fps。 OpenCV 并没有尝试播放,它只是加载帧,它会尝试以最快的速度播放,我认为没有办法配置它。我认为在显示每一帧之后放置一个 waitKey(1/fps) 将实现您正在寻找的内容。

关于python - 使用 OpenCV 和 PyAudio 同步音频和视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19493214/

相关文章:

opencv - 在 CentOS 5 上构建 OpenCV 2.0 时遇到问题?

C++/OpenCV 在图像上查找对象

python - IOError 输入溢出 : Record audio with Tkinter interface

python - 仅在一个 channel 上生成音频 pyaudio

python - 使用 PyAudio 和 NumPy 同时录制和播放音频

python - 我应该使用类作为全局变量的容器吗

python - numpy 选择每隔 n 个条目

python - Keras 输入形状 ValueError

python - 使用 cv.fromarray 将转置的 NumPy 数组转换为 Python 中的 CvMat 类型

python - 如何用不同的表达式格式化原始字符串?