How to scale up video with Python moviepy? - python

I am using Python 3.10 and moviepy library to process videos. I need to scale up (zoom) video without changing its resolution. There are a lot of example of using moviepy resize method, but it changes only the resolution.
Are there any options of scaling video with moviepy or maybe you can suggest some solutions with openCV?

For achieving zoomed in video, we may combine scaling and cropping.
Example:
from moviepy.editor import VideoFileClip
clip = VideoFileClip("input.mp4")
width, height = clip.size
resized_and_cropped_clip = clip.resize(2).crop(x1=width//2, y1=height//2, x2=width*3//2, y2=height*3//2)
resized_and_cropped_clip.write_videofile("output.mp4")
resize(2) - resize the video by a factor of 2 in each axis.
crop(x1=width//2, y1=height//2, x2=width*3//2, y2=height*3//2) - crop a rectangle with the original image size around the center of the resized video.
Alternately we may first crop and then resize.
It is more efficient, but may result minor degradation at the frame's margins:
from moviepy.editor import VideoFileClip
clip = VideoFileClip("input.mp4")
width, height = clip.size
resized_and_cropped_clip = clip.crop(x1=width//4, y1=height//4, x2=width*3//4, y2=height*3//4).resize(2)
resized_and_cropped_clip.write_videofile("output.mp4")
The above examples show zoom in by a factor of x2.
For zooming by other factor, we have to adjust the computation of x1, y1, x2, y2 arguments.

Related

Getting screen pixels taking into account the scale factor

I'm trying to get my screen size using python. I keep getting the incorrect value because my code is taking into account the scale factor. For example: My screen resolution is set to: 2736 x 1824. My scale factor is 200% so when I execute my code I get 1368 x 912.
import win32api
width = GetSystemMetrics(0)
height = GetSystemMetrics(1)
print('Width:', width)
print('Height:', height)
Is there any way I can get the resolution as shown in my windows settings without the scale factor? I want to be able to read 2736 x 1824.
import ctypes
scaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0) / 100
You can get the scale factor via shcore using ctypes.
Then from this you can calculate the real resolution.
ie: scaleFactor 1.25 is 125%
Your application is not DPI aware. Windows has to lie to the application about the dimensions and magnify the GUI to fit the scale.
A quick fix:
import ctypes
ctypes.windll.user32.SetProcessDPIAware()
For an executable it is recommended to set DPI awareness in the manifest file.

Set pygame surface DPI

I am rendering Mandelbrot fractal on a pygame surface from a numpy array.
When I generate a 10k px * 10k px image and save it using pylab in a 10 * 10 inch image with a 1000dpi I get a 10k pixels image which render pretty well when windows build in photo app display it with zoom ajustment.
In pygame, the image looks pretty ugly although it is displayed with the same size :
I'm using this code :
pygame.init()
display = pygame.display.set_mode((1000, 1000))
surf = pygame.surfarray.make_surface(gimage)
surf = pygame.transform.rotate(surf, 90)
surf = pygame.transform.scale(surf, (1000, 1000))
How would one set pygame image size and ajust DPI ?
scale() is "fast scale operation" and doesn't use resampling.
There is also smoothscale() which uses different algorythm.
Maybe it will give you better result.
You can also use PIL/Pillow to resize() with different methods of resampling.
You can also try to use CV2 to resize().
Yesterday there was question how to use CV2 with PyGame

How to properly scale/rotate images in pyqtgraph?

I have implemented pyqtgraph inside QGraphicsView in PyQt5. When I display the image the following way, it is stretched out and expands in the same aspect ratio as the screen. How do I fix this?
image = pg.ImageItem(asarray(Image.open('pic.png')) )
self.graphicsView.addItem(image)
image.rotate(270)
EDIT: found out how to rotate image, so I updated question with the solution. Now I am just trying to scale it properly.
You probably want something like:
import pyqtgraph as pg
from PIL import Image
from numpy import asarray
app = pg.mkQApp()
# Set up a window with ViewBox inside
gv = pg.GraphicsView()
vb = pg.ViewBox()
gv.setCentralItem(vb)
gv.show()
# configure view for images
vb.setAspectLocked()
vb.invertY()
# display image
img_data = asarray(Image.open('/home/luke/tmp/graph.png'))
image = pg.ImageItem(img_data, axisOrder='row-major')
vb.addItem(image)
The important pieces here that set the image scaling/orientation are:
using ImageItem(axisOrder='row-major') because image files are stored in row-major order
vb.invertY() because image files have the +y axis pointing downward
and vb.setAspectLocked() to keep the pixels square
I used np.rot90() instead, it's much faster and cythonable
image = pg.ImageItem(np.rot90(np.asarray(Image.open('pic.png'))))

Python/PyQt4: How do you find the SIZE of a monitor (in inches)?

I'm trying to find the horizontal width of a monitor in inches or cm (not pixels!) to make a small "ruler" program. DPI would work too.
I'm using PyQt4.
try using the QDesktopWidget's width() and height() to get the width and height respectively.
Class reference at QDesktopWidget Class Reference, this will give you the screens size in pixels and then use QX11Info.appDpiX, this will give you the DPI in pixels per inch. Use both the above info to calculate the screen size in inches.
PS: The width() returns the union width, so in case you have multiple screens, it will return union width of all the screens.

python tkinter: how to work with pixels?

using google (and this site) i have seen some similar questions but my problem is still here:
"i want to draw an image (without reading a file) , being able to manipulate every single pixel's colour in that image."
i have seen another question where was suggested to do something like this:
from tkinter import *
A=Tk()
B=Canvas(A)
B.place(x=0,y=0,height=256,width=256)
for a in range(256):
for b in range(256):
B.create_line(a,b,a+1,b+1,fill=pyList[a][b])#where pyList is a matrix of hexadecimal strings
A.geometry("256x256")
mainloop()
in fact this answers my question but... it is extremely slow.
what should i do with a 1920x1080 image ? wait for my death?
so i am asking something to perform the same as the above code but in a faster way
i have found a way to improve the method suggested by jsbueno , it is explained in the page linked :
Why is Photoimage put slow?
It is indeed tricky --
I thought you had to use a Canvas widget, but that has no access to Pixels either.
Image items embedded in the Canvas do have, though. The Tkinter.PhotoImage class
does have a "put" method that accepts a color in hex format and pixel coordinates:
from tkinter import Tk, Canvas, PhotoImage, mainloop
from math import sin
WIDTH, HEIGHT = 640, 480
window = Tk()
canvas = Canvas(window, width=WIDTH, height=HEIGHT, bg="#000000")
canvas.pack()
img = PhotoImage(width=WIDTH, height=HEIGHT)
canvas.create_image((WIDTH/2, HEIGHT/2), image=img, state="normal")
for x in range(4 * WIDTH):
y = int(HEIGHT/2 + HEIGHT/4 * sin(x/80.0))
img.put("#ffffff", (x//4,y))
mainloop()
The good news is that even it being done this way, the updates are "live":
you set pixels on the image, and see them showing up on screen.
This should be much faster than the way drawing higher level lines on screen -
but for lots of pixels it still will be slow, due to a Python function call needed for
every pixel. Any other pure python way of manipulating pixels directly will suffer from that - the only way out is calling primitives that manipulate several pixels at a time in native code from your Python code.
A nice cross-platform library for getting 2d drawing, however poorly documented as well
is Cairo - it would should have much better primitives than Tkinter's Canvas or PhotoImage.
Don't forget to save a reference after canvas.create_image. In some cases, especially when working with the PIL module, python will garbage-collect the image, even though it is being displayed!
Syntax is something like
canvas.create_image((WIDTH/2, HEIGHT/2), image=img)
canvas.image = img

Categories

Resources