Um OpenCV effektiv nutzen zu können, muss das gewünschte Ergebnis nicht nur durch einen Prozess, sondern auch durch mehrere Prozesse und die Kombination mit anderen Paketen erzielt werden. Versuchen wir diesmal als Beispiel, die Farbe des angeklickten Teils zu löschen.
Wenn Sie mit der linken Maustaste auf einen bestimmten Farbteil im Video klicken, verschwindet diese Farbe. Um die Größe des gelöschten Teils und den Grad der Unschärfe anzupassen, müssen Parameter wie der HSV-Wert geändert werden. Die Parameter können in der GUI geändert werden.
Der Prozess ist wie folgt. Video wird geladen
↓
Maskenherstellung → Konvertieren Sie das Bild in HSV und stellen Sie ein, dass nur eine bestimmte Farbe maskiert wird. Um die Farbe zu extrahieren, klicken Sie mit der linken Maustaste auf das Video, um die Farbe dieses Teils zu extrahieren. Darüber hinaus können Sie mit dem mit der PySimple-Benutzeroberfläche erstellten Schieberegler Feineinstellungen vornehmen.
↓
Rauschunterdrückung zum Maskieren des Bildes (Öffnen, Schließen) → Da das Rauschen nur durch Farbextraktion erhalten bleibt, wird das Rauschen durch Öffnen und Schließen entfernt.
↓
Quellprozess (Dilatation) zum Maskieren des Bildes → Da der Umriss der Farbe in vielen Fällen nicht gut extrahiert werden kann, wird der Maskenteil gleichmäßig erweitert.
↓
Reparaturbehandlung (Inpaint) am Maskenteil → Wir reparieren das Maskenteil mit der umgebenden Farbe.
↓
Verwischen Sie die Maske → Da es nur bei Inpaint auffällt, ist es unscharf.
↓
Anzeige
import PySimpleGUI as sg
import cv2
import numpy as np
from pathlib import Path
def file_read():
'''
Wählen Sie eine Datei aus und laden Sie sie
'''
fp = ""
#GUI-Layout
layout = [
[
sg.FileBrowse(key="file"),
sg.Text("Datei"),
sg.InputText()
],
[sg.Submit(key="submit"), sg.Cancel("Exit")]
]
# self.WINDOW-Generation
window = sg.Window("Dateiauswahl", layout)
#Ereignisschleife
while True:
event, values = window.read(timeout=100)
if event == 'Exit' or event == sg.WIN_CLOSED:
break
elif event == 'submit':
if values[0] == "":
sg.popup("Es wurde keine Datei eingegeben.")
event = ""
else:
fp = values[0]
break
window.close()
return Path(fp)
Diese Funktion erstellt eine Maske, um nur den HSV-Wert innerhalb des angegebenen Bereichs zu verarbeiten. Angegeben auf PySimpleGUI Lesen Sie den Wert des Schiebereglers und generieren Sie ein Maskenbild.
def hsv(frame, H_max, H_min, S_max, S_min, V_max, V_min, reverse=False):
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
if reverse:
lower1 = np.array([0, int(S_min), int(V_min)])
upper1 = np.array([int(H_min), int(S_max), int(V_max)])
mask1 = cv2.inRange(frame_hsv, lower1, upper1)
lower2 = np.array([int(H_max), int(S_min), int(V_min)])
upper2 = np.array([255, int(S_max), int(V_max)])
mask2 = cv2.inRange(frame_hsv, lower2, upper2)
mask = mask1 + mask2
frame = cv2.bitwise_and(frame, frame, mask=mask)
# mask = cv2.bitwise_and(frame, mask, mask=mask)
else:
lower = np.array([int(H_min), int(S_min), int(V_min)])
upper = np.array([int(H_max), int(S_max), int(V_max)])
mask = cv2.inRange(frame_hsv, lower, upper)
frame = cv2.bitwise_and(frame, frame, mask=mask)
return frame
Laden Sie das Video aus der Datei und zeigen Sie es in OpenCV an. Wenn Sie mit der linken Maustaste auf das Bild klicken, erstellen Sie eine Funktion, die den HSV-Wert dieses Teils im Schiebereglerwert von PySimpleGUI widerspiegelt, und geben Sie ihn als Rückruffunktion an.
class Main:
def __init__(self):
self.fp = file_read()
self.cap = cv2.VideoCapture(str(self.fp))
#Video-Speicherflagge
self.rec_flg = False
#Holen Sie sich das erste Bild
#Überprüfen Sie, ob es erhältlich ist
self.ret, self.f_frame = self.cap.read()
self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
#Wenn Sie den Rahmen erhalten können, erhalten Sie verschiedene Parameter
if self.ret:
self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
#Erfassung von Videoinformationen
self.fps = self.cap.get(cv2.CAP_PROP_FPS)
self.org_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.width = self.org_width
self.org_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.height = self.org_height
self.total_count = self.cap.get(cv2.CAP_PROP_FRAME_COUNT)
#Definition des Maskenbildes
self.mask = np.zeros_like(self.f_frame[:, :, 0])
#Rahmenbezogen
self.frame_count = 0
self.s_frame = 0
self.e_frame = self.total_count
#Pause-Flag spielen
self.stop_flg = False
#GUI-Ereignis
self.event = ""
cv2.namedWindow("Movie")
#Rückrufregistrierung für Mausereignisse
cv2.setMouseCallback("Movie", self.onMouse)
#Beenden Sie, wenn der Frame nicht erhalten werden konnte
else:
sg.Popup("Fehler beim Lesen der Datei.")
return
#Mausereignis
def onMouse(self, event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONUP:
hsv = cv2.cvtColor(
self.frame[y:y + 1, x:x + 1, :], cv2.COLOR_BGR2HSV)
h = int(hsv[:, :, 0])
h_min = max(h - 20, 0)
h_max = min(255, h + 20)
s = int(hsv[:, :, 1])
s_min = max(s - 20, 0)
s_max = min(255, s + 20)
v = int(hsv[:, :, 2])
v_min = max(v - 20, 0)
v_max = min(255, v + 20)
self.window['-H_MIN SLIDER_MASK-'].update(h_min)
self.window['-H_MAX SLIDER_MASK-'].update(h_max)
self.window['-S_MIN SLIDER_MASK-'].update(s_min)
self.window['-S_MAX SLIDER_MASK-'].update(s_max)
self.window['-V_MIN SLIDER_MASK-'].update(v_min)
self.window['-V_MAX SLIDER_MASK-'].update(v_max)
self.window['-Hue Reverse_MASK-'].update(False)
def run(self):
# GUI #######################################################
#GUI-Layout
layout = [
[
sg.Text("Start", size=(8, 1)),
sg.Slider(
(0, self.total_count - 1),
0,
1,
orientation='h',
size=(45, 15),
key='-START FRAME SLIDER-',
enable_events=True
)
],
[sg.Slider(
(0, self.total_count - 1),
0,
1,
orientation='h',
size=(50, 15),
key='-PROGRESS SLIDER-',
enable_events=True
)],
[sg.HorizontalSeparator()],
[
sg.Text("Resize ", size=(13, 1)),
sg.Slider(
(0.1, 4),
1,
0.01,
orientation='h',
size=(40, 15),
key='-RESIZE SLIDER-',
enable_events=True
)
],
[
sg.Checkbox(
"Inpaint",
size=(10, 1),
default=False,
key='-INPAINT-',
enable_events=True
)
],
[
sg.Checkbox(
"Opening",
size=(20, 1),
default=False,
key='-OPENING-',
enable_events=True
),
sg.Checkbox(
"Closing",
size=(20, 1),
default=False,
key='-CLOSING-',
enable_events=True
),
sg.Slider(
(3, 31),
5,
2,
orientation='h',
size=(15, 15),
key='-OPENING SLIDER-',
enable_events=True
)
],
[
sg.Checkbox(
"Dilation",
size=(10, 1),
default=False,
key='-DILATION-',
enable_events=True
),
sg.Slider(
(1, 31),
4,
2,
orientation='h',
size=(15, 15),
key='-DILATION SLIDER-',
enable_events=True
)
],
[
sg.Checkbox(
'blur',
size=(10, 1),
key='-BLUR-',
enable_events=True
),
sg.Slider(
(1, 10),
1,
1,
orientation='h',
size=(40, 15),
key='-BLUR SLIDER-',
enable_events=True
)
],
[
sg.Text(
'hsv',
size=(10, 1),
key='-HSV_MASK-',
enable_events=True
),
sg.Button('Blue', size=(10, 1)),
sg.Button('Green', size=(10, 1)),
sg.Button('Red', size=(10, 1))
],
[
sg.Checkbox(
'Hue Reverse',
size=(10, 1),
key='-Hue Reverse_MASK-',
enable_events=True
)
],
[
sg.Text('Hue', size=(10, 1), key='-Hue_MASK-'),
sg.Slider(
(0, 255),
0,
1,
orientation='h',
size=(19.4, 15),
key='-H_MIN SLIDER_MASK-',
enable_events=True
),
sg.Slider(
(1, 255),
125,
1,
orientation='h',
size=(19.4, 15),
key='-H_MAX SLIDER_MASK-',
enable_events=True
)
],
[
sg.Text('Saturation', size=(10, 1), key='-Saturation_MASK-'),
sg.Slider(
(0, 255),
50,
1,
orientation='h',
size=(19.4, 15),
key='-S_MIN SLIDER_MASK-',
enable_events=True
),
sg.Slider(
(1, 255),
255,
1,
orientation='h',
size=(19.4, 15),
key='-S_MAX SLIDER_MASK-',
enable_events=True
)
],
[
sg.Text('Value', size=(10, 1), key='-Value_MASK-'),
sg.Slider(
(0, 255),
50,
1,
orientation='h',
size=(19.4, 15),
key='-V_MIN SLIDER_MASK-',
enable_events=True
),
sg.Slider(
(1, 255),
255,
1,
orientation='h',
size=(19.4, 15),
key='-V_MAX SLIDER_MASK-',
enable_events=True
)
],
[sg.Output(size=(65, 5), key='-OUTPUT-')],
[sg.Button('Clear')]
]
# self.Fenster generieren
self.window = sg.Window('OpenCV Integration', layout, location=(0, 0))
#Anzeige von Videoinformationen
self.event, values = self.window.read(timeout=0)
print("Die Datei wurde gelesen.")
print("File Path: " + str(self.fp))
print("fps: " + str(int(self.fps)))
print("width: " + str(self.width))
print("height: " + str(self.height))
print("frame count: " + str(int(self.total_count)))
#Hauptschleife#########################################################
try:
while True:
#Laden von GUI-Ereignissen
self.event, values = self.window.read(
timeout=0
)
#Ereignis im Fenster anzeigen
if self.event != "__TIMEOUT__":
print(self.event)
#Beenden, wenn die Schaltfläche Beenden gedrückt wird oder wenn die Schaltfläche zum Schließen des Fensters gedrückt wird
if self.event in ('Exit', sg.WIN_CLOSED, None):
break
#Video neu laden
#Funktioniert, wenn der Startrahmen eingestellt ist
if self.event == 'Reset':
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.s_frame)
self.frame_count = self.s_frame
self.window['-PROGRESS SLIDER-'].update(self.frame_count)
self.video_stabilization_flg = False
self.stab_prepare_flg = False
#Reflektieren Sie weiterhin Änderungen am Fortschrittsregler
continue
#Rahmenbetrieb################################################
#Priorität wird gegeben, wenn der Schieberegler direkt geändert wird
if self.event == '-PROGRESS SLIDER-':
#Stellen Sie die Frame-Anzahl auf den Fortschrittsbalken ein
self.frame_count = int(values['-PROGRESS SLIDER-'])
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.frame_count)
#Wenn Sie den Startrahmen ändern
if self.event == '-START FRAME SLIDER-':
self.s_frame = int(values['-START FRAME SLIDER-'])
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.s_frame)
self.frame_count = self.s_frame
self.window['-PROGRESS SLIDER-'].update(self.frame_count)
#Wenn der Zähler den Endrahmen überschreitet, starten Sie ihn vom Startrahmen aus neu
if self.frame_count >= self.e_frame:
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.s_frame)
self.frame_count = self.s_frame
self.window['-PROGRESS SLIDER-'].update(self.frame_count)
continue
#Unterbrechen Sie das Laden des Videos mit der Stopp-Taste
if self.event == 'Play / Stop':
self.stop_flg = not self.stop_flg
#Wenn das Stopp-Flag nicht gesetzt ist und ein Ereignis eintritt, zählen Sie mit
#Beenden Sie den Vorgang
#Wenn die Stopp-Taste gedrückt wird, wird die Videoverarbeitung gestoppt, aber etwas
#Wenn ein Ereignis auftritt, aktualisieren Sie nur das Image
#Gleiches gilt für die Bedienung der Maus
if(
(
self.stop_flg
and self.event == "__TIMEOUT__"
)
):
self.window['-PROGRESS SLIDER-'].update(self.frame_count)
continue
#Rahmen laden##############################################
self.ret, self.frame = self.cap.read()
#Wenn der letzte Frame über sich selbst ist.s_Vom Rahmen fortsetzen
if not self.ret:
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.s_frame)
self.frame_count = self.s_frame
continue
#Größe ändern
self.width = int(self.org_width * values['-RESIZE SLIDER-'])
self.height = int(self.org_height * values['-RESIZE SLIDER-'])
self.frame = cv2.resize(self.frame, (self.width, self.height))
#Führen Sie die Verarbeitung für den ROI durch##########################################
if self.event == 'Blue':
self.window['-H_MIN SLIDER_MASK-'].update(70)
self.window['-H_MAX SLIDER_MASK-'].update(110)
self.window['-S_MIN SLIDER_MASK-'].update(70)
self.window['-S_MAX SLIDER_MASK-'].update(255)
self.window['-V_MIN SLIDER_MASK-'].update(0)
self.window['-V_MAX SLIDER_MASK-'].update(255)
self.window['-Hue Reverse_MASK-'].update(False)
if self.event == 'Green':
self.window['-H_MIN SLIDER_MASK-'].update(20)
self.window['-H_MAX SLIDER_MASK-'].update(70)
self.window['-S_MIN SLIDER_MASK-'].update(70)
self.window['-S_MAX SLIDER_MASK-'].update(255)
self.window['-V_MIN SLIDER_MASK-'].update(0)
self.window['-V_MAX SLIDER_MASK-'].update(255)
self.window['-Hue Reverse_MASK-'].update(False)
if self.event == 'Red':
self.window['-H_MIN SLIDER_MASK-'].update(20)
self.window['-H_MAX SLIDER_MASK-'].update(110)
self.window['-S_MIN SLIDER_MASK-'].update(70)
self.window['-S_MAX SLIDER_MASK-'].update(255)
self.window['-V_MIN SLIDER_MASK-'].update(0)
self.window['-V_MAX SLIDER_MASK-'].update(255)
self.window['-Hue Reverse_MASK-'].update(True)
self.mask = self.frame
self.mask = hsv(
self.mask,
values['-H_MAX SLIDER_MASK-'],
values['-H_MIN SLIDER_MASK-'],
values['-S_MAX SLIDER_MASK-'],
values['-S_MIN SLIDER_MASK-'],
values['-V_MAX SLIDER_MASK-'],
values['-V_MIN SLIDER_MASK-'],
values['-Hue Reverse_MASK-']
)
Führt eine Graustufenkonvertierung, eine Öffnungsverarbeitung, eine Schließverarbeitung und eine Dilatationsverarbeitung des Maskenbilds durch.
#Graustufen
self.mask = cv2.cvtColor(
self.mask,
cv2.COLOR_BGR2GRAY
)
#Geräuschreduzierung
if values['-OPENING-']:
self.mask = cv2.morphologyEx(self.mask, cv2.MORPH_OPEN,
np.ones((int(values['-OPENING SLIDER-']), int(values['-OPENING SLIDER-'])), np.uint8))
#Geräuschentfernung 2
if values['-CLOSING-']:
self.mask = cv2.morphologyEx(self.mask, cv2.MORPH_CLOSE,
np.ones((int(values['-OPENING SLIDER-']), int(values['-OPENING SLIDER-'])), np.uint8))
#Expansionsprozess
if values['-DILATION-']:
self.mask = cv2.dilate(self.mask,
np.ones((int(values['-DILATION SLIDER-']), int(values['-DILATION SLIDER-'])), np.uint8), iterations=1)
Die Lackverarbeitung und die Unschärfeverarbeitung werden am Maskenteil durchgeführt. Der zu lackierende Teil kann implementiert werden, indem ein Maskenbild als Argument angegeben wird. Für Unschärfe verwende ich "cv2.bitwise_not", um Unschärfe nur auf den Maskenteil anzuwenden.
if values['-INPAINT-']:
self.frame = cv2.inpaint(
self.frame,
self.mask,
2,
cv2.INPAINT_TELEA
)
#Verwischen
if values['-BLUR-']:
self.frame_roi = cv2.GaussianBlur(
self.frame, (21, 21), values['-BLUR SLIDER-']
)
#Maske im Rahmen auftragen
#Nur Maskenverarbeitungsteil.Zum Rahmen wechseln
self.frame = cv2.bitwise_not(
cv2.bitwise_not(self.frame_roi),
self.frame,
mask=self.mask
)
#Anzeige der Anzahl der Frames und der verstrichenen Sekunden
cv2.putText(self.frame,
str("framecount: {0:.0f}".format(self.frame_count)),
(15,
20),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
(240,
230,
0),
1,
cv2.LINE_AA)
cv2.putText(self.frame,
str("time: {0:.1f} sec".format(self.frame_count / self.fps)),
(15,
40),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
(240,
230,
0),
1,
cv2.LINE_AA)
#Bild anzeigen
cv2.imshow("Movie", self.frame)
cv2.imshow("Mask", cv2.cvtColor(self.mask, cv2.COLOR_GRAY2BGR))
if self.stop_flg:
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.frame_count)
else:
self.frame_count += 1
self.window['-PROGRESS SLIDER-'].update(
self.frame_count + 1)
#Andere Verarbeitung###############################################
#Protokollfenster löschen
if self.event == 'Clear':
self.window['-OUTPUT-'].update('')
finally:
cv2.destroyWindow("Movie")
cv2.destroyWindow("Mask")
self.cap.release()
self.window.close()
if __name__ == '__main__':
Main().run()
Automatische Bildinterpolation mit OpenCV und Python (Fast Marching Method, Navier-Stokes) Image Inpainting
Recommended Posts