Rotate an image around its x-axis

醉酒当歌 提交于 2020-05-28 06:09:47

问题


I need to rotate an image around its x-axis (or y-axis). I can easily create such an animation with avisynth, but now I need to implement that effect with Python's moviepy module. I can easily rotate an image with the following script but need some clues how to rotate it in 2D or 3D.

from moviepy.editor import *

clip = ImageClip('my_image.jpg')
rotated_clip = (clip.add_mask()
                .fx(vfx.resize, width=300, height=300)
                .fx(vfx.rotate, lambda t: 90*t, expand=False)
                .set_duration(5))
final_clip = CompositeVideoClip([rotated_clip.set_pos("center")], size=(800,800), bg_color=3*[255])
final_clip.write_videofile("test.mp4", fps=25, codec="libx264")

Here is the avisynth script that actually generated that example image. Please note, it does require "QUAD" plugin.

function stars(clip c, int r) {
    c.Overlay(x=rand(c.width),y=rand(c.height),BlankClip(c,width=1,height=1,color=$030301*rand(85)))
    (r==0)? last : stars(r-1)
    Trim(0,-1).Loop(c.Framecount, 0, 0)
}
width= 800
height=600
length=100000
Tcolor=$000040
Bcolor=$000018

StackVertical(BlankClip(length=length,width=2,height=1,color=TColor,pixel_type="RGB32"),BlankClip(length=length,width=2,height=1,color=BColor)).BilinearResize(width,2*height,src_top=0,src_height=2).Crop(0,height/2,0,-height/2).Stars(width*height/3072)

ImageSource("path_to_image.png", start=0, end=total_time, fps=300, pixel_type="RGB32")
#BlankClip(length=length,FPS=25,width=640,height=480,color=$000018,pixel_type="RGB32")

#ColorBars()
HALFCYCLE=10                        # Frames in 1 HALF rotation (spinning clip)
NSPIN   = 1                         # Number of HALF rotations in spinning clip
NSTILL  = 10                        # Frames in STILL clip
V       = 0.2                       # Tilt/Yaw
tim     = PI / HALFCYCLE

ScriptClip("""

    c=last
    t=tim*current_frame
    t1x= 0.5 -  0.5 * cos(t)        # BOTH Left
    t2x= 0.5 +  0.5 * cos(t)        # BOTH Right
    #
    t1y= 0.0 +  V * sin(t)          # ] both Top's opposite sign
    t2y= 0.0 -  V * sin(t)          # ] 
    t3y= 1.0 +  V * sin(t)          # [ both Bottoms opposite sign
    t4y= 1.0 -  V * sin(t)          # [
    ResetMask
    quad(t1x,t1y, t2x,t2y, t2x,t3y, t1x,t4y,  normal=true)
    #Overlay(c,last,mask=last.ShowAlpha())


""")

SPIN=Trim(0,-(NSPIN*HALFCYCLE +1))     # Spinning clip, + 1 to complete last spin
STILL=SPIN.Trim(SPIN.FrameCount-1,-1).Loop(NSTILL,0,0)
SPIN2=Trim((NSPIN%2 ==0)?0:HALFCYCLE,-(NSPIN*HALFCYCLE +1))
SPIN ++ STILL ++ SPIN2
Return Last

回答1:


One way to do this is to use Vapory, another library by the author of MoviePy, which facilitates the operation of POV-Ray via Python. You can create a rectangle within a 3D scene and rotate it around whatever axis you like, saving frames into a MoviePy clip at intervals.

MoviePy + Vapory code

from moviepy.editor import concatenate, ImageClip, VideoClip
from vapory import *

img_path = './baseball.png'
img_clip = ImageClip(img_path)
W, H = img_clip.w, img_clip.h
AR = 1.0*W/H

# Set rotation rate by defining the period (in seconds) for 360 deg. revolution
t_rev = 2.0

t_half = t_rev/2.0  # The time required for a half revolution
t_still = 0.8 # How long (in seconds) to hold the half rotated image still


# Static POV-Ray objects
cam = Camera('location', [ 0,  0, -1],
             'look_at',  [ 0,  0,  0])
light = LightSource([0, 0, -1]) # Light at camera location
bg = Background('color', [0, 0, 0]) # Black background


def scene(t):
    """ Returns the scene at time 't' (in seconds) """
    s = Scene(camera = cam, objects = [light, bg])

    # Add POV-Ray box with image textured on it
    s = s.add_objects([
          Box([0, 0, 0],
              [W, H, 0],
              Texture(Pigment(ImageMap('"{}"'.format(img_path), 'once')),
                      Finish('ambient', 1.0)),
              'translate', [-0.5, -0.5, 0],
              'scale', [AR, 1, 0],
              'rotate', [0, (360/t_rev)*t, 0])]) # Can change axis of rotation here
    return s


def make_frame(t):
    return scene(t).render(width=W, height=H, antialiasing=0.1)


still_1 = VideoClip(make_frame).to_ImageClip(t=0).set_duration(t_still)
half_1  = VideoClip(make_frame).subclip(0, t_half)
still_2 = VideoClip(make_frame).to_ImageClip(t=t_half).set_duration(t_still)
half_2  = VideoClip(make_frame).subclip(t_half, t_rev)

final_clip = concatenate([still_1, half_1, still_2, half_2])
final_clip.write_gif("./baseball_rot.gif", fps=15)

Output GIF

Other thoughts:

The main things you might want to change are img_path, t_rev (the time for a full 360 degree revolution), t_still, and the output frame rate.

I removed one column of pixels from your example image to get it down to an even width (150 px). It's not important if you only want to make GIFs, but if you want to produce an x264-encoded MP4, you should probably use mod2 dimensions.

It seems like overkill to use a ray tracer for this problem, but it's the first working solution I came up with. I wanted to represent the image as a 2D rectangle in a 3D scene, where I could simply specify an angle of rotation and the 3D library would handle the rest.

It should be possible to solve this problem using a projective transform from scikit-image, as in this MoviePy example. Note specifically, the trapzWarp function near the middle of that code listing.



来源:https://stackoverflow.com/questions/40186787/rotate-an-image-around-its-x-axis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!