[PYTHON] Faire pivoter les sprites avec OpenCV

introduction

Ceci est une suite de Gestion des images transparentes avec OpenCV-Making sprites dance-.

C'est excitant de faire pivoter le sprite. Je me souviens de la carte SYSTEM II de Namco. Assaut ou ordre. J'ai acheté Namco Museum VOL.4 avant d'acheter la PlayStation elle-même.

Faire pivoter l'image avec OpenCV

Dans OpenCV, vous pouvez faire pivoter l'image par incréments de 90 degrés avec cv2.rotate (), mais il n'y a pas de fonction pour la faire pivoter à n'importe quel angle. Il existe une fonction plus avancée, alors utilisez-la.

Etudier la conversion Affin

La transformation Affin est un mappage qui combine une transformation principale telle que la rotation et la mise à l'échelle avec un mouvement parallèle. En bref

\begin{pmatrix}
x' \\
y'
\end{pmatrix}
=
\begin{pmatrix}
a & b \\
d & e
\end{pmatrix}
\begin{pmatrix}
x \\
y
\end{pmatrix}
+
\begin{pmatrix}
c \\
f
\end{pmatrix}

C'est une conversion. Il est difficile de programmer sous cette forme

\begin{pmatrix}
x' \\
y' \\
1
\end{pmatrix}
=
\begin{pmatrix}
a & b & c \\
d & e & f \\
0 & 0 & 1
\end{pmatrix}
\begin{pmatrix}
x \\
y \\
1
\end{pmatrix}

Je vais l'exprimer comme. Le fond est quelque peu désagréable, mais il n'y a qu'une égalité de «1 = 1».

cette

\begin{pmatrix}
a & b & c \\
d & e & f \\
\end{pmatrix}

Est défini et appliqué à la fonction cv2.warpAffine (). Cependant, lors de la rotation de l'image, dérangez

\begin{pmatrix}
cosθ & -sinθ & 0 \\
sinθ & cosθ & 0 \\
\end{pmatrix}

Il n'est pas nécessaire de calculer. Vous pouvez utiliser la matrice obtenue par cv2.getRotationMatrix2D ().

Créer une matrice de rotation cv.getRotationMatrix2D (centre, angle, échelle)

Ajoutons le mouvement parallèle par vous-même.

Conversion affine des images cv.warpAffine (src, M, dsize)

--src Image d'origine. -M matrice de conversion 2 * 3. --dsize Spécifiez la taille de l'image de sortie avec une touche de (largeur, hauteur).

Entraine toi

Je me demande à quoi ressemble la matrice de conversion.

Source 1


import cv2
angle = 30  # degrees
M = cv2.getRotationMatrix2D((0,0), angle, 1)
print (M)
print (M.shape)
print (M.dtype)

Résultat 1


[[ 0.8660254  0.5        0.       ]
 [-0.5        0.8660254  0.       ]]
(2, 3)
float64

cos30 degrés = √3 / 2 = 0.8660254 ... C'est donc exactement ce qu'est la matrice de rotation ...? La position négative est différente, non? Apparemment, contrairement au plan xy utilisé en mathématiques, le calcul correspond à un système de coordonnées où le fond est positif.

Alors, convertissons l'image en utilisant ceci.

Source 2


import cv2

filename = "hoge.png "
img = cv2.imread(filename)
h, w = img.shape[:2]
center = (140,60)
angle = 0

while True:
    angle = (angle + 10) % 360
    M = cv2.getRotationMatrix2D(center, angle, 1)
    img_rot = cv2.warpAffine(img, M, (w, h))
    cv2.imshow(filename, img_rot)
    key = cv2.waitKey(100) & 0xFF
    if key == ord("q"):
        break
    
cv2.destroyAllWindows()

Le résultat est le suivant.

L'image originale résultat
uchuhikoushi_point.png uchuhikoushi_anim_0.gif

Je comprends l'angle de rotation et le centre de rotation, mais je veux dire: "Attendez une minute, l'image dépasse en premier lieu."

Évitez les surplombs

Comment éviter de sortir du lot? Je vais calculer quoi faire.

rot_cad_2.png

Lorsqu'un rectangle (rouge) dont les deux côtés sont w et h est incliné d'un angle a, la taille du quadrilatère circonscrit (bleu) est

python


rot_w = w*cos(a) + h*sin(a)
rot_h = w*sin(a) + h*cos(a)

Sera. Si la température s'écarte de 0 à 90 degrés, le sinus et le cosinus seront négatifs, donc pour être exact, chaque terme doit être une valeur absolue. Oh, je comprends enfin. Cette formule est apparue dans l'article des ancêtres décrit plus tard, et je me demandais en quoi elle était différente de la matrice de rotation.

Ainsi, vous pouvez déplacer la position en parallèle pour qu'elle tienne dans ce rectangle bleu. Puisque (0,0) est le centre de rotation, nous pensons en fonction du centre de l'image.

Source 3


import cv2
import numpy as np

filename = "hoge.png "
img = cv2.imread(filename)
h, w = img.shape[:2]
angle = 0

while True:
    angle = (angle + 10) % 360
    a = np.radians(angle)
    w_rot = int(np.round(w*abs(np.cos(a)) + h*abs(np.sin(a))))
    h_rot = int(np.round(w*abs(np.sin(a)) + h*abs(np.cos(a))))

    M = cv2.getRotationMatrix2D((w/2,h/2), angle, 1)
    M[0][2] += -w/2 + w_rot/2
    M[1][2] += -h/2 + h_rot/2

    img_rot  = cv2.warpAffine(img, M, (w_rot,h_rot))
    cv2.imshow(filename, img_rot)
    key = cv2.waitKey(100) & 0xFF
    if key == ord("q"):
        break
    
cv2.destroyAllWindows()

Le résultat est le suivant. L'image ne sort plus de la fenêtre, mais cela ne peut pas être aidé car l'animation est basée sur la restriction que la position de la fenêtre (position supérieure gauche de l'image) est commune.

uchuhikoushi_anim_1.gif

Spécifiez le centre de rotation

Afin de spécifier le centre et de le faire pivoter afin que l'image créée ne devienne pas sauvage, la taille de la toile sur laquelle l'image pivotée est dessinée doit être déterminée à l'avance. Trouver la taille du campus n'est pas difficile. De la distance entre le centre de rotation et les quatre coins, le plus grand correspond au rayon. La taille de la toile est le double. rot_cad_3.png

Probablement en bon état, la source suivante exprime la formule pour trouver le rayon en une seule ligne. Maintenant, il est difficile de comprendre quel genre de calcul je fais. Ce n'est pas bon de courir très habilement.

Source 4


import cv2
import numpy as np

filename = "hoge.png "
img = cv2.imread(filename)
h, w = img.shape[:2]
xc, yc = 140, 60 #Centre de rotation
angle = 0

#Trouvez la valeur maximale de la distance entre le centre de rotation et les quatre coins
pts = np.array([(0,0), (w,0), (w,h), (0,h)])
ctr = np.array([(xc,yc)])
r = np.sqrt(max(np.sum((pts-ctr)**2, axis=1)))
winH, winW = int(2*r), int(2*r)

while True:
    angle = (angle + 10) % 360
    M = cv2.getRotationMatrix2D((xc,yc), angle, 1)
    M[0][2] += r - xc
    M[1][2] += r - yc
    
    imgRot = cv2.warpAffine(img, M, (winW,winH))
    cv2.imshow("", imgRot)
    key = cv2.waitKey(100) & 0xFF
    if key == ord("q"):
        break

cv2.destroyAllWindows()

Le résultat est le suivant. uchuhikoushi_anim_2.gif

Combinez l'image pivotée avec l'image d'arrière-plan

Ajoutez le traitement ci-dessus à la fonction sprite de previous. Il aurait pu être préférable d'arrondir avec math.ceil () au lieu de ʻint () `.

Source 5


import cv2
import numpy as np

def putSprite_mask2(back, front4, pos, angle=0, center=(0,0)):
    x, y = pos
    xc, yc = center
    fh, fw = front4.shape[:2]
    bh, bw = back.shape[:2]

    #Trouvez la valeur maximale de la distance entre le centre de rotation et les quatre coins
    pts = np.array([(0,0), (fw,0), (fw,fh), (0,fh)])
    ctr = np.array([(xc,yc)])
    r = int(np.sqrt(max(np.sum((pts-ctr)**2, axis=1))))

    #Tourner
    M = cv2.getRotationMatrix2D((xc,yc), angle, 1)
    M[0][2] += r - xc
    M[1][2] += r - yc
    imgRot = cv2.warpAffine(front4, M, (2*r,2*r))  #Quadrilatère externe contenant une image pivotée

    #Ne rien faire si le carré extrinsèque entier est en dehors de l'image d'arrière-plan
    x0, y0 = x+xc-r, y+yc-r
    if not ((-2*r < x0 < bw) and (-2*r < y0 < bh)) :
        return back    

    #Obtenez uniquement l'image d'arrière-plan du carré extrinsèque
    x1, y1 = max(x0,  0), max(y0,  0)
    x2, y2 = min(x0+2*r, bw), min(y0+2*r, bh)
    imgRot = imgRot[y1-y0:y2-y0, x1-x0:x2-x0]

    #Combinez le quadrilatère circonscrit et l'arrière-plan avec la méthode du masque
    front_roi = imgRot[:, :, :3]
    mask1 = imgRot[:, :, 3]
    mask_roi = 255 - cv2.merge((mask1, mask1, mask1))
    roi = back[y1:y2, x1:x2]
    tmp = cv2.bitwise_and(roi, mask_roi)
    tmp = cv2.bitwise_or(tmp, front_roi)
    back[y1:y2, x1:x2] = tmp

    return back


if __name__ == "__main__":
    filename_back = "space.jpg "
    filename_front = "uchuhikoushi.png "
    img_back = cv2.imread(filename_back)
    img_front = cv2.imread(filename_front, -1)

    pos = [(0, 50), (300,200), (400,400), (500,-50), (-100,1000)] #Coordonnée en haut à gauche pour mettre l'image
    xc, yc = 140, 60  #Centre de rotation de l'image de premier plan
    angle = 0

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

            #Assurez-vous qu'il est correctement représenté (non requis)
            cv2.circle(img, (x,y), 5, (0,255,0), -1)       #Marque en haut à gauche de l'image de premier plan
            cv2.circle(img, (x+xc,y+yc), 5, (0,0,255), -1) #Marque au centre de rotation
            cv2.putText(img, f"angle={angle}", (10,440), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)

        cv2.imshow("putSprite_mask2", img)

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

C'est fait. uchuhikoushi_anim_3.gif

À la fin

En fait, je voulais obtenir le même comportement en minimisant le quadrilatère circonscrit et en contrôlant finement les coordonnées en haut à gauche, mais je ne pouvais pas bien résoudre les problèmes de figures et de matrices, c'est-à-dire au niveau des mathématiques du lycée. Il n'y en avait pas. Hein? Pourquoi ne fais-tu pas la queue au lycée maintenant? !!

Article de référence

Crée et enregistre une image qui pivote autour du centre de l'image d'origine selon l'angle spécifié. Comment éviter que la partie saillante ne soit coupée en faisant pivoter l'image d'opencv Comprendre complètement la conversion Affin

Recommended Posts

Faire pivoter les sprites avec OpenCV
Faire pivoter les sprites avec OpenCV # 2 ~ Maîtriser cv2.warpAffine () ~
Détecter le retour du chat avec OpenCV
Binarisation avec OpenCV / Python
Augmentation des données avec openCV
Faites pivoter le sprite avec OpenCV # 3 ~ Calculez-le vous-même sans le laisser aux autres ~
TopView facile avec OpenCV
Trébucher avec opencv3 de homebrew
Reconnaissance faciale avec OpenCV de Python
"Traitement Apple" avec OpenCV3 + Python3
Essayez la détection des bords avec OpenCV
Édition d'image avec python OpenCV
Capture de caméra avec Python + OpenCV
[Python] Utilisation d'OpenCV avec Python (basique)
Binariser les données photo avec OpenCV
Chargement de la vidéo en boucle avec opencv
Détection de visage avec Python + OpenCV
Obtenez des fonctionnalités d'image avec OpenCV
Reconnaissance faciale / coupe avec OpenCV
Essayez OpenCV avec Google Colaboratory
Création d'un classificateur en cascade avec opencv
Utiliser OpenCV avec Python @Mac
Reconnaissance d'image avec Keras + OpenCV
Détection de visage d'anime avec OpenCV
Briller la vie avec Python et OpenCV
Principes de base du traitement d'image en temps réel avec opencv
Dessinez des sprites non flous avec cocos2d / pyglet
[Python] Utilisation d'OpenCV avec Python (filtrage d'image)
Réseau neuronal avec OpenCV 3 et Python 3
[Python] Utilisation d'OpenCV avec Python (transformation d'image)
[Python] Utilisation d'OpenCV avec Python (détection des bords)
Effacez des couleurs spécifiques avec OpenCV + PySimpleGUI
Présentation d'OpenCV sur Mac avec homebrew
Programmation facile Python + OpenCV avec Canopy
Trouver les erreurs les plus simples avec OpenCV
[OpenCV] Identification personnelle avec photo du visage
Essayez la reconnaissance faciale avec python + OpenCV
Découpez le visage avec Python + OpenCV
Reconnaissance faciale avec caméra avec opencv3 + python2.7
Détection des fonctionnalités OpenCV avec Google Colaboratory
Recherche de mots composés à phase identique avec opencv
Charger une image gif avec Python + OpenCV
Détection de chat avec OpenCV (distribution de modèles)
Trouver la similitude d'image avec Python + OpenCV
Essayez de brouiller l'image avec opencv2
Utiliser OpenCV avec Python 3 dans Window
Dessinez une illustration avec Python + OpenCV
Suivre les balles de baseball avec Python + OpenCV
Segmentation basée sur un graphique avec Python + OpenCV
Reconnaissance d'objets avec openCV par traincascade
Dessinez des figures avec OpenCV et PIL
J'ai essayé la reconnaissance faciale avec OpenCV
Implémentation de la méthode de différence inter-trame avec OpenCV
Dessinez une flèche (vecteur) avec opencv / python
Etude de base d'OpenCV avec Python
Je veux détecter des objets avec OpenCV
Créer un lecteur vidéo avec PySimpleGUI + OpenCV
Enregistrer la vidéo image par image avec Python OpenCV
Essayez d'utiliser l'appareil photo avec OpenCV de Python
Capturer des images avec Pupil, python et OpenCV