matplotlib save animation in gif error - animation

I want to save matplotlib animation in gif format.
I succeded to save animation to mp4 format, using code
import matplotlib
matplotlib.use("Agg")
~some codes~
ani = animation.FuncAnimation(fig, draw, update, interval=10, blit=False)
mywriter = animation.FFMpegWriter(fps=60)
ani.save('myanimation.mp4',writer=mywriter)
but if I change myanimation.mp4 to gif format, python makes error
Traceback (most recent call last):
File "C:\Users\Administrator\Desktop\edison\Edison_v4_backup_1\ver5.py", line 164, in <module>
ani.save('demoanimation.gif',writer=mywriter);
File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 718, in save
writer.grab_frame(**savefig_kwargs)
File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 204, in grab_frame
dpi=self.dpi, **savefig_kwargs)
File "C:\Python27\lib\site-packages\matplotlib\figure.py", line 1421, in savefig
self.canvas.print_figure(*args, **kwargs)
File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 2220, in print_figure
**kwargs)
File "C:\Python27\lib\site-packages\matplotlib\backends\backend_agg.py", line 497, in print_raw
renderer._renderer.write_rgba(filename_or_obj)
RuntimeError: Error writing to file
Seeing that I succeded to save in mp4 format, I don't know why it makes error when saving gif format.

This is because matplotlib does not support GIFs without external programs. If you have imagemagick correctly installed and configured, this should work:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
def init_animation():
global line
line, = ax.plot(x, np.zeros_like(x))
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1,1)
def animate(i):
line.set_ydata(np.sin(2*np.pi*i / 50)*np.sin(x))
return line,
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.linspace(0, 2*np.pi, 200)
ani = matplotlib.animation.FuncAnimation(fig, animate, init_func=init_animation, frames=50)
ani.save('/tmp/animation.gif', writer='imagemagick', fps=30)

Just a reminder, before you use Matplotlib and ImageMagick to convert images or videos to gif, you need to modify Matplotlib's config and add ImageMagick's path.
The following code will show you the config file path of Matplotlib
import matplotlib
matplotlib.matplotlib_fname()
For me the path is
C:\Anaconda\lib\site-packages\matplotlib\mpl-data\matplotlibrc
Then changing animation.convert_path
#animation.convert_path: 'convert' # Path to ImageMagick's convert binary.
# On Windows use the full path since convert
# is also the name of a system tool.
by adding convert.exe path to it
animation.convert_path: C:\Program Files\ImageMagick-6.9.2-Q16-HDRI\convert.exe
Don't forget to remove the # before animation.convert_path.
After the above modification, Matplotlib and ImageMagick will perfectly work and output the gif file you want.
Hope it helps.

Still had some trouble on Mac OS X, but the answers above pointed me in the right direction.
What I did came down to:
brew install imagemagick
edit the path file on location /etc/path (sudo vim path) and added the location of bin folder of imagemagick, in my case: /usr/local/Cellar/imagemagick/6.9.6-4/bin
changed the settings of matplotlibrc as described above. You can find the location of matplotlibrc by doing in Python: import matplotlib matplotlib.matplotlib_fname()
The settings you need to adjust can be found at the end of the file. I adjusted the following ones (commented out). Please note that those settings are not in 'quotes':
animation.writer : imagemagick
animation.codec : mpeg4
animation.bitrate: -1
animation.frame_format: png
animation.convert_path: convert

DrV's script didn't work for me on Windows 7, even though convert and ffmpeg both are in the system path.
File "C:\Python27\lib\site-packages\matplotlib\backends\backend_agg.py", line 513, in print_raw
renderer._renderer.write_rgba(filename_or_obj)
RuntimeError: Error writing to file
C:\Users>ffmpeg
ffmpeg version N-50911-g9efcfbe Copyright (c) 2000-2013 the FFmpeg developers
...
C:\Users>convert
Version: ImageMagick 6.9.1-1 Q16 x64 2015-03-20 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
...
Editing my matplotlibrc to add the full path to the exe fixed it:
###ANIMATION settings
#animation.html : 'none' # How to display the animation as HTML in
# the IPython notebook. 'html5' uses
# HTML5 video tag.
#animation.writer : ffmpeg # MovieWriter 'backend' to use
#animation.codec : mpeg4 # Codec to use for writing movie
#animation.bitrate: -1 # Controls size/quality tradeoff for movie.
# -1 implies let utility auto-determine
#animation.frame_format: 'png' # Controls frame format used by temp files
animation.ffmpeg_path: C:\Program Files\ImageMagick-6.9.1-Q16\ffmpeg.exe # Path to ffmpeg binary. Without full path
# $PATH is searched
#animation.ffmpeg_args: '' # Additional arguments to pass to ffmpeg
#animation.avconv_path: 'avconv' # Path to avconv binary. Without full path
# $PATH is searched
#animation.avconv_args: '' # Additional arguments to pass to avconv
#animation.mencoder_path: 'mencoder'
# Path to mencoder binary. Without full path
# $PATH is searched
#animation.mencoder_args: '' # Additional arguments to pass to mencoder
animation.convert_path: C:\Program Files\ImageMagick-6.9.1-Q16\convert.exe # Path to ImageMagick's convert binary.
# On Windows use the full path since convert
# is also the name of a system tool.

I have just tried to install ffmpeg, didn't help. Then I tried to install imagemagick - failed. So I resorted to looping animation and recording it with screen scraper . I use ScreenToGif.

Related

Why does this SVG to ICO conversion with ImageMagick batch script I wrote produce broken images?

Okay I've been doing a bunch of searching on this topic and I can't seem to find a good answer on this website, so please read this entire thing before marking it as a duplicate or whatever.
I'm writing some personal zsh utilities to make it easy for me to batch process icons into various different formats.
Here's the version output info for the imagemagick convert utility
┌─ ~/LinuxSVGsets/Dex_KDE/actions
└─➤ convert -version
Version: ImageMagick 6.9.7-4 Q16 x86_64 20170114 http://www.imagemagick.org
Copyright: © 1999-2017 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules OpenMP
Delegates (built-in): bzlib djvu fftw fontconfig freetype jbig jng jpeg lcms lqr ltdl lzma openexr pangocairo png tiff wmf x xml zlib
Here is my current script
function svg2icoBatch () {
for fname in $1/**/*.svg
do
#take off the svg
pathAndName=${fname%.svg}
#take off the path from the file name
iconname=${pathAndName##*/}
#take off the file name from the path
iconpath=$pathAndName:h
#create new folder for converted icons to be placed in
mkdir -p ${iconpath}/ico-converted/
convert $fname -background none -density 256 -define icon:auto-resize=16,32,48,64,256 ${iconpath}/ico-converted/${iconname}.ico
echo "\033[1;33m converted ${iconname}.svg to ico\n \033[0m"
done
}
the resulting ico looks like garbage:
When I try opening them up on an online ico viewer to make sure this wasn't just something weird with the image previewer utility in Ubuntu, I see a super blurry version of the icon that doesn't include it's additional sizes. I have no clue what I'm doing wrong here.
Any clues?

ImageMagick no decode delegate for this image format `PDF' Windows

Trying to play with ImageMagick to read scanned PDF texts, but at the point to convert the PDF to image, I've got this error, where it shows "no decode delegate for this image format `PDF' # error/constitute.c/ReadImage/504". Been search for this solution for hours to no avail, need some help here.
OS: Windows 7 x64
ImageMagick Version: ImageMagick-6.9.8-10-Q16-x86-dll.exe
convert -list format
shows below output
Format Module Mode Description
-------------------------------------------
* native blob support
r read support
w write support
+ support for multiple images
Looks like your delegates are not properly configured,
Once Ghostscript is installed make sure the binary folder C:\Program Files/gs/gs3.0.9/bin is added to your path.
Once Done, there should be a file names delegates.mgk in you graphics magick home directory. Open that file in a text editor.
<delegate decode="pdf" encode="eps" mode="bi" command='"#PSDelegate#" -q -dBATCH -dSAFER -dMaxBitmap=50000000 -dNOPAUSE -sDEVICE=#GSEPSDevice# "-sOutputFile=%o" -- "%i" -c quit' />
In the whole file, find and replace #PSDelegate# with gswin64c and it should get the job done.

PIL Issue, OSError: cannot open resource

I'm attempting to write a program that places text onto an image, I'm trying to get my head round PIL and have run into the error: OSError: cannot open resource. This is my first python program so apologies if the error is obvious.
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
im = Image.open("example.jpg")
font_type = ImageFont.truetype("Arial.ttf", 18)
draw = ImageDraw.Draw(im)
draw.text(xy=(50, 50), text= "Text One", fill =(255,69,0), font = font_type)
im.show()
I get the error:
Traceback (most recent call last):
File "C:\Users\laurence.maskell\Desktop\attempt.py", line 7, in <module>
font_type = ImageFont.truetype("Arial.ttf", 18)
File "C:\Python34\lib\site-packages\PIL\ImageFont.py", line 259, in truetype
return FreeTypeFont(font, size, index, encoding, layout_engine)
File "C:\Python34\lib\site-packages\PIL\ImageFont.py", line 143, in __init__
self.font = core.getfont(font, size, index, encoding,
layout_engine=layout_engine)
OSError: cannot open resource
I fixed the problem by using default font.
font = ImageFont.load_default()
If you just need to put some text (font style is not matter to you) then this might be a simple solution.
font = ImageFont.load_default()
draw = ImageDraw.Draw(pil_img)
draw.text(( 20, 32), "text_string", (255,0,0), font=font)
from PIL import Image, ImageDraw, ImageFont
im = Image.open("mak.png")
font_type = ImageFont.truetype("arial.ttf", 18)
draw = ImageDraw.Draw(im)
draw.text(xy=(120, 120), text= "download font you want to use", fill=(255,69,0), font=font_type)
im.show()
Its "arial.ttf" not "Arial.ttf"
Here is the link to download arial.ttf font.
I have also met this issue on Windows 10 Pro with PIL 5.3.0.
On my machine, the error is caused by non-ASCII font file names. If I change the the font name to only contain ASCII characters, I can open the font without any error.
Edit (2019-07-29): this is indeed a bug with ImageFont.truetype() method and it has been fixed in this pull request.
For Linux I used:
$ locate .ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-B.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-BI.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-C.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-L.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-LI.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-M.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-MI.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-R.ttf
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-RI.ttf
/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-B.ttf
/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-BI.ttf
/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf
/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-RI.ttf
It actually returned A LOT MORE than that!
Then I took the python code posted here in Stack Overflow:
PIL: Generating Vertical Gradient Image
Plugged in the font name "Ubuntu-R.ttf" returned by locate:
color_palette = [BLUE, GREEN, RED]
image_w=200
image_h=200
region = Rect(0, 0, image_w, image_h)
imgx, imgy = region.max.x+1, region.max.y+1
image = Image.new("RGB", (imgx, imgy), WHITE)
draw = ImageDraw.Draw(image)
vert_gradient(draw, region, gradient_color, color_palette)
#image.text((40, 80),"No Artwork",(255,255,255))
#font = ImageFont.truetype(r'C:\Users\System-Pc\Desktop\arial.ttf', 40)
#font = ImageFont.load_default()
font = ImageFont.truetype("Ubuntu-R.ttf", int(float(image_w) / 6))
draw.text((int(image_w/12), int(image_h / 2.5)), "No Artwork", \
fill=(0,0,0), font=font)
image.show()
And voila! I now have an image to display when there is no image to display in a music file I'm playing:
I was also facing the same issue. but later found out it was an issue with the slash. So, if anybody else missed this small thing, it's for you.
I had the font inside the font folder. When I tried to import the font using font/<font_name>.ttf, the code couldn't locate it. Replaced / with \ and it could locate the font.
If you are on Windows, by the following method my problem was resolved:
go to the Font folder in C:\Windows\Fonts
Right-click on the font that you want to use and click on "Properties"
go to the Security tab and copy the address of "Object name:"
then place the above path (*****) in the following code:
ImageFont.truetype("*****", int(float(image_w) / 6))
PIL cannot find the specified font. Check that it exists, and that it is named with the exact same case.
You can also try to copy it directly in the project folder.
I think you should move the font to fonts or any folder. I had the same issue on heroku. After i moved the font to fonts directory it works
When I ran into this issue in Linux, I solved by:
Install the .ttf into Linux
Run the code with the actual .tff in ~. For some reason, even with the font installed and the .py running inn another dir, it needed to have the .tff in the home dir.
This issue also crops up in PIL for android. While it is quite possible to copy a font file into the project directory as others have noted, if more than a few android fonts are wanted it may be tidier to add the android font directory to the ImageFont.py search path instead. I altered it like this between lines 870-871:
870 elif sys.platform in ("linux", "linux2"):
if 'ANDROID_BOOTLOGO' in os.environ:
# kludge added for android
dirs += [
"/system/fonts"
]
else:
871 lindirs = os.environ.get("XDG_DATA_DIRS", "")
872 if not lindirs:
... # According to the freedesktop spec, XDG_DATA_DIRS should
# default to /usr/share
lindirs = "/usr/share"
dirs += [os.path.join(lindir, "fonts") for lindir in lindirs.split(":")]
As I have understood, a problem with location
of the file: "Arial.ttf"
As I have understood the Arial.ttf file is with the program, but start is made from other place.
In this case it is necessary to add the Arial.ttf file to a full path:
# __file__ contain full path to the py scrypt
# for python 3.9 and later
import os
path = os.path.dirname(__file__) + '/'
im = Image.open("example.jpg")
font_type = ImageFont.truetype(path + "Arial.ttf", 18)
For older py version see more at:
How do I get the full path of the current file's directory?
It's just that the name of the .ttf file does'nt match with the filename you pass to ImageFont.truetype().
Make sure that the case and spelling are correct. There is no other external factor that could affect merely loading a font from a ttf file.
I solved it simply by doing the following steps:
Created a hidden folder named fonts (.fonts) in the home directory.
Downloaded my desired font from the web. Note: You can download any
font you want by typing "font_name.tiff download" on Google.
Copy and paste the downloaded .ttf file into the .fonts folder.
Copy and paste the new path of your .ttf file in the code as shown below.
im_show = draw_ocr(image, boxes, txts, scores, font_path='/.fonts/simfang.ttf')
That's how it worked for me.
You can follow this link as a visual aid. https://www.youtube.com/watch?v=Q5GO_glHXyQ&t=35s

installed ffmpeg not detected. Can't convert audio (python 2.7, mac os x)

General information:
I have a project in python that deals with audio classification; the backend is complete but I'm suffering with the front-end. The backend requirement (that I can't change) is that the audio file must be in wav format but I want users to be able to upload mp3 files as well. My front-end is a web server using python 2.7 and flask.
So, I basically want to convert mp3 to wav, but keep on getting errors.
(The complete code is at the bottom in case it is needed to understand the problem more clearly)
My attempts:
1- I used pydub library
I installed homebrew, libav, and ffmpeg
libav installation method: brew install libav --with-libvorbis --with-sdl --with-theora
ffmpeg installation method: brew install ffmpeg --with-libvorbis --with-ffplay --with-theora
Method1
sound = AudioSegment.from_file(filename[i], format="mp3") #filename[i]=nameOfFile
sound.export("input.wav", format="wav")
Method2
AudioSegment.from_file(filename[i], format="mp3").export("input.wav", format="wav")
=> Kept getting "file not found" and "cannot detect ffmpeg or avconv" runtime warning even though I installed ffmpeg and libav
=> Got same error above ("file not found") when I used "from_mp3" instead of "from_file"
=> Tried using "raw" instead of "mp3" and got "key error: sample_width" (couldn't find what this error meant)
Note: I made sure I'm in the right directory
2- Used subprocess
import subprocess
subprocess.call(["ffmpeg", "-i",filename[i],"inputAudio.wav"])
=> Got "OSError: No such file or directory"
I hope you can help me understand what the problem is and how to solve it...
Complete Code:
I have this at the top
app = Flask(__name__)
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
os.chdir(APP_ROOT)
Inside the function that deals with the audio files
data = request.files.getlist('file') #get all uploaded audio files
fsize = len(data) #number of audio files
i = 0 #index counter
filename = ["" for x in range(fsize)] #LIST TO STORE EACH FILE'S NAME
audiofile = ["" for x in range(fsize)] #LIST TO STORE CLASSIFICATION RESULTS OF EACH FILE
#LOOP THROUGH EACH UPLOADED FILE
for file in data:
filename[i] = file.filename #ADD FILENAME TO LIST ABOVE
destination = str(APP_ROOT)
Problematic Part:
if file.filename.endswith(".mp3"):
from pydub import AudioSegment
t = destination + "/" + filename[i]
file.save(t) #SAVE UPLOADED MP3 FILE TO EXTRACT IT USING PYDUB
sound = AudioSegment.from_file(filename[i], format="mp3")
sound.export("input.wav", format="wav")
os.remove(t) #DELETE MP3 FILE, WE ONLY WANT WAV
destination += "/inputAudio.wav"
Code Continuation:
#STORE AUDIO FILE TO PREPARE FOR PROCESSING (CLASSIFICATION)
else:
destination += "/inputAudio.wav"
file.save(destination)
#FINAL STEP
audiofile[i]=Raudio.start() #AUDIO PROCESSING (CLASSIFICATION)
os.remove(destination) #DELETE AUDIO FILE TO PREVENT CLUTTERING OF FILES
i += 1 #INCREMENT FILE INDEX
Okay so I have found a solution to this problem.
I ended up downloading the FFmpeg binary from this site.
Then I just copy-pasted all of the contents of the downloaded file in the following path:
Macintosh HD/Library/Frameworks/Python.framework/Versions/2.7
This is also where the python exec is and I remember reading somewhere that the problem may be that ffmpeg couldn't be found in the path of python or something.
So.... It finally works! Thought I'd share the solution as this problem has taken up most of my weekend and I hope it can help someone else solve their issues,

Python strip all GPS metadata from image

Is there a simple way, on windows and linux (Ubuntu Linux and Windows 7, both 64-bit with Python 2.7), to strip all (not just EXIF) GPS metadata on all images in a directory, and leave the rest of the metadata intact? It only needs to work for JPGs and PNGs.
It's not exactly what I want, but I wrote a script using PyExiv2 which obscures some GPS EXIF data. Here is the script.
#!/usr/bin/python2.7
from pyexiv2 import ImageMetadata, ExifTag
from fractions import Fraction
import argparse, os
parser = argparse.ArgumentParser(description='Strip GPS metadata.')
parser.add_argument('dir', metavar='DIRECTORY',
help='The directory to process.')
args = parser.parse_args()
files = os.listdir(args.dir)
for tiname in files:
iname = args.dir+tiname
image = ImageMetadata(iname)
image.read()
image["Exif.GPSInfo.GPSLatitude"] = Fraction(1,1)
image["Exif.GPSInfo.GPSLongitude"] = Fraction(1,1)
image.write()
EDIT: This apparently (at least on windows) does not strip the latitude and longitude.

Resources