Cette fois, je modifie le programme précédent, mais à ce moment-là, je change également les noms de variables, etc. en détail.
À propos de la fonction de superposition de type sprite de l'ancien ordinateur personnel de loisir putSprite(back, front4, pos, angle=0, home=(0,0)) Et. L'expression est presque la même que les articles précédents, mais la signification de l'argument est modifiée.
(0,0)
.Je pense que celui-ci est plus facile à utiliser.
C'est difficile à animer à chaque fois, alors j'ai fait ça.
sample.py
import cv2
import numpy as np
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(img_back, img_front, pos, angle=0, home=(0,0)):
#Mettez en œuvre de différentes manières et choisissez la meilleure.
pass
def main():
img_front = cv2.imread("uchuhikoushi.png ", -1)
img_front = makeSampleImg(img_front)
img_back = cv2.imread("space.jpg ", -1)
pos = (100,80)
home = (140,60)
angle = 30
#C'est le principal. Modifiez le nom de la fonction selon vos besoins
img = putSprite(img_back.copy(), img_front, pos, angle, home)
cv2.circle(img, pos, 5, (0,0,255), -1) #Mêmes coordonnées(pos)Tracez un cercle
cv2.imshow("rotation", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
Le résultat est le suivant. Devrait être.
résultat |
---|
Dans "Faire pivoter les sprites avec OpenCV", je n'ai pas pu trouver les coordonnées en haut à gauche de l'image pivotée, mais j'ai réussi à le calculer après cela. Comme je le savais, c'était des mathématiques de niveau secondaire.
putSprite_calc
def putSprite_calc(back, front4, pos, angle=0, home=(0,0)):
fh, fw = front4.shape[:2]
bh, bw = back.shape[:2]
x, y = pos
xc, yc = home[0] - fw/2, home[1] - fh/2 #Changer le point d'origine de la référence supérieure gauche à la référence du centre de l'image
a = np.radians(angle)
cos , sin = np.cos(a), np.sin(a) #Cette fonction triangulaire apparaît plusieurs fois, alors faites-en une variable
w_rot = int(fw * abs(cos) + fh * abs(sin))
h_rot = int(fw * abs(sin) + fh * abs(cos))
M = cv2.getRotationMatrix2D((fw/2,fh/2), angle, 1) #Rotation au centre de l'image
M[0][2] += w_rot/2 - fw/2
M[1][2] += h_rot/2 - fh/2
imgRot = cv2.warpAffine(front4, M, (w_rot,h_rot)) #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
xc_rot = xc * cos + yc * sin #Quantité de mouvement lors de la rotation au centre de l'image
yc_rot = -xc * sin + yc * cos
x0 = int(x - xc_rot - w_rot / 2) #Coordonnée supérieure gauche du carré circonscrit
y0 = int(y - yc_rot - h_rot / 2)
if not ((-w_rot < x0 < bw) and (-h_rot < 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 + w_rot, bw), min(y0 + h_rot, 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
result = back.copy()
front = imgRot[:, :, :3]
mask1 = imgRot[:, :, 3]
mask = 255 - cv2.merge((mask1, mask1, mask1))
roi = result[y1:y2, x1:x2]
tmp = cv2.bitwise_and(roi, mask)
tmp = cv2.bitwise_or(tmp, front)
result[y1:y2, x1:x2] = tmp
return result
imgRot |
---|
"Faire pivoter les sprites avec OpenCV" a fini par utiliser un carré inutilement grand avec des relations dimensionnelles connues. La fonction à ce moment est modifiée selon cette spécification.
putSprite_mask2 break
def putSprite_mask2(back, front4, pos, angle=0, home=(0,0)):
fh, fw = front4.shape[:2]
bh, bw = back.shape[:2]
x, y = pos
xc, yc = home
#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))))
#Carré contenant une image pivotée
M = cv2.getRotationMatrix2D((xc,yc), angle, 1) #Rotation à la maison
M[0][2] += r - xc
M[1][2] += r - yc
imgRot = cv2.warpAffine(front4, M, (2*r,2*r)) #Carré contenant une image pivotée
#Ne rien faire si le carré entier est en dehors de l'image d'arrière-plan
x0, y0 = x-r, y-r
if not ((-2*r < x0 < bw) and (-2*r < y0 < bh)) :
return back
#Obtenez uniquement l'image d'arrière-plan du rectangle
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
result = back.copy()
front = imgRot[:, :, :3]
mask1 = imgRot[:, :, 3]
mask = 255 - cv2.merge((mask1, mask1, mask1))
roi = result[y1:y2, x1:x2]
tmp = cv2.bitwise_and(roi, mask)
tmp = cv2.bitwise_or(tmp, front)
result[y1:y2, x1:x2] = tmp
return result
imgRot |
---|
Quand je me demandais si je pouvais obtenir le plus petit carré circonscrit de ce carré inutilement grand par programmation plutôt que mathématiquement, j'ai trouvé l'article que je cherchais.
J'allais m'en occuper si je ne pouvais pas résoudre le problème de la figure jusqu'au bout.
imgRot | Minimiser |
---|---|
"Faire pivoter les sprites avec OpenCV # 2 ~ Maîtriser cv2.warpAffine () ~" Modifions également le programme. Puisque la taille de l'image pendant la rotation est égale à celle de l'image d'arrière-plan, la vitesse d'exécution ralentira dès que vous essayez de placer de nombreux petits sprites sur la grande image d'arrière-plan.
imgRot |
---|
putSprite_Affine2
def putSprite_Affine2(back, front4, pos, angle=0, home=(0,0)):
x, y = pos
xc, yc = home
front3 = front4[:, :, :3]
mask1 = front4[:, :, 3]
mask3 = 255- cv2.merge((mask1, mask1, mask1))
bh, bw = back.shape[:2]
M = cv2.getRotationMatrix2D(home, angle, 1)
M[0][2] += x - xc #Le seul point de changement est ici où la définition de pos a été modifiée.
M[1][2] += y - yc #Cv2 ne nécessite pas de calcul supplémentaire.warpAffine()Forces.
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
Ajoutez un élément de rotation au programme de comparaison créé dans Gestion des images transparentes avec OpenCV-Making sprites dance- et exécutez-le.
rot_test.py
import cv2
import numpy as np
import time
# def makeSampleImg(img4)Est inutile
def putSprite_calc(back, front4, pos, angle=0, home=(0,0)):
#Ceux énumérés ci-dessus
def putSprite_mask2(back, front4, pos, angle=0, home=(0,0)):
#Ceux énumérés ci-dessus
def putSprite_Affine2(back, front4, pos, angle=0, home=(0,0)):
#Ceux énumérés ci-dessus
def main(func):
filename_back = "space.jpg "
filename_front = "uchuhikoushi.png "
img_back = cv2.imread(filename_back)
img_front = cv2.imread(filename_front, -1)
bh, bw = img_back.shape[:2]
xc, yc = bw//2, bh//2
rx, ry = bw*0.3, bh*0.4
home = (140,60)
cv2.putText(img_back, func, (20,bh-20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255))
###Commencez à partir d'ici pour mesurer le temps
start_time = time.time()
for angle in range(-180, 180, 10):
back = img_back.copy()
x = int(xc + rx * np.cos(np.radians(angle)))
y = int(yc + ry * np.sin(np.radians(angle)))
img = eval(func)(img_back, img_front, (x,y), angle=angle, home=home)
#Cela peut être activé ou désactivé selon les besoins
#cv2.imshow(func, img)
#cv2.waitKey(1)
elasped_time = time.time() - start_time
###Jusque là
print (f"{func} : {elasped_time} sec")
cv2.destroyAllWindows()
if __name__ == "__main__":
funcs = ["putSprite_calc",
"putSprite_mask2",
"putSprite_Affine2" ]
for func in funcs:
for i in range(10):
main(func)
L'animation créée est à peu près celle illustrée ci-dessous, bien que divers éléments aient été ajoutés par souci de clarté.
résultat |
---|
Le temps qu'il faut pour traiter cela est dans mon environnement.
python
putSprite_calc : 0.12500691413879395 sec
putSprite_mask2 : 0.27501583099365234 sec
putSprite_Affine2 : 0.5620322227478027 sec
Comme je le savais, plus la zone de retour sur investissement est petite, plus la vitesse d'exécution est rapide. La taille du ROI est directement liée à la quantité de calcul des canaux verticaux x horizontaux x RVB 3, donc juste parce qu'OpenCV fait du bon travail, si vous utilisez un ROI excessivement important, il ralentira rapidement.
Maintenant que je suis arrivé jusqu'ici, je veux créer un jeu. Je dois également étudier l'apprentissage profond. S'il est lié de force à l'apprentissage en profondeur, il sera possible de réduire la quantité de calcul en réduisant bien la taille même lors du passage à l'apprentissage profond.