[PYTHON] Löschen Sie bestimmte Farben mit OpenCV + PySimpleGUI

Einführung

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.

Was können Sie mit diesem Artikel tun?

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.

test_normal.gif

test.gif

Prozessablauf

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

Programm

Video wird geladen

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)

Farberkennung durch HSV

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 von Bildern und GUI

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-']
                )

Verarbeitung zum Maskieren des Bildes

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)

Reparieren Sie die Verarbeitung des Rahmens und verwischen Sie die Verarbeitung

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()



Referenzlink

Automatische Bildinterpolation mit OpenCV und Python (Fast Marching Method, Navier-Stokes) Image Inpainting

Recommended Posts

Löschen Sie bestimmte Farben mit OpenCV + PySimpleGUI
Erstellen Sie einen Videoplayer mit PySimpleGUI + OpenCV
Katze zurück mit OpenCV erkennen
Sprites mit OpenCV drehen
Datenerweiterung mit openCV
Einfache TopView mit OpenCV
Stolpern Sie mit opencv3 von Homebrew
Gesichtserkennung mit OpenCV von Python
"Apple-Verarbeitung" mit OpenCV3 + Python3
Versuchen Sie die Kantenerkennung mit OpenCV
Bildbearbeitung mit Python OpenCV
Kameraerfassung mit Python + OpenCV
[Python] Verwenden von OpenCV mit Python (Basic)
Binarisieren Sie Fotodaten mit OpenCV
Loop-Video-Laden mit opencv
Echtzeit-Kantenerkennung mit OpenCV
Gesichtserkennung mit Python + OpenCV
Holen Sie sich Bildfunktionen mit OpenCV
Gesichtserkennung / Schneiden mit OpenCV
Probieren Sie OpenCV mit Google Colaboratory aus
Erstellung eines Kaskadenklassifikators mit opencv
Verwenden von OpenCV mit Python @Mac
Bilderkennung mit Keras + OpenCV
Anime-Gesichtserkennung mit OpenCV
Erstellen Sie einen Videoplayer mit PySimpleGUI + OpenCV 3 Hinzufügen einer Maskenfunktion