Using ffmpeg with Python3 subprocess to convert multiple PNGs to a video - python

I am using Python3, subprocess and ffmpeg to convert multiple PNG images into a single video.
I have 400 PNG numbered as "00001.png".
This call for one single specific image to a a one-frame-video works:
subprocess.call(["ffmpeg","-y","-r","24","-i", "00300.png","-vcodec","mpeg4", "-qscale","5", "-r", "24", "video.mp4"])
However, when I try some methods seen online for calling all of my images formated as "#####.png" using "%05d.png" as below, it does not work anymore:
subprocess.call(["ffmpeg","-y","-r","24","-i", "%05d.png","-vcodec","mpeg4", "-qscale","5", "-r", "24", "video.mp4"])
I receive the error : "%05d.png: No such file or directory".
I have the feelling that the above syntax is proper to Python2 and not working on my python3 but can't find the correct python3 syntax anywhere.
Thanks in advance for your help

Well, I finally found the answer, and as expected it is disappointingly simple: The numbering has to start with 1 (00001 in my case), while in fact my files ranged from 00002.png to 00301.png.
Worked as soon as I added an initial 00001.png file.

Related

Count the audio tracks in a movie file with python

I'm trying to get the number of audio tracks in a video file. The video have multiple tracks (like different, selectable languages for the same movie.) So if there are three optional languages for the video, i'd like to get the number 3 in the end, no matter if the audio is in stereo, mono or in 5.1.
So far I tried to do it with moviepy. I found only the function "reader.nchannels", but that counts only the first audio track's left and right channel, so I get the number 2 every time.
The code right now is really simple, it looks like this:
from moviepy.editor import *
from moviepy.audio import *
clip = VideoFileClip(source)
audio_tracks = clip.audio.reader.nchannels
I also tried to get every info from the audio like this:
audio = AudioFileClip(source)
tracks= audio_tracks.reader.infos
The output for this looks like this:
"'audio_found': True, 'audio_fps': 48000}"
tburrows13, thanks for pointing to the right direction.
I was able to get the numbers of audio channels and store it in a variable through a py script. Maybe this is not the most elegant solution, but it works, so here it is, if someone needs it. You have to import "subprocess" and use ffprobe with it. ffprobe comes with ffmpeg.
To get the number of streams the command goes like this:
ffprobe <filename here> -show_entries format=nb_streams
This will give you the number of streams in the file, not just the audios, but the video streams too. There is an option to get the data only for the audio streams, but this was not necessary for my project.
You can call this command through a python script. The command needs to be a string, you can store it in a variable too. To get and store the output of this commmand in an other variable you can use this:
variable = subprocess.check_output(subprocesscommand) # subprocesscommand is the string version of the command wrote above.
If you print out now this variable the output will be something like: b'[FORMAT]\r\nnb_streams=3\r\n[/FORMAT]\r\n'
Now you just need to slice the string value, to get the number of the streams.
Thanks again for your help!

python ghostscript not closing output file

I'm trying to turn PDF files with one or many pages into images for each page. This is very much like the question found here. In fact, I'm trying to use the code from #Idan Yacobi in that post to accomplish this. His code looks like this:
import ghostscript
def pdf2jpeg(pdf_input_path, jpeg_output_path):
args = ["pdf2jpeg", # actual value doesn't matter
"-dNOPAUSE",
"-sDEVICE=jpeg",
"-r144",
"-sOutputFile=" + jpeg_output_path,
pdf_input_path]
ghostscript.Ghostscript(*args)
When I run the code I get the following output from python:
##### 238647312 c_void_p(238647312L)
When I look at the folder where the new .jpg image is supposed to be created, there is a file there with the new name. However, when I attempt to open the file, the image preview says "Windows Photo Viewer can't open this picture because the picture is being edited in another program."
It seems that for some reason Ghostscript opened the file and wrote to it, but didn't close it after it was done. Is there any way I can force that to happen? Or, am I missing something else?
I already tried changing the last line above to the code below to explicitly close ghostscript after it was done.
GS = ghostscript.Ghostscript(*args)
GS.exit()
I was having the same problem where the image files were kept open but when I looked into the ghostscript init.py file (found in the following directory: PythonDirectory\Lib\site-packages\ghostscript__init__.py), the exit method has a line commented.
The gs.exit(self._instance) line is commented by default but when you uncomment the line, the image files are being closed.
def exit(self):
global __instance__
if self._initialized:
print '#####', self._instance.value, __instance__
if __instance__:
gs.exit(self._instance) # uncomment this line
self._instance = None
self._initialized = False
I was having this same problem while batching a large number of pdfs, and I believe I've isolated the problem to an issue with the python bindings for Ghostscript, in that like you said, the image file is not properly closed. To bypass this, I had to go to using an os system call. so given your example, the function and call would be replaced with:
os.system("gs -dNOPAUSE -sDEVICE=jpeg -r144 -sOutputFile=" + jpeg_output_path + ' ' + pdf_input_path)
You may need to change "gs" to "gswin32c" or "gswin64c" depending on your operating system. This may not be the most elegant solution, but it fixed the problem on my end.
My work around was actually just to install an image printer and have Python print the PDF using the image printer instead, thus creating the desired jpeg image. Here's the code I used:
import win32api
def pdf_to_jpg(pdf_path):
"""
Turn pdf into jpg image(s) using jpg printer
:param pdf_path: Path of the PDF file to be converted
"""
# print pdf to jpg using jpg printer
tempprinter = "ImagePrinter Pro"
printer = '"%s"' % tempprinter
win32api.ShellExecute(0, "printto", pdf_path, printer, ".", 0)
I was having the same problem when running into a password protected PDF - ghostscript would crash and not close the PDF preventing me from deleting the PDF.
Kishan's solution was already applied for me and therefore it wouldn't help my problem.
I fixed it by importing GhostscriptError and instantiating an empty Ghostscript before a try/finally block like so:
from ghostscript import GhostscriptError
from ghostscript import Ghostscript
...
# in my decryptPDF function
GS = Ghostscript()
try:
GS = Ghostscript(*args)
finally:
GS.exit()
...
# in my function that runs decryptPDF function
try:
if PDFencrypted(append_file_path):
decryptPDF(append_file_path)
except GhostscriptError:
remove(append_file_path)
# more code to log and handle the skipped file
...
For those that stumble upon this with the same problem. I looked through the python ghostscript init file and discovered the ghostscript.cleanup() function/def.
Therefore, I was able to solve the problem by adding this simple one-liner to the end of my script [or the end of the loop].
ghostscript.cleanup()
Hope it helps someone else because it frustrated me for quite a while.

OpenCV Python not opening images with imread()

I'm not entirely sure why this is happening but I am in the process of making a program and I am having tons of issues trying to get opencv to open images using imread. I keep getting errors saying that the image is 0px wide by 0px high. This isn't making much sense to me so I searched around on here and I'm not getting any answers from SO either.
I have taken about 20 pictures and they are all using the same device. Probably 8 of them actually open and work correctly, the rest don't. They aren't corrupted either because they open in other programs. I have triple checked the paths and they are using full paths.
Is anyone else having issues like this? All of my files are .jpgs and I am not seeing any problems on my end. Is this a bug or am I doing something wrong?
Here is a snippet of the code that I am using that is reproducing the error on my end.
imgloc = "F:\Kyle\Desktop\Coinjar\Test images\ten.png"
img = cv2.imread(imgloc)
cv2.imshow('img',img)
When I change the file I just adjust the name of the file itself the entire path doesn't change it just refuses to accept some of my images which are essentially the same ones.
I am getting this error from a later part of the code where I try to use img.shape
Traceback (most recent call last):
File "F:\Kyle\Desktop\Coinjar\CoinJar Test2.py", line 14, in <module>
height, width, depth = img.shape
AttributeError: 'NoneType' object has no attribute 'shape'
and I am getting this error when I try to show a window from the code snippet above.
Traceback (most recent call last):
File "F:\Kyle\Desktop\Coinjar\CoinJar Test2.py", line 11, in <module>
cv2.imshow('img',img)
error: ..\..\..\..\opencv\modules\highgui\src\window.cpp:261: error: (-215) size.width>0 && size.height>0 in function cv::imshow
Probably you have problem with special meaning of \ in text - like \t or \n
Use \\ in place of \
imgloc = "F:\\Kyle\\Desktop\\Coinjar\\Test images\\ten.png"
or use prefix r'' (and it will treat it as raw text without special codes)
imgloc = r"F:\Kyle\Desktop\Coinjar\Test images\ten.png"
EDIT:
Some modules accept even / like in Linux path
imgloc = "F:/Kyle/Desktop/Coinjar/Test images/ten.png"
From my experience, file paths that are too long (OS dependent) can also cause cv2.imread() to fail.
Also, when it does fail, it often fails silently, so it is hard to even realize that it failed, and usually something further the the code will be what sparks the error.
Hope this helps.
Faced the same problem on Windows: cv.imread returned None when reading jpg files from a subfolder. The same code and folder structure worked on Linux.
Found out that cv.imread processes the same jpg files, if they are in the same folder as the python file.
My workaround:
copy the image file to the python file folder
use this file in cv.imread
remove redundant image file
import os
import shutil
import cv2 as cv
image_dir = os.path.join('path', 'to', 'image')
image_filename = 'image.jpg'
full_image_path = os.path.join(image_dir, image_filename)
image = cv.imread(full_image_path)
if image is None:
shutil.copy(full_image_path, image_filename)
image = cv.imread(image_filename)
os.remove(image_filename)
...
I had i lot of trouble with cv.imread() not finding my Image. I think i tryed everything involving changing the path. The os.path.exists(file_path) function also gave me back a True.
I finaly solved the problem by loading the images with imageio.
img = imageio.imread('file_path')
This also loads the img in a numpy array and you can use funktions like cv.matchTemplate() on this object. But i would recomment if u are doing stuff with multiple images that you then read all of them with imageio because i found diffrences in the arrays produced by .imread() from the two libs (opencv, imageio) on a File both of them could open.
I hope i could help someone
Take care to :
try imread() with a reliable picture,
and the correct path in your context like (see Kyle772 answer). For me either //or \.
I lost a couple of hours trying with 2 images saved from a left click in a browser. As soon as I took a personal camera image, it works fine.
Spyder screen shot
#context windows10 / anaconda / python 3.2.0
import cv2
print(cv2.__version__) # 3.2.0
imgloc = "D:/violettes/Software/Central/test.jpg" #this path works fine.
# imgloc = "D:\\violettes\\Software\\Central\\test.jpg" this path works fine also.
#imgloc = "D:\violettes\Software\Central\test.jpg" #this path fails.
img = cv2.imread(imgloc)
height, width, channels = img.shape
print (height, width, channels)
python opencv image-loading imread
I know that the question is already answered but in case anybody still is not able to load images with imread. It may be because there are letters in the string path witch imread does not accept.
For exmaple umlauts and diacritical marks.
My suggestion for everyone facing the same problem is to try this:
cv2.imshow("image", img)
The img is keyword. Never forget.
When you get error like this AttributeError: 'NoneType' object has no attribute 'shape'
Try with new_image=image.copy

ipython notebook - uploading from and saving to subdirectories?

Change IPython working directory
Inserting image into IPython notebook markdown
Hi, I've read the two above links, and the second link seems most relevant. what the person describes - simply calling the subdirectory - doesn't work for me. For instance, I have an image 'gephi.png' in '/Graphs/gephi.png'
But when I write the following
from IPython.display import Image
path = "/Graphs/gephi.png"
i = Image(path)
i
no image pops up - Yup. No error. Just nothing pops up besides an empty square box image.
Clarification:
When I move the image to the regular director, the image pops up fine.
My only code change is path = "gephi.png"
IPython's Image display object takes three kinds of arguments
The first is raw image data (e.g. the results of open(filename).read():
with open("Graphs/graph.png") as f:
data = f.read()
Image(data=data)
The second model is to load an image from a filename. This is functionally the same as above, but IPython does the reading from the file:
Image(filename="Graphs/graph.png")
The third form is passing URLs. External URLs can be used, but relative URIs will serve files relative to the notebook's own directory:
Image(url="Graphs/graph.png")
Where this can get confusing is if you don't tell IPython which one of these you are specifying, and you just pass the one argument positionally:
Image("Graphs/graph.png")
IPython tries to guess what you mean in this case:
if it looks like a path and points to an existing file, use it as a filename
if it looks like a URL, use it as a URL
otherwise, fallback on embedding the string as raw png data
That #3 is the source of the most confusion. If you pass it a filename that doesn't exist,
you will get a broken image:
Image("/Graphs/graph.png")
Note that URLs to local files must be relative. Absolute URLs will generally be wrong:
Image(url="/Graphs/graph.png")
An example notebook illustrating these things.

ffmpeg convert image sequence to video

image sequences start with
sdhdfd_plate_bg01_v001_fds_fdse_fdfd.1001
sdhdfd_plate_bg01_v001_fds_fdse_fdfd.1002
sdhdfd_plate_bg01_v001_fds_fdse_fdfd.1003
using
ffmpeg -i D:/imagesequence/sdhdfd_plate/sdhdfd_plate_bg01_v001_fds_fdse_fdfd.%04d.jpg -vf "[in]drawtext=fontsize=32:fontcolor=White:fontfile='/Windows/Fonts/arial.ttf':text='shotName':x=(w)/2:y=(h)-50[out]" D:/Uss/Temp/sdhdfd_plate_bg01_v001_fds_fdse_fdfd.%04d.jpg
following error occurs
D:/imagesequence/sdhdfd_plate/sdhdfd_plate_bg01_v001_fds_fdse_fdfd.%04d.jpg: N
o such file or directory
is it possible to convert these type images using ffmpeg
There seems to be a couple reasons why this isn't working. First, as pointed out by pixelistik, if your images don't actually have .jpg extensions, it won't work (eg, if they're actually png or something).
Secondly, your image sequence has to start at 0 or 1, so starting at 1001 won't work. You can use this batch code or something like it in a UNIX shell to rename your images into a workable sequence.
x=1; for i in *jpg; do counter=$(printf %04d $x); ln "$i" sdhdfd_plate_bg01_v001_fds_fdse_fdfd."$counter".jpg; x=$(($x+1)); done
Note that you must be in the directory holding the images, and if there are other images that you don't want included, you'll have to change for i in *jpg to something like for i in sdhdfd_plate_bg01_v001_fds_fdse_fdfd.*.
seems pattern does not work under windows.
your pattern is incorrect,
for files:
sdhdfd_plate_bg01_v001_fds_fdse_fdfd.1001.jpg
sdhdfd_plate_bg01_v001_fds_fdse_fdfd.1002.jpg
sdhdfd_plate_bg01_v001_fds_fdse_fdfd.1003.jpg
the input pattern should be:
sdhdfd_plate_bg01_v001_fds_fdse_fdfd.1%03d.jpg
here the 1%03d mapping to: 1001, 1002, 1003...

Categories

Resources