Ein grundlegendes Konzept in Pc Imaginative and prescient Ist das Verständnis, wie Bilder gespeichert und dargestellt werden. Auf der Festplatte werden Bilddateien auf verschiedene Arten codiert, von verlustvoll, komprimiert JPEG Dateien zu verlustfrei Png Dateien. Sobald Sie ein Bild in ein Programm geladen und aus dem jeweiligen Dateiformat dekodieren, hat es höchstwahrscheinlich eine Array-ähnliche Struktur, die die Pixel im Bild darstellt.

RGB

Jedes Pixel enthält einige Farbinformationen über diesen spezifischen Punkt im Bild. Jetzt ist die häufigste Artwork, diese Farbe darzustellen RGB Raum, wo jedes Pixel drei Werte hat: Rot, Grün und Blau. Diese Werte beschreiben, wie viel von jeder Farbe vorhanden ist und sie werden additiv gemischt. So ist beispielsweise ein Bild mit allen auf Null gesetzten Werten schwarz. Wenn alle drei Werte auf 100percenteingestellt sind, ist das resultierende Bild weiß.

Manchmal kann die Reihenfolge dieser Farbkanäle ausgetauscht werden. Eine weitere gemeinsame Reihenfolge ist BGRso ist die Reihenfolge umgekehrt. Dies wird üblicherweise in verwendet Opencv und die Standardeinstellung beim Lesen oder Anzeigen von Bildern.

Alpha -Kanal

Bilder können auch Informationen über Transparenz enthalten. In diesem Fall ist ein zusätzlicher Alpha -Kanal vorhanden (RGBA). Der Alpha -Wert gibt die Opazität jedes Pixels an: Ein Alpha von Null bedeutet, dass das Pixel vollständig clear ist und ein Wert von 100% ein vollständig undurchsichtiges Pixel darstellt.

HSV

Jetzt RGB (a) ist nicht der einzige Weg, um Farben darzustellen. Tatsächlich gibt es viele verschiedene Farbmodelle, die Farbe darstellen. Eines der nützlichsten Modelle ist die HSV Modell. In diesem Modell wird jede Farbe durch a dargestellt FarbtonAnwesend Sättigung Und Wert Eigentum. Der Farbton beschreibt den Farbton, unabhängig von Helligkeit und Sättigung. Manchmal wird dies auf einem Kreis mit Werten zwischen 0 und 360 oder 0 bis 180 oder einfach zwischen 0 und 100percentdargestellt. Wichtig ist, dass es zyklisch ist, was bedeutet, dass sich die Werte umwickeln. Die zweite Eigenschaft beschreibt die Sättigung wie intensiv Ein Farbton ist, daher führt eine Sättigung von 0 zu grauen Farben. Schließlich beschreibt die Werteigenschaft die Helligkeit der Farbe, sodass eine Helligkeit von 0% immer schwarz ist.

Jetzt ist dieses Farbmodell bei der Bildverarbeitung äußerst hilfreich, da wir den Farbton von der Sättigung und Helligkeit entkoppeln können RGB. Wenn Sie beispielsweise einen Übergang zwischen zwei Farben wünschen und während des vollständigen Übergangs die gleiche Helligkeit behalten, ist dies sehr komplex, um die Verwendung der mit dem zu erreichen RGB Farbmodell, während in der HSV Modell Dies ist unkompliziert, indem Sie nur den Farbton interpolieren.

Praktische Beispiele

Wir werden drei Beispiele für die Arbeit mit diesen Farbräumen in Python mit OpenCV betrachten. Im ersten Beispiel extrahieren wir Teile eines Bildes, die eine bestimmte Farbe haben. Im zweiten Teil erstellen wir eine Dienstprogrammfunktion, um Farben zwischen den Farbräumen zu konvertieren. Schließlich erstellen wir in der dritten Anwendung eine kontinuierliche Animation zwischen zwei Farben mit konstanter Helligkeit und Sättigung.

1 – Farbmaske

Das Ziel dieses Teils ist es, eine Maske zu finden, die Farben basierend auf ihrem Farbton in einem Bild isoliert. Im folgenden Bild gibt es verschiedene farbige Papierstücke, die wir trennen möchten.

farbige Papierstücke

Mit OpenCV können wir das Bild laden und in den HSV -Farbton konvertieren. Standardmäßig werden Bilder in gelesen BGR Format, daher brauchen wir die Flagge cv2.COLOR_BGR2HSV in der Umstellung:

Python">import cv2

img_bgr = cv2.imread("photos/notes.png")
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)

Jetzt auf der HSV Bild können einen Farbfilter mit dem anwenden cv2.inRange Funktion zur Angabe einer unteren und Obergrenze für jede Eigenschaft (Farbton, Sättigung, Wert). Mit einigen Experimenten kam ich zu den folgenden Werten für den Filter:

Eigentum Untergrenze Obergrenze
Farbton 90 110
Sättigung 60 100
Wert 150 200
masks = cv2.inRange(
    src=img_hsv,
    lowerb=np.array((90, 60, 150)),
    upperb=np.array((110, 100, 200)),
)

Der Farbtonfilter ist hier zwischen 90 und 110 beschränkt, was dem hellblauen Papier am Boden des Bildes entspricht. Wir setzen auch einen Bereich der Sättigung und den Helligkeitswert, um eine einigermaßen genaue Maske zu erhalten.

Um die Ergebnisse anzuzeigen, müssen wir zunächst die Einzelkanalmaske in a umwandeln BGR Bildform mit 3 Kanälen. Darüber hinaus können wir die Maske auch auf das Originalbild anwenden und das Ergebnis visualisieren.

mask_bgr = cv2.cvtColor(masks, cv2.COLOR_GRAY2BGR)
img_bgr_masked = cv2.bitwise_and(img_bgr, img_bgr, masks=masks)

composite = cv2.hconcat((img_bgr, mask_bgr, img_bgr_masked))
cv2.imshow("Composite", composite)

Durch das Ändern des Farbtonbereichs können wir auch andere Teile isolieren. Zum Beispiel für das lila Papier können wir den folgenden Bereich angeben:

Eigentum Untergrenze Obergrenze
Farbton 160 175
Sättigung 80 110
Wert 170 210

2 – Farbkonvertierung

Während OpenCV eine praktische Funktion zum Umwandeln vollständiger Bilder zwischen Farbräumen bietet, bietet sie keine außergewöhnliche Lösung, um einzelne Farben zwischen Farbräumen zu konvertieren. Wir können einen einfachen Wrapper schreiben, der ein kleines 1 × 1 -Pixel -Bild mit einer Eingangsfarbe erstellt, die integrierte OpenCV -Funktion verwendet, um in einen anderen Farbton zu konvertieren und die Farbe dieses einzelnen Pixels erneut zu extrahieren.

def convert_color_space(enter: tuple(int, int, int), mode: int) -> tuple(int, int, int):
    """
    Converts between coloration areas

    Args:
        enter: A tuple representing the colour in any coloration house (e.g., RGB or HSV).
        mode: The conversion mode (e.g., cv2.COLOR_RGB2HSV or cv2.COLOR_HSV2RGB).

    Returns:
        A tuple representing the colour within the goal coloration house.
    """
    px_img_hsv = np.array(((enter)), dtype=np.uint8)
    px_img_bgr = cv2.cvtColor(px_img_hsv, mode)
    b, g, r = px_img_bgr(0)(0)
    return int(b), int(g), int(r)

Jetzt können wir die Funktion mit jeder Farbe testen. Wir können überprüfen, dass wir die gleichen Werte erhalten, wenn wir von RGB -> HSV -> RGB zurück zum ursprünglichen Format konvertieren.

red_rgb = (200, 120, 0)

red_hsv = convert_color_space(red_rgb, cv2.COLOR_RGB2HSV)
red_bgr = convert_color_space(red_rgb, cv2.COLOR_RGB2BGR)
red_rgb_back = convert_color_space(red_hsv, cv2.COLOR_HSV2RGB)

print(f"{red_rgb=}") # (200, 120, 0)
print(f"{red_hsv=}") # (18, 255, 200)
print(f"{red_bgr=}") # (0, 120, 200)
print(f"{red_rgb_back=}") # (200, 120, 0)

3 – kontinuierlicher Farbübergang

In diesem dritten Beispiel werden wir einen Übergang zwischen zwei Farben mit einer konstanten Helligkeit und Sättigungsinterpolation erstellen. Dies wird mit einer direkten Interpolation zwischen den anfänglichen und endgültigen RGB -Werten verglichen.

def interpolate_color_rgb(
    start_rgb: tuple(int, int, int), end_rgb: tuple(int, int, int), t: float
) -> tuple(int, int, int):
    """
    Interpolates between two colours in RGB coloration house.
    Args:
        start_rgb: The beginning coloration in RGB format.
        end_rgb: The ending coloration in RGB format.
        t: A float between 0 and 1 representing the interpolation issue.
    Returns:
        The interpolated coloration in RGB format.
    """
    return (
        int(start_rgb(0) + (end_rgb(0) - start_rgb(0)) * t),
        int(start_rgb(1) + (end_rgb(1) - start_rgb(1)) * t),
        int(start_rgb(2) + (end_rgb(2) - start_rgb(2)) * t),
    )


def interpolate_color_hsv(
    start_rgb: tuple(int, int, int), end_rgb: tuple(int, int, int), t: float
) -> tuple(int, int, int):
    """
    Interpolates between two colours in HSV coloration house.
    Args:
        start_rgb: The beginning coloration in RGB format.
        end_rgb: The ending coloration in RGB format.
        t: A float between 0 and 1 representing the interpolation issue.
    Returns:
        The interpolated coloration in RGB format.
    """
    start_hsv = convert_color_space(start_rgb, cv2.COLOR_RGB2HSV)
    end_hsv = convert_color_space(end_rgb, cv2.COLOR_RGB2HSV)

    hue = int(start_hsv(0) + (end_hsv(0) - start_hsv(0)) * t)
    saturation = int(start_hsv(1) + (end_hsv(1) - start_hsv(1)) * t)
    worth = int(start_hsv(2) + (end_hsv(2) - start_hsv(2)) * t)

    return convert_color_space((hue, saturation, worth), cv2.COLOR_HSV2RGB)

Jetzt können wir eine Schleife schreiben, um diese beiden Interpolationsmethoden zu vergleichen. Um das Bild zu erstellen, verwenden wir das np.full Methode zum Füllen aller Pixel des Bildarrays mit einer angegebenen Farbe. Verwendung cv2.hconcat Wir können die beiden Bilder horizontal in einem Bild kombinieren. Bevor wir sie anzeigen, müssen wir in das OpenCV -Format BGR konvertieren.

def run_transition_loop(
    color_start_rgb: tuple(int, int, int),
    color_end_rgb: tuple(int, int, int),
    fps: int,
    time_duration_secs: float,
    image_size: tuple(int, int),
) -> None:
    """
    Runs the colour transition loop.

    Args:
        color_start_rgb: The beginning coloration in RGB format.
        color_end_rgb: The ending coloration in RGB format.
        time_steps: The variety of time steps for the transition.
        time_duration_secs: The period of the transition in seconds.
        image_size: The scale of the photographs to be generated.
    """

    img_shape = (image_size(1), image_size(0), 3)
    num_steps = int(fps * time_duration_secs)

    for t in np.linspace(0, 1, num_steps):
        color_rgb_trans = interpolate_color_rgb(color_start_rgb, color_end_rgb, t)
        color_hue_trans = interpolate_color_hsv(color_start_rgb, color_end_rgb, t)

        img_rgb = np.full(form=img_shape, fill_value=color_rgb_trans, dtype=np.uint8)
        img_hsv = np.full(form=img_shape, fill_value=color_hue_trans, dtype=np.uint8)

        composite = cv2.hconcat((img_rgb, img_hsv))
        composite_bgr = cv2.cvtColor(composite, cv2.COLOR_RGB2BGR)

        cv2.imshow("Coloration Transition", composite_bgr)

        key = cv2.waitKey(1000 // fps) & 0xFF
        if key == ord("q"):
            break

    cv2.destroyAllWindows()

Jetzt können wir diese Funktion einfach mit zwei Farben aufrufen, für die wir den Übergang visualisieren möchten. Unten visualisiere ich den Übergang von Blau Zu Gelb.

run_transition_loop(
    color_start_rgb=(0, 0, 255),  # Blue
    color_end_rgb=(255, 255, 0),  # Yellow
    fps=25,
    time_duration_secs=5,
    image_size=(512, 256),
)

Der Unterschied ist ziemlich drastisch. Während die Sättigung und Helligkeit in der richtigen Animation konstant bleiben, ändern sie sich erheblich für den Übergang, der direkt in die interpoliert RGB Raum.


Weitere Informationen zur Implementierung finden Sie im vollständigen Quellcode im GitHub -Repository:

https://github.com/trflorian/auto-color-filter


Alle Visualisierungen in diesem Beitrag wurden vom Autor erstellt.

Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert