Versuchen Sie, mit Python (1) eine Erfassungssoftware zu erstellen, die so genau wie möglich ist. https://qiita.com/akaiteto/items/b2119260d732bb189c87
Grob gesagt das Ziel Machen Sie Software wie Amarekoko mit Python, Lassen Sie uns mit hoher Anpassung aufnehmen, Der Zweck ist.
Letztes Mal, wie man Bilder mit Python aufnimmt, Wir haben die grundlegende Verwendung jedes Teils der System-Tonerfassungsmethode untersucht.
Dieses Mal werden wir erwägen, die Genauigkeit der Bildschirmaufnahme zu verbessern.
Beim letzten Mal habe ich gehört, dass der Bildschirmaufnahmevorgang langsam ist. Die Gesamtverarbeitungsgeschwindigkeit beträgt nur 18 fps. Wenn dies ein Video ist, scheint es ein wenig steif zu sein. Ich persönlich möchte mehr als 28.
Als ganzer Prozess
1.Bilderfassung
2.Konvertieren Sie das Bildfarbformat in RGB
Wenn ich über diese beiden Schritte nachdenke In der vorherigen Studie haben wir einen Schritt verbessert.
Insbesondere wenn die Verarbeitung mit einer Auflösung von 1920 x 1080 gemessen wird, Zuvor war (ImageGrab.grab) 26fps, Mit der Einführung von win32 wurde es zu fps42.
Als nächstes werden wir erwägen, den Konvertierungsprozess in 2 zu verbessern. Vorher denke ich darüber nach, ob es überhaupt notwendig ist, Geschwindigkeit zu erreichen.
Wenn Sie keine Echtzeit benötigen Behalten Sie die Daten als Array oder JPG-Datei bei. Ich denke, dass es kein Problem gibt, auch wenn Sie den Konvertierungsprozess später durchführen.
Hier wage ich es jedoch, eine Echtzeitleistung anzustreben. Erwägen Sie eine lange Aufzeichnung, wenn Sie die Daten ohne nachzudenken behalten Es scheint Druck auf das Gedächtnis auszuüben, und es kann Vorteile geben.
Lassen Sie uns also die Verarbeitungsgeschwindigkeit des Konvertierungsprozesses untersuchen.
Das zuletzt verwendete ImageGrab.grab von Pillow gibt Bilder im BGR-Format aus. Beim Speichern eines Videos muss es sich also um ein RGB-Bild handeln Eine OpenCV-Konvertierung war unbedingt erforderlich, was die Verarbeitungsgeschwindigkeit verlangsamte.
Und dieses Mal. Das von win32 api ausgegebene Bild ist RGBA. Die Konvertierung in RGB ist erforderlich, um als Film gespeichert zu werden.
Das letzte Mal, als ich versucht habe, die Aufnahme zu beschleunigen, Vergleichen wir nun die Geschwindigkeit der Erfassung und Konvertierung.
#Traditionelles ImageGrab.grab
parentTime = time.time()
for i in range(40):
img_cv = np.asarray(ImageGrab.grab())
img = cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)
current = time.time()
diff = (current - parentTime)
print("fps:" + str(float(40)/diff))
#Verbesserung win32+opencv
parentTime = time.time()
for i in range(40):
memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), win32con.SRCCOPY)
img = np.fromstring(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
current = time.time()
diff = (current - parentTime)
print("fps:" + str(float(40)/diff))
fps:17.665207097327016
fps:29.761997556556736
Oh, win32 ist selbst im Konvertierungsprozess von opencv schnell genug. Schauen wir uns das einmal an.
Wir haben keine großen Fortschritte gemacht, aber lassen Sie uns den Code bisher schreiben. (Es ist völlig unorganisierter und problematischer Code, verwenden Sie ihn also nicht.)
import cv2
import numpy as np
from PIL import ImageGrab
import ctypes
import time
import pyaudio
import wave
import win32gui, win32ui, win32con, win32api
import warnings
warnings.simplefilter("ignore", DeprecationWarning)
hnd = win32gui.GetDesktopWindow()
width = 1920
height = 1080
windc = win32gui.GetWindowDC(hnd)
srcdc = win32ui.CreateDCFromHandle(windc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, width, height)
memdc.SelectObject(bmp)
user32 = ctypes.windll.user32
capSize = (user32.GetSystemMetrics(0), user32.GetSystemMetrics(1))
print(capSize)
fourcc = cv2.VideoWriter_fourcc(*"DIVX")
writer = cv2.VideoWriter("test.mov", fourcc, 20, capSize)
count = 0
FirstFlag = True
WAVE_OUTPUT_FILENAME = "test.wav"
RECORD_SECONDS = 5
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 2 ** 11
audio = pyaudio.PyAudio()
stream = audio.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
input_device_index=0,
frames_per_buffer=CHUNK)
frames = []
sTime = time.time()
count = 0
arrScreenShot = []
print ("start")
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
count+=1
if count == 30 :
current = time.time()
diff = (current - sTime)
print("fps:" + str(float(count)/diff))
sTime = time.time()
count = 0
#Bilderfassung
# fps18
# img_cv = np.asarray(ImageGrab.grab())
# img = cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)
# writer.write(img)
# fps29
memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), win32con.SRCCOPY)
img = np.fromstring(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
#Videoexport
writer.write(img)
# #Sprachaufnahme
# data = stream.read(CHUNK)
# frames.append(data)
writer.release()
stream.stop_stream()
stream.close()
audio.terminate()
waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(b''.join(frames))
waveFile.close()
print ("finish")
Der Audioaufnahmevorgang ist auskommentiert. Wenn Sie gleichzeitig Bildschirm- und Audioaufnahmen machen, ist dies langsamer Ich habe vor, es parallel umzuschreiben. (Der unten ist neu geschrieben)
Lassen Sie uns zunächst die Bildschirmaufnahme abschließen.
fps:20.089757121871102
Wenn ich die obige Quelle verwende und die Geschwindigkeit messe, ist sie langsam. Die Ursache ist beim Exportieren des Videos.
writer.write(img)
Das Vorhandensein dieser in der Schleife durchgeführten Verarbeitung senkt die fps um etwa 10. Diese Funktion ist eine Funktion von opencv, einer Funktion einer Klasse namens cv2.VideoWriter. Wenn es eine andere schnelle Videoexportbibliothek gibt, würde ich sie gerne verwenden.
Die Probleme bei der Verwendung dieser Funktion sind im Rahmen der von mir verstandenen Spezifikationen wie folgt.
1. 1. Langsam beim Schreiben.
2. Sie können Videos nur mit einer festen Bildrate speichern.
Wenn es eine andere Videoexportbibliothek als opencv gibt, ist dies auch ein Problem, das Sie überprüfen möchten.
Um den zweiten zu ergänzen, Als ich den Bildschirm das letzte Mal aufgenommen habe, waren die fps 14-19fps Das Ergebnis war sehr unterschiedlich. Aus diesem Grund war die Ausgabevideozeit ausgeschaltet.
Sie können in einem festen Frame schreiben und dabei einige fps-Abweichungen ignorieren. In Anbetracht der endgültigen Kombination von Video und Audio, Ich möchte es genau speichern, wenn ich kann.
Mit der Standard-iOS-API bei der Ausgabe eines Videos Übergeben Sie den Zeitstempel mit dem Rahmenbild Ich habe das Gefühl, das Video gespeichert zu sehen. Am einfachsten wäre es, wenn Sie das Video mit einer solchen variablen Bildrate (VFR) speichern könnten. Außerdem ist es noch besser, wenn die Schreibgeschwindigkeit hoch ist.
Lassen Sie uns herausfinden, ob es eine andere solche Bibliothek gibt.
・ ・ ・ ・ ・ ・ ・ ・ ・ ・
Ich habe es nachgeschlagen, aber ich konnte es nicht finden. Es scheint keine andere Wahl zu geben, als einen Kompromiss einzugehen.
1. 1. Langsam beim Schreiben.
Wenn möglich, wollte ich es sofort nach der Aufnahme schreiben, aber lassen Sie uns aufgeben. Versuchen Sie, die aufgenommenen Bilder in einem Array zu halten und sie nach der Aufnahme zu verarbeiten.
Wenn Sie die gespeicherten Daten nicht in irgendeiner Form ausgeben, Wenn Sie lange aufnehmen, scheint die Erinnerung im Handumdrehen zu punktieren. Aber jetzt konzentrieren wir uns auf die Erfüllung der Funktion.
2. Sie können Videos nur mit einer festen Bildrate speichern.
Vor der zweiten Maßnahme werden wir die aktuellen Probleme lösen. Lassen Sie uns als Versuch die Verarbeitungszeit pro Bild grafisch darstellen, wenn jedes Bild aufgenommen wird.
... (weggelassen) ...
arrScreenShot = []
imgList = []
graph = []
print ("start")
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
count+=1
current = time.time()
diff = (current - sTime)
graph.append(diff)
# print( str(i) + "Rahmen:" + str(diff))
sTime = time.time()
count = 0
#Bilderfassung
memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), win32con.SRCCOPY)
img = np.fromstring(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
imgList.append(img)
import statistics
import matplotlib.pyplot as plt
median = statistics.median(graph)
print("Median:" + str(median))
x = list(range(len(graph)))
x3 = [median] * len(graph)
plt.plot(x, graph, color = "red")
plt.plot(x, x3, color = "blue")
plt.show()
... (weggelassen) ...
Die horizontale Achse ist die Anzahl der aufgenommenen Rahmenbilder. (107 Blätter insgesamt) Die vertikale Achse ist die Verarbeitungszeit pro Frame (s). Wenn es beispielsweise 30 fps ist, beträgt die Verarbeitungszeit pro Blatt 0,03 s.
Die rote Linie ist die Plotlinie der gemessenen Verarbeitungszeit. Die blaue Linie ist der Medianwert der roten Linie. Der Wert ist 0.03341841697692871. In fps ist es 29,9.
Betrachtet man die Grafik, so ist die Bearbeitungszeit des ansteigenden Teils Sie können sehen, dass es extrem langsam ist. Dies scheint die Hauptursache für schnellen und langsamen Vorlauf zu sein.
Ich dachte über Folgendes als Gegenmaßnahme nach.
1. 1. Schreiben Sie Videos mit variabler Bildrate
2. Korrigiert, sodass Screenshots in regelmäßigen Zeitabständen aufgenommen werden
Schreiben Sie ein Video in einem festen Rahmen
3. 3. Ignorieren Sie Frame-Bilder, die das angegebene Zeitintervall überschreiten oder nicht aufweisen, und verwenden Sie das vorherige Frame.
Schreiben Sie ein Video in einem festen Rahmen.
4. Nehmen Sie nicht den ersten Teil auf, der zu langsam ist. Zielt auf 20 Frames und höher ab.
Ich suchte nach einer Bibliothek, die mit VFR geschrieben werden kann, gab aber auf, weil sie nicht gefunden werden konnte. 4 scheint am einfachsten zu sein, aber damit wird es eine Lücke in der Wiedergabezeit zwischen Video und Audio geben. Sie können sehen, wie viel es aus ist, aber Es ist etwas unangenehm, wenn Sie am Ende daran denken, Ton und Video zusammenzuführen.
Irgendwie scheint 2 am sinnvollsten zu sein. Gehen wir mit der Politik von 2.
Derzeit wird der Bildschirmaufnahmevorgang jedes Mal ausgeführt, wenn Sie eine Schleife mit for ausführen. Es sollte nicht in regelmäßigen Zeitabständen erfasst werden.
https://qiita.com/montblanc18/items/05715730d99d450fd0d3 Verweis auf diese Seite, Versuchen Sie, in regelmäßigen Zeitintervallen auszugeben. Vorerst werde ich versuchen, es so auszuführen, wie es ist, ohne an irgendetwas zu denken.
~ (Weggelassen) ~
import time
import threading
def worker():
print(time.time())
memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), win32con.SRCCOPY)
img = np.fromstring(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
imgList.append(img)
def scheduler(interval, f, wait = True):
base_time = time.time()
next_time = 0
while True:
t = threading.Thread(target = f)
t.start()
if wait:
t.join()
next_time = ((base_time - time.time()) % interval) or interval
time.sleep(next_time)
scheduler(0.035, worker, False)
exit()
~ (Weggelassen) ~
Infolgedessen wurden viele Frames erfolgreich als Videos ausgegeben, aber sie schlugen häufig fehl.
Die Ursache scheint zu sein, dass ein Objekt von mehreren Threads referenziert wurde. Bisher eine Instanz namens memdc, die die Bildschirmaufnahme steuert Ich habe es die ganze Zeit benutzt.
Bei Verwendung der Thread-Verarbeitung wird auf eine Instanz verwiesen. Es ist durcheinander. Lassen Sie uns umschreiben.
~ (Weggelassen) ~
frames = []
sTime = time.time()
count = 0
arrScreenShot = []
imgList = []
graph = []
print ("start")
import time
import threading
def worker(imgList):
print(time.time())
imgList.append(win32con.SRCCOPY)
def scheduler(interval,MAX_SECOND, f, wait = False):
base_time = time.time()
next_time = 0
while (time.time()-base_time) < MAX_SECOND:
t = threading.Thread(target = f,args=(imgList,))
t.start()
if wait:
t.join()
next_time = ((base_time - time.time()) % interval) or interval
time.sleep(next_time)
scheduler(1/fps, 40, worker, False)
for tmpSRCCOPY in imgList:
memdc.BitBlt((0, 0), (width, height), srcdc, (0, 0), tmpSRCCOPY)
img = np.fromstring(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
writer.write(img)
~ (Weggelassen) ~
Wow, verdammt noch mal, s ... leg es beiseite Das letzte Mal habe ich versucht, ein 40-Sekunden-Video auszugeben, aber es kam in 28 Sekunden zurück. Was wird diesmal passieren?
39 Sekunden. Oh, es funktioniert. Es gibt kein Problem, da es sich um ein Dezimalpunktproblem handelt, das weniger als 1 Sekunde beträgt. Es ist ein Erfolg. Die Bildschirmaufnahme ist einmal so gut Lassen Sie uns die Genauigkeit in der zweiten Hälfte genauer überprüfen.
Übrigens mit der bisherigen Umsetzung Die Punkte, über die Sie sich Sorgen machen müssen und die Probleme, die nicht behoben wurden, sind folgende.
● Weil ich gerade die Bilddaten in das Array eingefügt habe
Wenn Sie für eine lange Zeit aufnehmen, wird es fallen.
● Ich habe einen Hochgeschwindigkeits-Win32 eingeführt, der in Echtzeit aufzeichnet.
Schließlich ist unsere Annahme, in Echtzeit aufzunehmen, verschwunden.
Eigentlich ImageGrab.grab()Es wurde ein Mechanismus, der sich nicht wesentlich von der Verwendung unterscheidet.
Organisieren Sie die Quelle. Ausführen, nachdem die folgende Bibliothek hinzugefügt wurde.
pip install moviepy
Diese Bibliothek wird zum Zusammenführen von Video und Audio verwendet.
Und das Folgende ist die Quelle, die gleichzeitig aufzeichnet und aufzeichnet. Als Maßnahme gegen Verzögerungen habe ich beschlossen, Audio- und Bildschirmaufnahmen in separaten Threads auszuführen. (Etwas verdächtig)
capture.py
import cv2
import numpy as np
import pyaudio
import wave
import win32gui, win32ui, win32con, win32api
import time
import threading
#Fehler Gegenmaßnahmen beim Versuch, mit win32 api in numpy zu konvertieren
import warnings
warnings.simplefilter("ignore", DeprecationWarning)
class VideoCap:
FrameList=[]
def __init__(self,width,height,fps,FileName):
capSize = (width, height)
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
self.writer = cv2.VideoWriter(FileName, fourcc, fps, capSize)
hnd = win32gui.GetDesktopWindow()
windc = win32gui.GetWindowDC(hnd)
self.srcdc = win32ui.CreateDCFromHandle(windc)
def RecordStart(self,fps,rec_time):
def StoreFrameCap(FrameList):
# print(time.time())
FrameList.append(win32con.SRCCOPY)
def scheduler(interval, MAX_SECOND, f, wait=False):
base_time = time.time()
next_time = 0
while (time.time() - base_time) < MAX_SECOND:
t = threading.Thread(target=f, args=(self.FrameList,))
t.start()
if wait:
t.join()
next_time = ((base_time - time.time()) % interval) or interval
time.sleep(next_time)
scheduler(1 / fps,rec_time, StoreFrameCap, False)
def RecordFinish(self):
for tmpSRCCOPY in self.FrameList:
memdc = self.srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(self.srcdc, width, height)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (width, height), self.srcdc, (0, 0), tmpSRCCOPY)
img = np.fromstring(bmp.GetBitmapBits(True), np.uint8).reshape(height, width, 4)
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
self.writer.write(img)
memdc.DeleteDC()
win32gui.DeleteObject(bmp.GetHandle())
self.writer.release()
class AudioCap:
class default:
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 2 ** 11
frames=[]
audio = pyaudio.PyAudio()
def __init__(self,FORMAT=default.FORMAT,CHANNELS=default.CHANNELS,RATE=default.RATE,CHUNK=default.CHUNK):
self.FORMAT = FORMAT
self.CHANNELS = CHANNELS
self.RATE = RATE
self.CHUNK = CHUNK
def RecordStart(self,rec_time):
self.stream = self.audio.open(format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
input=True,
input_device_index=0,
frames_per_buffer=self.CHUNK)
for i in range(0, int(self.RATE / self.CHUNK * rec_time)):
data = self.stream.read(self.CHUNK)
self.frames.append(data)
def RecordFinish(self):
self.stream.stop_stream()
self.stream.close()
self.audio.terminate()
def writeWAV(self,FileName):
waveFile = wave.open(FileName, 'wb')
waveFile.setnchannels(self.CHANNELS)
waveFile.setsampwidth(self.audio.get_sample_size(self.FORMAT))
waveFile.setframerate(self.RATE)
waveFile.writeframes(b''.join(self.frames))
waveFile.close()
#Grundlegende Konfiguration
width = 1920 #Auflösung horizontal
height = 1080 #Auflösung vertikal
fps = 30 # FPS
RECORD_SECONDS = 60 #Wiedergabezeit
VIDEO_OUTPUT_FILENAME = "test.mp4" #Audiodatei
AUDIO_OUTPUT_FILENAME = "test.wav" #Videodatei
FINAL_VIDEO = "final_video.mp4" #Video + Audiodatei
#Beispiel
CapAuidio = AudioCap()
CapVideo = VideoCap(width,height,fps,VIDEO_OUTPUT_FILENAME)
#Für Sprachverarbeitungsthreads
def threadFuncAudio(obj):
obj.RecordStart(RECORD_SECONDS)
obj.RecordFinish()
obj.writeWAV(AUDIO_OUTPUT_FILENAME)
thrAudio = threading.Thread(target=threadFuncAudio(CapAuidio,))
#Gleichzeitiger Erfassungsstart
thrAudio.start()
CapVideo.RecordStart(fps,RECORD_SECONDS)
CapVideo.RecordFinish()
#Überprüfung: Wie groß ist der Unterschied in der Wiedergabezeit?
from pydub import AudioSegment
sound = AudioSegment.from_file(AUDIO_OUTPUT_FILENAME, "wav")
time = sound.duration_seconds #Wiedergabezeit(Sekunden)
print('Audio: Wiedergabezeit:', time)
cap = cv2.VideoCapture(VIDEO_OUTPUT_FILENAME)
print('Video: Wiedergabezeit:',cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS))
#Überprüfung: Video / Audio-Zusammenführung
from moviepy.editor import VideoFileClip
from moviepy.editor import AudioFileClip
my_clip = VideoFileClip(VIDEO_OUTPUT_FILENAME)
audio_background = AudioFileClip(AUDIO_OUTPUT_FILENAME)
final_clip = my_clip.set_audio(audio_background)
final_clip.write_videofile(FINAL_VIDEO, fps=fps)
Die Ergebnisse sind wie folgt.
Audio: Wiedergabezeit: 4.96907029478458
Video: Wiedergabezeit: 4.933333333333334
Moviepy - Building video final_video.mp4.
MoviePy - Writing audio in final_videoTEMP_MPY_wvf_snd.mp3
MoviePy - Done.
Moviepy - Writing video final_video.mp4
Moviepy - Done !
Moviepy - video ready final_video.mp4
Process finished with exit code 0
In einem 5-Sekunden-Video gibt es eine Lücke von 0,03 Sekunden. Wenn die Aufnahmezeit lang ist, wird die Abweichung groß?
Audio: Wiedergabezeit: 59.953922902494334
Video: Spielzeit: 59.06666666666667
Eine Verzögerung von ca. 1 Sekunde in 60 Sekunden ... Wenn Sie ein Video mit einem festen Frame exportieren Es ist wahrscheinlich, dass Verzögerungen auftreten, egal was passiert.
Ab dem nächsten Mal ● Wie groß ist der Unterschied zwischen Video und Audio? ● Was passiert, wenn Sie längere Zeit aufnehmen? Erwägen.
Fahren Sie mit dem nächsten Mal fort