Verwenden Sie DMD (Dynamic Mode Decomposition), um den Hintergrund des Videos zu trennen und ein Video nur mit dem dynamischen Modus des sich bewegenden Objekts zu erstellen. Die dynamische Modenzerlegung ist wie eine Kombination aus Hauptkomponentenanalyse und Fourier-Transformation. Eine ausführliche Erläuterung der Zerlegung im dynamischen Modus finden Sie unter dem Link in dem Artikel, den ich zuvor geschrieben habe. -https://qiita.com/matsxxx/items/5e4b272de821fb1c11e0
Ich werde kurz das Verfahren der Zerlegung im dynamischen Modus vorstellen. Die dynamische Modenzerlegung erzeugt einen dynamischen Modus, indem die Eigenwerte und Eigenvektoren einer Übergangsmatrix aus Zeitreihendaten ermittelt werden. Es kann in Dimensionen und Zeitrichtung in Merkmale zerlegt werden. Dimensionsmerkmale erscheinen in Eigenvektoren und zeitliche Merkmale erscheinen in einer komplexen Anzahl von Eigenwerten.
Bei der dynamischen Modenzerlegung werden die Eigenwerte und Eigenvektoren der Übergangsmatrix implementiert, so dass sie mit einem realistischen Rechenaufwand erhalten werden können. In diesem Artikel ist es in Exact DMD implementiert.
import scipy.linalg as la
#DMD-Definition
def dmd(X, Y, truncate=None):#X=X_{1:n-1} Y=X_{2:n}
u2,sig2,vh2 = la.svd(X, False)
r = len(sig2) if truncate is None else truncate
u = u2[:,:r]
sig = np.diag(sig2)[:r,:r]
v = vh2.conj().T[:,:r]
Atil = np.dot(np.dot(np.dot(u.conj().T, Y), v), la.inv(sig))
mu,w = la.eig(Atil)
phi = np.dot(np.dot(np.dot(Y, v), la.inv(sig)), w)#DMD mode
return mu, phi
Ich habe Atrium in [Video hier] verwendet (https://www.jpjodoin.com/urbantracker/dataset.html). Dies ist ein Video einer Person, die geht. Ich benutze 120frame bis 170frame. Trennen Sie den Hintergrund von der gehenden Person.
import cv2
#Bildpfad
video_path = "./atrium_video.avi"
#Bild wird geladen
cap = cv2.VideoCapture(video_path)
#Holen Sie sich Bildauflösung, Bildrate, Anzahl der Bilder
wid = cap.get(cv2.CAP_PROP_FRAME_WIDTH)#Seite
hei = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)#Vertikal
fps = cap.get(cv2.CAP_PROP_FPS)#Bildrate
count = cap.get(cv2.CAP_PROP_FRAME_COUNT)#Anzahl der Frames
dt = 1/fps#Anzahl der Sekunden zwischen den Bildern
print(f"wid:{wid}", f" hei:{hei}", f" fps:{fps}", f" count:{count}", f"dt:{dt}")
#Rahmen zu verwenden
start_frame =120
end_frame = 170
#Bildauflösung 1/Auf 4 setzen (um den Rechenaufwand zu reduzieren)
r = 4
#Rahmenextraktion
cat_frames = []
cap.set(cv2.CAP_PROP_POS_FRAMES,start_frame)
for i in range(end_frame - start_frame):
ret, img = cap.read()
if not ret:
print("no image")
break
buf = cv2.cvtColor(cv2.resize(img,(int(wid/r), int(hei/r))), cv2.COLOR_BGR2GRAY).flatten()#
cat_frames.append(buf)
cat_frames = np.array(cat_frames).T#Bild für DMD verwendet
cap.release()
Bringt das Video in den dynamischen Modus. Der Hintergrund ist, dass der Vibrations- / Amplitudenmodus 0 Amplituden und 0 Frequenzen hat. Der sich bewegende Körper ist etwas anderes als der Hintergrund.
#DMD-Berechnung
X1 = cat_frames[:,:-1]
X2 = cat_frames[:,1:]
mu, phi = dmd(X1,X2)
omega = np.log(mu)/dt#Vibrations- / Amplitudenmodus
#Beurteilung des Hintergrunds und des sich bewegenden Objekts
bg = np.abs(omega) < 1e-2 #Hintergrundextraktion
fg = ~bg #Beweglicher Körper
phi_bg = phi[:,bg]#Dynamischer Hintergrundmodus
phi_fg = phi[:,fg]#Dynamischer Modus zum Bewegen von Objekten
omega_bg = omega[bg]#Hintergrundvibrations- / Amplitudenmodus
omega_fg = omega[fg]#Vibrations- / Amplitudenmodus des sich bewegenden Objekts
Verwenden Sie die folgende Formel, um ein Video im Bewegungsmodus zu rekonstruieren.
$ \ Phi ^ {fg} $ ist die dynamische Modusmatrix des sich bewegenden Objekts, $ \ omega ^ {fg} $ ist der Schwingungs- / Amplitudenmodus des sich bewegenden Objekts und die pseudo-inverse Matrix der dynamischen Modusmatrix des sich bewegenden Objekts ist $ \ mathbf {von rechts. Es ist eine Matrix, die erhalten wird, indem das Matrixprodukt des anfänglichen Videowerts von b} ^ {fg} $ genommen wird.
#Wiederaufbau
phi_fg_pinv = la.pinv(phi_fg)#Pseudo-inverse Matrix. Es benötigt viel Zeit. Wenn Sie nicht genügend Speicher haben, erhöhen Sie r.
X_fg = np.zeros((len(omega_fg), end_frame - start_frame), dtype='complex')
b = phi_fg_pinv @ cat_frames[:,0]#Ursprünglicher Wert
for tt in range(end_frame - start_frame):
X_fg[:,tt] = b * np.exp(omega_fg * dt * tt)
X_fg = phi_fg @ X_fg
#Zur Helligkeitseinstellung
lum_max = np.abs(X_fg.real.max())
lum_min = np.abs(X_fg.real.min())
lum_diff = lum_max + lum_min
#Videoerstellung
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
writer = cv2.VideoWriter("out_dmd_fg.mp4", fourcc, fps, (int(wid/r), int(hei/r)))
for tt in range(end_frame - start_frame):
a = X_fg[:,tt].real.reshape(int(hei/r), -1)
a = (a + lum_min)/lum_diff * 255
a = a.astype("uint8")
out_img = np.tile(a, (3,1,1)).transpose((1,2,0))#Graustufen[wid, hei, 3]In eine Matrix von konvertieren
writer.write(out_img)
writer.release()
Sie können sehen, dass der Hintergrund verschwunden ist und die Bewegung nur für Menschen ist. Ein Nachbild ist jedoch in der Bewegung von Menschen zu sehen. Ich denke, das liegt daran, dass nur 50 Bilder des Videos verwendet werden, aber es scheint, dass ich nicht gut darin bin, lineare Bewegungen zu zerlegen.
import numpy as np
import scipy.linalg as la
import cv2
#Bildpfad
video_path = "./atrium_video.avi"
#DMD-Definition
def dmd(X, Y, truncate=None):
u2,sig2,vh2 = la.svd(X, False)
r = len(sig2) if truncate is None else truncate
u = u2[:,:r]
sig = np.diag(sig2)[:r,:r]
v = vh2.conj().T[:,:r]
Atil = np.dot(np.dot(np.dot(u.conj().T, Y), v), la.inv(sig))
mu,w = la.eig(Atil)
phi = np.dot(np.dot(np.dot(Y, v), la.inv(sig)), w)#DMD mode
return mu, phi
#Bild wird geladen
cap = cv2.VideoCapture(video_path)
#Holen Sie sich Bildauflösung, Bildrate, Anzahl der Bilder
wid = cap.get(cv2.CAP_PROP_FRAME_WIDTH)#Seite
hei = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)#Vertikal
fps = cap.get(cv2.CAP_PROP_FPS)#Bildrate
count = cap.get(cv2.CAP_PROP_FRAME_COUNT)#Anzahl der Frames
dt = 1/fps#Anzahl der Sekunden zwischen den Bildern
print(f"wid:{wid}", f" hei:{hei}", f" fps:{fps}", f" count:{count}", f"dt:{dt}")
#Rahmen zu verwenden
start_frame =120
end_frame = 170
#Bildauflösung 1/Auf 4 setzen (um den Rechenaufwand zu reduzieren)
r = 4
#Rahmenextraktion
cat_frames = []
cap.set(cv2.CAP_PROP_POS_FRAMES,start_frame)
for i in range(end_frame - start_frame):
ret, img = cap.read()
if not ret:
print("no image")
break
buf = cv2.cvtColor(cv2.resize(img,(int(wid/r), int(hei/r))), cv2.COLOR_BGR2GRAY).flatten()#
cat_frames.append(buf)
cat_frames = np.array(cat_frames).T
cap.release()
#DMD-Berechnung
X1 = cat_frames[:,:-1]
X2 = cat_frames[:,1:]
mu, phi = dmd(X1,X2)
omega = np.log(mu)/dt
#Urteil anders als Hintergrund und bewegliches Objekt
bg = np.abs(omega) < 1e-2 #Hintergrundextraktion
fg = ~bg #Extraktion des sich bewegenden Körpers
phi_bg = phi[:,bg]#Dynamischer Hintergrundmodus
phi_fg = phi[:,fg]#Dynamischer Modus zum Bewegen von Objekten
omega_bg = omega[bg]#Hintergrundvibrations- / Amplitudenmodus
omega_fg = omega[fg]#Vibrations- / Amplitudenmodus des sich bewegenden Objekts
#Rekonstruktion im dynamischen Modus
phi_fg_pinv = la.pinv(phi_fg)#Pseudo-inverse Matrix. Wenn ein Speicherfehler auftritt, erhöhen Sie r
X_fg = np.zeros((len(omega_fg), end_frame - start_frame), dtype='complex')
b = phi_fg_pinv @ cat_frames[:,0]#Ursprünglicher Wert
for tt in range(end_frame - start_frame):
X_fg[:,tt] = b * np.exp(omega_fg * dt * tt)
X_fg = phi_fg @ X_fg
#Zur Helligkeitseinstellung
lum_max = np.abs(X_fg.real.max())
lum_min = np.abs(X_fg.real.min())
lum_diff = lum_max + lum_min
#Videoerstellung
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
writer = cv2.VideoWriter("out_dmd_fg.mp4", fourcc, fps, (int(wid/r), int(hei/r)))
for tt in range(end_frame - start_frame):
a = X_fg[:,tt].real.reshape(int(hei/r), -1)
a = (a + lum_min)/lum_diff * 255
a = a.astype("uint8")
out_img = np.tile(a, (3,1,1)).transpose((1,2,0))#Graustufen[wid, hei, 3]In eine Matrix von konvertieren
writer.write(out_img)
writer.release()