capture screenshot/frame of a video file - python

is there a way to capture a single frame of a video file in python?
it could also be done by command line. im using handbrakecli to convert the videos,
but i would need some screenshots of it too.
thank you

You should first check out PyFFmpeg.
PyFFmpeg is a wrapper around FFmpeg's
libavcodec, libavformat and libavutil
libraries whose main purpose is to
provide access to individual frames of
video files of various formats
(including MPEG and DIVX encoded
videos). It also provides access to
audio data.
It is also possible using ffmpeg, so call that using subprocess. A simple search will give you the command required to extract a frame from a video file. Just call that command using subprocess and that should do it.
>>> import subprocess
>>> import shlex # to split the command that follows
>>> command = 'ffmpeg -i sample.avi' # your command goes here
>>> subprocess.call(shlex.split(command))
The similar procedure applies to handbrakecli or whatever you might use. Just call the appropriate command.

Related

youtube-dl, calling as subprocess, link not recognized

So, I'm writing a basic python script to use youtube-dl to download a highquality thumbnail from a video. With the command line youtube-dl, you can run "youtube-dl --list-thumbnails [LINK]" and it will output a list of different quality links to the thumbnail images. Usually the highest resolution one has 'maxresdefault' in its link. I want to be able to download this image from the command line with wget. This is the code I have so far to achieve it. I'm not familiar with regex, but according to this site: regexr.com, it should have a match in the link with 'maxresdefault'.
import subprocess
import sys
import re
youtubeoutput = subprocess.call(['youtube-dl', '--list-thumbnails', 'https://www.youtube.com/watch?v=t2U2mUtTnzY'], shell=True, stdout=subprocess.PIPE)
print(str(youtubeoutput))
imgurl = re.search("/maxresdefault/g", str(youtubeoutput)).group(0)
print(imgurl)
subprocess.run('wget', str(imgurl))
I put the print statements in there to see what the outputs were. When I run the code, I can see the youtube-dl doesn't recognize a link being in there. youtube-dl: error: You must provide at least one url. Since there's no links in the output, the re.search becomes a NoneType and it gives me an error. I don't know why youtube-dl won't recognize the link. I'm not even sure it recognizes the --list-thumnails. Could anyone help?
You've asked subprocess to use a shell (shell=True), so you would usually pass an entire command to call, like so:
youtubeoutput = subprocess.call("youtube-dl --list-thumbnails https://www.youtube.com/watch?v=t2U2mUtTnzY", shell=True, stdout=subprocess.PIPE)
But really, you may not need a shell. Try something like:
youtubeoutput = subprocess.check_output(['youtube-dl', '--list-thumbnails', 'https://www.youtube.com/watch?v=t2U2mUtTnzY'])
Note that call does not actually return the program's standard output; check_output does.
Reference

How do I integrate the FFMPEG commands with Python Script?

I am trying to extract the frames when the scene changes in an .mp4 video.
The package that I am using is FFMPEG.
FFMPEG predominantly works on the CLI and I am trying to integrate it with Python3.x
The command I am using in the CLI is:
ffmpeg -i {0} -vf "select=gt(scene\,0.5), scale=640:360" -vsync vfr frame%d.png
The output comes out just fine with the CLI execution.
But I want to use same command in a Python script, how do I do that and what should be the code?
Being an amateur in the field, currently grappling with this!
You could execute that command from Python via subprocess module, of course, but it would better to use library like https://github.com/kkroening/ffmpeg-python
I would recommend PyAV. it's a proper wrapper around ffmpeg's libraries.
the other mentioned packages use the "subprocess" approach, which is limited and inefficient. these libraries may be more convenient than plain ffmpeg APIs.
Thanks for the help!
This is the snippet of code I'm currently using and it gives the results as I require.
I have added a functionality for timestamp generation of the frames in addition to the frame formation using scene change detection
===========================================================================
> # FFMPEG Package call through script
> # need to change the location in the cmd post -vsync vfr to the location where the frames are to be stored
> # the location should be same as where the videos are located
============================================================================
inputf = []
for filename in os.listdir(path):
file= filename.split('.')[0] # Splits the file at the extension and stores it without .mp4 extension
input_file = path + filename
inputf.append(input_file) # Creates a list of all the files read
for x in range (0, len(inputf)):
cmd = f'ffmpeg -i {inputf[x]} -filter_complex "select=gt(scene\,0.2), scale=640:360, metadata=print:file=time_{file}.txt" -vsync vfr {path where the videos are located}\\{file}_frame%d.jpg'
os.system(cmd)
x=x+1
print("Done") # Takes time will loop over all the videos

Python subprocess.call() doesn't write content to file

Using Python 2.7 on Raspberry Pi B+, I want to call the command "raspistill -o image.jpg" from Python and find using this is recommended:
from subprocress import call
call(["raspistill","-o image.jpg"])
However, this doesn't work since the image.jpg isn't created although outside Python,
raspistill -o
does create the file.
Next try is to first create the image file and writing to it.
f = open("image.jpg","w")
call(["raspistill","-o image.jpg"], stdout = f)
Now the image file is created, but nothing is written to it: its size remains 0. So how can I get this to work?
Thank you.
You are passing -o image.jpg as a single argument. You should pass them like two. Here is how:
call(["raspistill", "-o", "image.jpg"])
The way you did it it's like calling raspistill "-o image.jpg" from the command line, which will likely result in an error.
First, you're creating and truncating the file image.jpg:
f = open("image.jpg","w")
Then you're sending raspistill's stdout to that same file:
call(["raspistill","-o image.jpg"], stdout = f)
When you eventually get around to close-ing the file in Python, now image.jpg is just going to hold whatever raspistill wrote to stdout. Or, if you never close it, it'll be that minus the last buffer, which may be nothing at all.
Meanwhile, you're also trying to get raspistill to create a file with the same name, by passing it as part of the -o argument. You're doing that wrong, as Ionut Hulub's answer explains. Some programs will take "-o image.jpg" "-oimage.jpg", and "-o", "image.jpg" as meaning the same thing, some won't. But, even if this one does, at best you've now got two programs fighting over what file gets created and written as image.jpg.
If raspistill has an option to write the still to stdout, then you can use that option, together with passing stdout=f, and making sure to close the file. Or, if it has an option to write to a filename, then you can use that option. But doing both is not going to work.
If you don't know how to split the command, you can use shlex.split. For example,
>>> import shlex
>>> args = shlex.split('raspistill -o image.jpg')
>>> args
['raspistill', '-o', 'image.jpg']
>>> call(args)

How to call command line command (AFNI command)?

I am trying to read a dicom header tag in dicom file.
Now, there are two ways to read this dicom header tag.
1) Using pydicom package in python which apparently is not working well on my python installed version(python 3).
2) or when i call AFNI function 'dicom_hinfo' through command line, i can get dicom tag value. The syntax to call afni function in terminal is as follows:
dicom_hinfo -tag aaaa,bbbb filename.dcm
output:fgre
Now how should i call this dicom-info -tag aaaa,bbbb filename.dcm in python script.
I guess subprocess might work but not sure about how to use it in this case.
To get output from a subprocess, you could use check_output() function:
#!/usr/bin/env python
from subprocess import check_output
tag = check_output('dicom_hinfo -tag aaaa,bbbb filename.dcm output:fgre'.split(),
universal_newlines=True).strip()
universal_newlines=True is used to get Unicode text on Python 3 (the data is decoded using user locale's character encoding).
check_output() assumes that dicom_hinfo prints to its standard output stream (stdout). Some utilities may print to stderr or the terminal directly instead. The code could be modified to adapt to that.
Oh this was due to syntax error using Pydicom.
I wanted to access 0019, 109c tag.
Syntax should be:
ds[0x0019,0x109c].value.
not ds[aaaa,bbbb].value

Capture jpgs produced in subprocess in main script

I'm not sure that this is possible, but I'm trying to generate a number of thumbnails from pdfs in an automated way and then store them within elasticsearch. Basically I would like to convert the pdf to a series of jpgs (or pngs, or anything similar) and then index them as binaries. Currently I'm producing these jpgs like this:
import subprocess
params = ['convert', 'pdf_file', 'thumb.jpg']
subprocess.check_call(params)
which works well, but it just writes the jpgs out to the filesystem. I would like to have these files as strings without writing them out to the local file system at all. I've tried using the stdout methods of subprocess, but I'm fairly new to using subprocesses, so I wasn't able to figure this one out.
I'm using imagemagick for this conversion, but I am open to switching to any other tool so long as I can achieve this goal.
Any ideas?
You can have it send the data to stdout instead...
import subprocess
params = ['convert', 'pdf_file', 'jpg:-']
image_data = subprocess.check_output(params)
you can use imagemagick's python API, for example something like:
import PythonMagick
img = PythonMagick.Image("file.pdf")
img.depth = 8
img.magick = "RGB"
data = img.data
or use wand:
from wand.image import Image
with Image(filename='file.pdf') as img:
data = img.make_blob('png')
I would like to have these files as strings without writing them out to the local file system at all.
The way to do this is to tell the command to write its data to stdout instead of a file, then just read it from proc.stdout.
Not every command has a way to tell it to do this, but in many cases, just passing - as the output filename will do it, and that's true for ImageMagick's convert. Of course you'll also need to give it a format, because it can no longer guess it from the extension of thumb.jpg. The easiest way to do this is in convert is to prefix the type to the - pseudo-filename. (Don't try that with anything other than ImageMagick.)
So:
import subprocess
params = ['convert', 'pdf_file', 'jpg:-']
converted = subprocess.check_output(params)
However, this is going to get you one giant string. If you were trying to get a bunch of separate images, you'll need to split the one giant string into separate images, which will presumably require some knowledge of the JPEG/JFIF format.

Categories