[PYTHON] Sprites mit OpenCV # 2 drehen ~ Mastering cv2.warpAffine () ~

Einführung

Der vorherige Artikel "Sprites mit OpenCV drehen" konnte während der Sommerferien nicht fertiggestellt werden, und ich konnte ihn am Wochenende auflösen. Am Tag nach dem Hochladen kam mir jedoch eine neue Idee. Immerhin ist die Umgebung mit vielen Versuchungen nicht gut. Sie müssen sich in eine härtere Umgebung versetzen, um studieren zu können. Arbeitsplatz. </ strike>

Details zu cv2.warpAffine ()

Es gab ein interessantes, nicht wesentliches Argument von "cv2.warpAffine ()", das ich beim letzten Mal weggelassen habe. Referenzartikel: Zeichnen Sie mit OpenCV ein weiteres Bild auf ein Bild

--src Originalbild. Erforderlich.

  • M 2 * 3-Umwandlungsmatrix. Erforderlich. --dsize Geben Sie die Größe des Ausgabebildes mit einem Taple von "(Breite, Höhe)" an. Erforderlich. --dst Hintergrundbild (außerhalb des Originalbildes). Die Größe sollte der Größe von dsize entsprechen. --flags Bildkomplementmethode. Der Standardwert ist "cv2.INTER_LINEAR". Außerdem cv2.INTER_NEAREST etc. --BorderMode-Hintergrundverarbeitungsmethode (außerhalb des Originalbilds). Der Standardwert ist "cv2.BORDER_CONSTANT". --BorderValue Die Farbe bei borderMode = cv2.BORDER_CONSTANT. Der Standardwert ist "0". Siehe unten.

Verarbeiten Sie das Originalbild im Voraus

Erstellen Sie eine kleine Funktion, um das Ergebnis der Bildverarbeitung leicht verständlich zu machen. Bitte beachten Sie, dass nur der Mindestteil beschrieben wird.

python


def makeSampleImg(img4):   #Bringen Sie ein RGBA 4-Kanal-Bild mit
    h, w = img.shape[:2]
    #A sowie die Umgebung zu färben=Es ist ein Fehler, es 255 (undurchsichtig) zu machen
    cv2.rectangle(img, (0,0), (w-1,h-1), (0,0,255,255), 1)
    return img

img_origin = cv2.imread(filename, -1) #RGBA-Bild
img4 = makeSampleImg(img_origin)
img3 = img4[:, :, :3]  #Beseitigen Sie das A-Element und machen Sie es zu einem RGB-Bild
Das Originalbild Kleine Verarbeitung 3 Kanäle
uchuhikoushi.png uchuhikoushi4w.png uchuhikoushi3w.png

Füllen Sie den Hintergrund mit einer einzigen Farbe

Machen Sie den Hintergrund mit borderMode = cv2.BORDER_CONSTANT einfarbig. Da dies der Standardwert von "borderMode" ist, muss er nicht beschrieben werden. Ich werde es versuchen.

Geben Sie die Hintergrundfarbe an


M = cv2.getRotationMatrix2D((w/2,h/2), 30, 1)
img_rot31 = cv2.warpAffine(img3, M, (w, h), borderValue=(255,255,0))     #Vordergrund RGB, Hintergrund RGB
img_rot32 = cv2.warpAffine(img3, M, (w, h), borderValue=(255,255,0,0))   #Vordergrund RGB, Hintergrund RGBA (A Komponente = 0)
img_rot33 = cv2.warpAffine(img3, M, (w, h))                              #Vordergrund RGB, kein Hintergrund angegeben
img_rot41 = cv2.warpAffine(img4, M, (w, h), borderValue=(255,255,0))     #Vordergrund RGBA, Hintergrund RGB
img_rot42 = cv2.warpAffine(img4, M, (w, h), borderValue=(255,255,0,0))   #Vordergrund-RGBA, Hintergrund-RGBA (A-Komponente = 0)
img_rot43 = cv2.warpAffine(img4, M, (w, h))                              #Vordergrund RGBA, kein Hintergrund angegeben
img_rot44 = cv2.warpAffine(img4, M, (w, h), borderValue=(255,255,0,255)) #Vordergrund-RGBA, Hintergrund-RGBA (mit A-Komponente)

** Wenn der Vordergrund ein RGB-Bild ist **, wird die A-Komponente ignoriert, auch wenn 4 RGBA-Kanäle als Hintergrundfarbe angegeben sind (img_rot32). Es versteht sich, dass, wenn borderValue nicht angegeben ist, der Hintergrund schwarz ist (img_rot33 bzw. die Standardberechnung), die Hintergrundfarbe jedoch "(0,0,0)".

img_rot31 img_rot32 img_rot33
uchuhikoushi31.png uchuhikoushi32.png uchuhikoushi33.png

** Wenn der Vordergrund ein RGBA-Bild ist **, werden 4 RGBA-Kanäle ausgegeben, auch wenn 3 RGB-Kanäle als Hintergrundfarbe angegeben sind. Die zu diesem Zeitpunkt angegebene A-Komponente ist "0". Da A Deckkraft und nicht Transparenz ist, ist dies "0", was bedeutet, dass selbst wenn ein BGR-Wert definiert wird, der nicht RGB ... war, dieser als Ergebnis transparent ist (img_rot41). Selbst wenn borderValue nicht angegeben ist, wird der Hintergrund transparent (img_rot43), aber es ist leicht zu verstehen, wenn Sie glauben, dass die Hintergrundfarbe "(0,0,0,0)" ist. Wenn Sie für die A-Komponente einen anderen Wert als "0" festlegen, wird dieser natürlich richtig gefärbt (img_rot44).

img_rot41 img_rot42 img_rot43 img_rot44
uchuhikoushi41.png uchuhikoushi42.png uchuhikoushi43.png uchuhikoushi44.png

Legen Sie ein Bild als Hintergrund fest

Wenn Sie borderMode = cv2.BORDER_TRANSPARENT setzen, können Sie das Hintergrundbild mit dst angeben. Wie so oft bei OpenCV wird bei Verwendung von "cv2.warpAffine ()" das durch "dst" angegebene Hintergrundbild verarbeitet. Wenn Sie das Originalbild behalten möchten, müssen Sie "dst = back.copy ()" setzen.

Ich habe erwartet, dass es transparent sein würde, weil es TRANSPARENT ist. Wenn ich also nicht "dst" angeben würde, wäre es ein transparenter Hintergrund, aber es war nicht so einfach. Oh! Irgendwie möchte ich Ikura essen.

Geben Sie das Hintergrundbild an


back = cv2.imread(back_name)  #RGB-Bild mit der gleichen Größe wie das Vordergrundbild
back4 = cv2.cvtColor(back, cv2.COLOR_BGR2BGRA) #Erstellen eines RGBA-Images Eine Komponente ist 255 anstelle von 0

M = cv2.getRotationMatrix2D((w/2,h/2), 30, 1)
img_rot35 = cv2.warpAffine(img3, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT, dst=back.copy())   #Vordergrund RGB, Hintergrund RGB
img_rot36 = cv2.warpAffine(img3, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT, dst=back4.copy())  #Vordergrund RGB, Hintergrund RGBA
img_rot37 = cv2.warpAffine(img3, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT)                    #Vordergrund RGB, kein Hintergrund angegeben
img_rot45 = cv2.warpAffine(img4, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT, dst=back.copy())   #Vordergrund RGBA, Hintergrund RGB
img_rot46 = cv2.warpAffine(img4, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT, dst=back4.copy())  #Vordergrund RGBA, Hintergrund RGBA
img_rot47 = cv2.warpAffine(img4, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT)                    #Vordergrund RGBA, kein Hintergrund angegeben

Sowohl der Vordergrund als auch der Hintergrund verhielten sich beim RGB-Bild wie erwartet (img_rot35).

Wenn ich im RGB-Vordergrund kein Hintergrundbild angegeben habe, hat sich das Ergebnis bei jeder Ausführung geändert (img_rot37). numpy hat eine Funktion namens numpy.empty (), die ein nicht initialisiertes Array erstellt. Das Hintergrundbild (oder besser gesagt das Numpy-Array) wird wahrscheinlich auch hier mit denselben Spezifikationen erstellt. Ich bin mir nicht sicher, warum img_rot36, das den RGBA-Hintergrund im RGB-Vordergrund spezifizierte, sich in einen schwarzen Hintergrund mit Staub verwandelte.

img_rot35 img_rot36 img_rot37 teil 1 img_rot37 Teil 2
uchuhikoushi35.png uchuhikoushi36.png uchuhikoushi37.png uchuhikoushi37_2.png

Das RGBA-Bild (img_rot46) sowohl für den Vordergrund als auch für den Hintergrund ist wie erwartet, aber es ist auch ein enttäuschendes Ergebnis. Ich war froh, wenn der Hintergrund im transparenten Teil des Vordergrunds angezeigt wurde, aber es kann nicht geholfen werden, weil ** Affin-Konvertierung überhaupt nicht so ist **. Der Hintergrund von img_rot45, der einen RGB-Hintergrund für den RGBA-Vordergrund spezifizierte, und img_rot47, der kein Hintergrundbild für den RGBA-Vordergrund spezifizierte, wurde transparent. In beiden Fällen scheint dem A-Element "0" hinzugefügt worden zu sein.

Kurz gesagt, die weltliche Schlussfolgerung ist, dass es ratsam ist, es nicht unerwartet zu verwenden.

img_rot45 img_rot46 img_rot47
uchuhikoushi45.png uchuhikoushi46.png uchuhikoushi47.png

Verwenden Sie für Sprites

Wie oben erwähnt, habe ich unter Bezugnahme auf den Artikel meines Vorgängers darüber nachgedacht, ein RGBA-Bild einschließlich Transparenz in das Bild einzufügen, aber es war unmöglich zu schließen. Attraktiv sind jedoch die Spezifikationen, die auch dann keinen Fehler verursachen, wenn sie über das Hintergrundbild hinausgehen. Aus diesem Grund habe ich beschlossen, die bisherige Maskenmethode mit der Affin-Konvertierung zu kombinieren. Dann ... ist es geschafft, super einfach. Es gibt keine Probleme mit dem extrinsischen Quadrat oder dem ROI.

Quelle


import cv2

def makeSampleImg(img4):
    h, w = img4.shape[:2]
    cv2.rectangle(img4, (0,0), (w-1,h-1), (0,0,255,255), 1)
    return img4

def putSprite_Affine(back, front4, pos, angle=0, center=(0,0)):
    x, y = pos
    front3 = front4[:, :, :3]
    mask1 =  front4[:, :, 3]
    mask3 = 255- cv2.merge((mask1, mask1, mask1))
    bh, bw = back.shape[:2]

    M = cv2.getRotationMatrix2D(center, angle, 1)
    M[0][2] += x
    M[1][2] += y
    front_rot = cv2.warpAffine(front3, M, (bw,bh))
    mask_rot = cv2.warpAffine(mask3, M, (bw,bh), borderValue=(255,255,255))
    tmp = cv2.bitwise_and(back, mask_rot)
    result = cv2.bitwise_or(tmp, front_rot)
    return result

if __name__ == "__main__":
    filename_front = "uchuhikoushi.png "
    filename_back = "space.jpg "
    img_front = cv2.imread(filename_front, -1)
    img_front = makeSampleImg(img_front)  #Fügen Sie dem RGBA-Image einen Frame hinzu (nicht erforderlich)
    img_back = cv2.imread(filename_back)

    pos = [(0, 50), (300,200), (400,400), (500,-50), (-100,1000)] #Obere linke Koordinate, um das Bild zu platzieren
    xc, yc = 140, 60  #Drehpunkt des Vordergrundbildes
    angle = 0

    while True:
        img = img_back.copy()
        for x,y in pos:
            img = putSprite_Affine(img, img_front, (x,y), angle, (xc,yc))

            #Stellen Sie sicher, dass es korrekt dargestellt wird (nicht erforderlich).
            cv2.circle(img, (x,y), 5, (0,255,0), -1)       #Markieren Sie oben links im Vordergrundbild
            cv2.circle(img, (x+xc,y+yc), 5, (0,0,255), -1) #Markieren Sie in der Mitte der Drehung
            cv2.putText(img, f"angle={angle}", (10,440), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)

        cv2.imshow("putSprite_Affine", img)

        key = cv2.waitKey(1) & 0xFF
        if key == ord("q"):
            break
        angle = (angle + 30) % 360

    cv2.destroyAllWindows()

Apropos Nachteile: Der Rechenaufwand ist nutzlos groß, da das Maskenbild und das RGB-Bild in das gesamte Hintergrundbild konvertiert werden ("Overhead. AA% E3% 83% BC% E3% 83% 90% E3% 83% BC% E3% 83% 98% E3% 83% 83% E3% 83% 89) scheint groß zu sein. "

Vorderseite in der Mitte der Zeichnung_rot
front_rot.png
Maske mitten in der Zeichnung_rot
mask_rot.png
Ergebnis
Hier wird das vorherige Anime-GIF gepostet, aber in Wirklichkeit dreht sich der Charakter mit dem roten Rahmen.uchuhikoushi_anim_3.gif

Nun wollen wir sehen, wie sich dies auf die Ausführungsgeschwindigkeit auswirkt.

Am Ende

Es ist noch nicht vorbei.

Recommended Posts

Sprites mit OpenCV # 2 drehen ~ Mastering cv2.warpAffine () ~
Sprites mit OpenCV drehen
Drehen Sie das Sprite mit OpenCV # 3 ~ Berechnen Sie es selbst, ohne es anderen zu überlassen ~
Katze zurück mit OpenCV erkennen
Binarisierung mit OpenCV / Python
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