Dieses Mal ändere ich das vorherige Programm, aber zu diesem Zeitpunkt ändere ich auch die Variablennamen usw. im Detail.
Über die Sprite-ähnliche Überlagerungsfunktion des alten Hobby-PCs putSprite(back, front4, pos, angle=0, home=(0,0)) Und. Der Ausdruck ist fast der gleiche wie in den vorherigen Artikeln, aber die Bedeutung des Arguments wird geändert.
Ich denke, dieser ist einfacher zu bedienen.
Es ist jedes Mal mühsam zu animieren, also habe ich das gemacht.
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)):
#Implementieren Sie auf verschiedene Arten und wählen Sie die beste aus.
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
#Dies ist die Hauptsache. Ändern Sie den Funktionsnamen nach Bedarf
img = putSprite(img_back.copy(), img_front, pos, angle, home)
cv2.circle(img, pos, 5, (0,0,255), -1) #Gleiche Koordinaten(pos)Zeichne einen Kreis
cv2.imshow("rotation", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
Das Ergebnis ist dies. Sollte sein.
Ergebnis |
---|
In "Sprites mit OpenCV drehen" konnte ich die oberen linken Koordinaten des gedrehten Bildes nicht finden, aber ich konnte sie danach berechnen. Wie ich wusste, war es Mathematik auf Highschool-Niveau.
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 #Wechseln Sie von der Referenz oben links zur Referenz für die Bildmitte nach Hause
a = np.radians(angle)
cos , sin = np.cos(a), np.sin(a) #Diese Dreiecksfunktion wird häufig angezeigt. Machen Sie sie daher zu einer Variablen
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) #In der Bildmitte drehen
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)) #Externes Viereck mit gedrehtem Bild
#Tun Sie nichts, wenn sich das gesamte äußere Quadrat außerhalb des Hintergrundbilds befindet
xc_rot = xc * cos + yc * sin #Bewegungsumfang beim Drehen in der Bildmitte
yc_rot = -xc * sin + yc * cos
x0 = int(x - xc_rot - w_rot / 2) #Obere linke Koordinate des umschreibenden Quadrats
y0 = int(y - yc_rot - h_rot / 2)
if not ((-w_rot < x0 < bw) and (-h_rot < y0 < bh)) :
return back
#Holen Sie sich nur das Hintergrundbild des äußeren Quadrats
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]
#Kombinieren Sie das umschreibende Viereck und den Hintergrund mit der Maskenmethode
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 |
---|
In "Sprites mit OpenCV drehen" habe ich ein nutzlos großes Quadrat mit bekannten Dimensionsbeziehungen verwendet. Die Funktion zu diesem Zeitpunkt wird an diese Spezifikation geändert.
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
#Finden Sie den Maximalwert des Abstands zwischen dem Drehpunkt und den vier Ecken
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))))
#Quadrat mit gedrehtem Bild
M = cv2.getRotationMatrix2D((xc,yc), angle, 1) #Zu Hause drehen
M[0][2] += r - xc
M[1][2] += r - yc
imgRot = cv2.warpAffine(front4, M, (2*r,2*r)) #Quadrat mit gedrehtem Bild
#Tun Sie nichts, wenn sich das gesamte Quadrat außerhalb des Hintergrundbilds befindet
x0, y0 = x-r, y-r
if not ((-2*r < x0 < bw) and (-2*r < y0 < bh)) :
return back
#Holen Sie sich nur das Hintergrundbild des Rechtecks
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]
#Kombinieren Sie das umschreibende Viereck und den Hintergrund mit der Maskenmethode
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 |
---|
Als ich mich fragte, ob ich das kleinste umschreibende Quadrat aus diesem nutzlos großen Quadrat programmatisch und nicht mathematisch erhalten könnte, fand ich den Artikel, den ich suchte.
Ich würde mich darum kümmern, wenn ich das Figurenproblem nicht bis zum Ende lösen könnte.
imgRot | Minimieren |
---|---|
"Sprites mit OpenCV # 2 drehen ~ cv2.warpAffine () ~ beherrschen" Lassen Sie uns auch das Programm ändern. Da die Bildgröße während der Drehung der des Hintergrundbilds entspricht, sinkt die Ausführungsgeschwindigkeit sofort, wenn Sie versuchen, viele kleine Sprites auf einem großen Hintergrundbild zu platzieren.
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 #Der einzige Änderungspunkt ist hier, wo die Definition von pos geändert wurde.
M[1][2] += y - yc #Cv2 erfordert keine zusätzliche Berechnung.warpAffine()Stärken.
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
Fügen Sie dem in Umgang mit transparenten Bildern mit OpenCV-Making Sprites Dance- erstellten Vergleichsprogramm ein Rotationselement hinzu und führen Sie es aus.
rot_test.py
import cv2
import numpy as np
import time
# def makeSampleImg(img4)Ist unnötig
def putSprite_calc(back, front4, pos, angle=0, home=(0,0)):
#Die oben aufgeführten
def putSprite_mask2(back, front4, pos, angle=0, home=(0,0)):
#Die oben aufgeführten
def putSprite_Affine2(back, front4, pos, angle=0, home=(0,0)):
#Die oben aufgeführten
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))
###Beginnen Sie von hier aus, um die Zeit zu messen
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)
#Dies kann nach Bedarf aktiviert oder deaktiviert werden
#cv2.imshow(func, img)
#cv2.waitKey(1)
elasped_time = time.time() - start_time
###Bisher
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)
Die erstellte Animation entspricht in etwa der folgenden Abbildung, obwohl der Übersichtlichkeit halber verschiedene Elemente hinzugefügt wurden.
Ergebnis |
---|
Die Zeit, die benötigt wird, um dies zu verarbeiten, ist in meiner Umgebung.
python
putSprite_calc : 0.12500691413879395 sec
putSprite_mask2 : 0.27501583099365234 sec
putSprite_Affine2 : 0.5620322227478027 sec
Wie ich wusste, ist die Ausführungsgeschwindigkeit umso schneller, je kleiner der ROI-Bereich ist. Die Größe des ROI hängt direkt mit dem Rechenaufwand für vertikale x horizontale x RGB 3-Kanäle zusammen. Nur weil OpenCV gute Arbeit leistet, verlangsamt sich der ROI schnell, wenn Sie einen verschwenderisch großen ROI verwenden.
Jetzt, wo ich es bisher geschafft habe, möchte ich ein Spiel machen. Ich muss auch tiefes Lernen lernen. Wenn es zwangsweise mit Deep Learning zusammenhängt, ist es möglich, den Rechenaufwand zu reduzieren, indem die Größe auch beim Deep Learning deutlich reduziert wird.