L'article précédent "Faire pivoter les sprites avec OpenCV" ne pouvait pas être terminé pendant les vacances d'été, et j'ai réussi à le diviser en utilisant le week-end.
Cependant, le lendemain de son téléchargement, une nouvelle idée m'est venue. Après tout, l'environnement avec de nombreuses tentations n'est pas bon. Vous devez vous mettre dans un environnement plus difficile pour étudier. Lieu de travail. </ grève>
Il y avait un argument intéressant non essentiel de cv2.warpAffine ()
que j'ai omis la dernière fois.
Article de référence: Dessinez une autre image sur une image avec OpenCV
--src Image d'origine. Obligatoire.
-M matrice de conversion 2 * 3. Obligatoire.
--dsize Spécifiez la taille de l'image de sortie avec une touche de (largeur, hauteur)
. Obligatoire.
--dst image d'arrière-plan (en dehors de l'image d'origine). La taille doit être la même que dsize.
--flags Méthode de complément d'image. La valeur par défaut est «cv2.INTER_LINEAR». De plus, cv2.INTER_NEAREST
etc.
--BorderMode Méthode de traitement de l'arrière-plan (en dehors de l'image d'origine). La valeur par défaut est «cv2.BORDER_CONSTANT».
--BorderValue La couleur lorsque borderMode = cv2.BORDER_CONSTANT
. La valeur par défaut est «0». Voir ci-dessous.
Créez une petite fonction pour rendre le résultat du traitement d'image facile à comprendre. Veuillez noter que seule la partie minimale est décrite.
python
def makeSampleImg(img4): #Apportez une image RGBA 4 canaux
h, w = img.shape[:2]
#A ainsi que la coloration des environs=C'est une erreur d'en faire 255 (opaque)
cv2.rectangle(img, (0,0), (w-1,h-1), (0,0,255,255), 1)
return img
img_origin = cv2.imread(filename, -1) #Image RGBA
img4 = makeSampleImg(img_origin)
img3 = img4[:, :, :3] #Éliminez l'élément A et faites-en une image RVB
L'image originale | Petit traitement | 3 canaux |
---|---|---|
Faites de l'arrière-plan une couleur unique avec borderMode = cv2.BORDER_CONSTANT
. Comme il s'agit de la valeur par défaut de borderMode
, il n'est pas nécessaire de se soucier de la décrire.
Je vais en essayer.
Spécifiez la couleur d'arrière-plan
M = cv2.getRotationMatrix2D((w/2,h/2), 30, 1)
img_rot31 = cv2.warpAffine(img3, M, (w, h), borderValue=(255,255,0)) #RVB de premier plan, RVB d'arrière-plan
img_rot32 = cv2.warpAffine(img3, M, (w, h), borderValue=(255,255,0,0)) #RVB de premier plan, arrière-plan RVBA (composant A = 0)
img_rot33 = cv2.warpAffine(img3, M, (w, h)) #RVB de premier plan, aucun arrière-plan spécifié
img_rot41 = cv2.warpAffine(img4, M, (w, h), borderValue=(255,255,0)) #RGBA de premier plan, arrière-plan RGB
img_rot42 = cv2.warpAffine(img4, M, (w, h), borderValue=(255,255,0,0)) #RGBA de premier plan, RGBA d'arrière-plan (composant A = 0)
img_rot43 = cv2.warpAffine(img4, M, (w, h)) #RGBA de premier plan, aucun arrière-plan spécifié
img_rot44 = cv2.warpAffine(img4, M, (w, h), borderValue=(255,255,0,255)) #RGBA de premier plan, RGBA d'arrière-plan (avec composant A)
** Si le premier plan est une image RVB **, le composant A est ignoré même si 4 canaux RVBA sont spécifiés comme couleur d'arrière-plan (img_rot32).
Il faut comprendre que si borderValue n'est pas spécifié, l'arrière-plan sera noir (img_rot33, ou par défaut), mais la couleur d'arrière-plan sera (0,0,0)
.
img_rot31 | img_rot32 | img_rot33 |
---|---|---|
** Si le premier plan est une image RGBA **, le résultat de sortie sera de 4 canaux RGBA même si 3 canaux RVB sont spécifiés comme couleur d'arrière-plan. La composante A donnée à ce moment est «0». Puisque A est l'opacité, pas la transparence, c'est «0», ce qui signifie que même si une valeur BGR qui n'était pas RVB… est définie, elle sera transparente en conséquence (img_rot41). Même si borderValue n'est pas spécifié, l'arrière-plan devient transparent (img_rot43), mais il est facile à comprendre si vous pensez que la couleur d'arrière-plan sera (0,0,0,0)
.
Bien sûr, si vous définissez une valeur autre que «0» pour le composant A, il sera correctement coloré (img_rot44).
img_rot41 | img_rot42 | img_rot43 | img_rot44 |
---|---|---|---|
Si vous définissez borderMode = cv2.BORDER_TRANSPARENT
, vous pouvez spécifier l'image d'arrière-plan avec dst
.
Comme c'est souvent le cas avec OpenCV, lorsque cv2.warpAffine ()
est utilisé, l'image d'arrière-plan spécifiée par dst
est traitée. Si vous avez besoin de conserver l'image d'origine, vous devez définir dst = back.copy ()
.
Je m'attendais à ce que ce soit transparent car il était TRANSPARENT, donc si je ne spécifiais pas dst
, ce serait un arrière-plan transparent, mais ce n'était pas si facile. Oh, d'une manière ou d'une autre, je veux manger Ikura.
Spécifiez l'image d'arrière-plan
back = cv2.imread(back_name) #Image RVB de la même taille que l'image de premier plan
back4 = cv2.cvtColor(back, cv2.COLOR_BGR2BGRA) #Créer une image RGBA Un composant est 255 au lieu de 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()) #RVB de premier plan, RVB d'arrière-plan
img_rot36 = cv2.warpAffine(img3, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT, dst=back4.copy()) #RVB de premier plan, arrière-plan RVBA
img_rot37 = cv2.warpAffine(img3, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT) #RVB de premier plan, aucun arrière-plan spécifié
img_rot45 = cv2.warpAffine(img4, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT, dst=back.copy()) #RGBA de premier plan, arrière-plan RGB
img_rot46 = cv2.warpAffine(img4, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT, dst=back4.copy()) #RGBA de premier plan, arrière-plan RGBA
img_rot47 = cv2.warpAffine(img4, M, (w, h), borderMode=cv2.BORDER_TRANSPARENT) #RGBA de premier plan, aucun arrière-plan spécifié
Le premier plan et l'arrière-plan se sont comportés comme prévu avec l'image RVB (img_rot35).
Si je ne spécifiais pas d'image d'arrière-plan au premier plan RVB, le résultat changeait à chaque fois que je l'exécutais (img_rot37). numpy
a une fonction appelée numpy.empty ()
qui crée un tableau non initialisé. L'image d'arrière-plan (ou plutôt le tableau numpy) peut avoir été créée avec les mêmes spécifications ici aussi.
Je ne sais pas pourquoi img_rot36, qui spécifiait l'arrière-plan RGBA au premier plan RVB, s'est transformé en fond noir avec de la poussière.
img_rot35 | img_rot36 | img_rot37 partie 1 | img_rot37 partie 2 |
---|---|---|---|
L'image RGBA (img_rot46) pour le premier plan et l'arrière-plan est comme prévu, mais c'est aussi un résultat décevant. J'étais content si l'arrière-plan était affiché dans la partie transparente du premier plan, mais cela ne peut pas être aidé car ** la conversion Affin n'est pas ce genre de chose en premier lieu **. L'arrière-plan de img_rot45, qui spécifiait un arrière-plan RVB pour le premier plan RGBA, et img_rot47, qui ne spécifiait pas d'image d'arrière-plan pour le premier plan RGBA, est devenu transparent. Dans les deux cas, il semble que «0» ait été ajouté à l'élément A.
En bref, la conclusion banale est qu'il est sage de ne pas l'utiliser de manière inattendue.
img_rot45 | img_rot46 | img_rot47 |
---|---|---|
Comme mentionné ci-dessus, en référence à l'article de mon prédécesseur, j'ai pensé à coller une image RGBA avec transparence sur l'image, mais il était impossible de conclure. Cependant, les spécifications qui ne provoquent pas d'erreur même si elle s'étend au-delà de l'image de fond sont attrayantes. Par conséquent, j'ai décidé de combiner la méthode du masque que j'ai fait jusqu'à présent avec la conversion Affin. Ensuite ... c'est fait, super facile. Il n'y a pas de problème avec le carré extrinsèque ou le retour sur investissement.
La source
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) #Ajouter un cadre à l'image RGBA (non requis)
img_back = cv2.imread(filename_back)
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:
img = img_back.copy()
for x,y in pos:
img = putSprite_Affine(img, 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_Affine", img)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
angle = (angle + 30) % 360
cv2.destroyAllWindows()
En parlant d'inconvénients, la quantité de calcul est inutilement importante car l'image du masque et l'image RVB sont converties en l'image d'arrière-plan entière ("[Overhead](https://ja.wikipedia.org/wiki/%E3%82%]" AA% E3% 83% BC% E3% 83% 90% E3% 83% BC% E3% 83% 98% E3% 83% 83% E3% 83% 89) semble être grand. "
Devant au milieu du dessin_rot |
---|
Masque au milieu du dessin_rot |
résultat |
Ici, le GIF animé précédent est posté, mais en réalité, le personnage avec le cadre rouge tourne. |
Voyons maintenant comment cela affecte la vitesse d'exécution.
Ce n'est pas encore fini.
Recommended Posts