I am trying to create a function to export an animation to a video format. I believe the first step in this is to transform a single image into a bytearray, but I can't figure out how to do this.
I tried adjusting the following program which exports a single image:
import pyqtgraph as pg
import pyqtgraph.exporters
# generate something to export
plt = pg.plot([1, 5, 2, 4, 3])
# create an exporter instance, as an argument give it
# the item you wish to export
exporter = pg.exporters.ImageExporter(plt.plotItem)
# save to file
exporter.export('fileName.png')
from this website. But I couldn't get it to store it as a bytearray. Does anybody know how to do this, or how else to approach exporting an entire animation?
Related
I have created a graph in python utilizing the follow sample code.
import plotly.graph_objects as go
from matplotlib.pyplot import figure
image_path = "C:/Users/Me/Pictures/x.png"
fig = go.Figure(go.Indicator(...))
fig.write_image(image_path)
When I go to create new image with this same code, the old data is still in there somewhere and saves with the old data rather than the new data.
I tried using fig.close() but I get an error 'Figure' object has no attribute 'close'. I also tried using plt.close('all') but no luck.
I tried looking on the ploty.graph_objects page but was not able to find how to close the image or save new image with new data.
I also tried clearing the figure data/layout after each run with fig.data = [] and fig.layout = {}
I also tried fig.show() which when looping through images, does show the correct image but the saved image still shows old data.
Any ideas on how to save a figure graph object from plotly with new data?
generating four indicators in a loop
save to a filename x.png and x_.png
x.png and x_750.png are the same so file is definitely being overwritten
import plotly.graph_objects as go
from pathlib import Path
p = Path.cwd().joinpath("indicator_images")
if not p.is_dir():
p.mkdir()
for v in [300,450,600,750]:
fig = go.Figure(go.Indicator(
mode = "gauge+number",
value = v,
title = {'text': "Speed"},
domain = {'x': [0, 1], 'y': [0, 1]}
))
fig.write_image(p.joinpath("x.png"))
fig.write_image(p.joinpath(f"x_{v}.png"))
The Problem:
I'm trying to simulate a live video by cycling through a series of still images I have saved in a directory, but when I add the animation and update functions my plot is displayed empty.
Background on why I'm doing this:
I believe its important for me to do it this way rather than a complete change of approach, say turning the images into a video first then displaying that, because what I really want to test is the image analysis I will be adding and then overlaying on each frame. The final application will be receiving frames one by one from a camera and will need to do some processing, display the image + annotations + output the data as .csv etc... I'm simulating this for now because I do not have any of the hardware to generate the images and will not have it for several months during which time I need to get the image processing set up, but I do have access to some sets of stills that are approximately what will be produced. In case its relevant my simulation images are 1680x1220 and are 1.88 Mb TIFFs, though I could covert and compress them if needed, and in the final form the resolution will be a bit higher and probably the image format could be adjusted if needed.
What I have tried:
I followed an example to list all files in a folder, and an example
to update a plot. However, the plot displays blank when I run the
code.
I added a line to print the current file name, and I can see this
cycling as expected.
I also made sure the images will display in the plot if I just create
a plot and add one image, and they do. But, when combined with the
animation function the plot is blank and I'm not sure what I've done
wrong/failed to include.
I also tried adding a plt.pause() in the update, but again this
didn't work.
I increased the interval up to 2000 to give it more time, but that didn't work. I believe 2000 is extreme, I'm expecting it should work with more like 20-30fps. Going to 0.5fps tells me the code is wrong or incomplete, rather than it just being a question of needing time to read the image file.
I appreciate no one else has my images, but they are nothing special. I'm using 60 images but I guess it could be tested with any 2 random images and setting range(60) to range(2) instead?
The example I copied originally demonstrated the animation function by making a random array, and if I do that it will show a plot that updates with random squares as expected.
Replacing:
A = np.random.randn(10,10)
im.set_array(A)
...with my image instead...
im = cv2.imread(files[i],0)
...and the plot remains empty/blank. I get a window shown called "Figure1" (like when using the random array), but unlike with the array there is nothing in this window.
Full code:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import os
import cv2
def update(i):
im = cv2.imread(files[i],0)
print(files[i])
#plt.pause(0.1)
return im
path = 'C:\\Test Images\\'
files = []
# r=root, d=directories, f = files
for r, d, f in os.walk(path):
for file in f:
if '.TIFF' in file:
files.append(os.path.join(r, file))
ani = FuncAnimation(plt.gcf(), update, frames=range(60), interval=50, blit=False)
plt.show()
I'm a python and a programming novice so have relied on adjusting examples others have given online but I have only a simplistic understanding of how they are working and end up with a lot of trial and error on the syntax. I just can't figure out anything to make this one work though.
Cheers for any help!
The main reason nothing is showing up is because you never add the images to the plot. I've provided some code below to do what you want, be sure to look up anything you are curious about or don't understand!
import glob
import os
from matplotlib import animation
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
IMG_DIRPATH = 'C:\\Test Images\\' # the folder with your images (be careful about
# putting spaces in directory names!)
IMG_EXT = '.TIFF' # the file extension of your images
# Create a figure, and set to the desired size.
fig = plt.figure(figsize=[5, 5])
# Create axes for the current figure so that images can be sized appropriately.
# Passing in [0, 0, 1, 1] makes the axes fill the whole figure.
# frame_on=False means we won't have a bounding box, and setting xticks=[] and
# yticks=[] means that we won't have pesky tick marks along our image.
ax_props = {'frame_on': False, 'xticks': [], 'yticks': []}
ax = plt.axes([0, 0, 1, 1], **ax_props)
# Get all image filenames.
img_filepaths = glob.glob(os.path.join(IMG_DIRPATH, '*' + IMG_EXT))
def update_image(img_filepath):
# Remove all existing images on the axes, and restore our settings.
ax.clear()
ax.update(ax_props)
# Read the current image.
img = mpimg.imread(img_filepath)
# Add the current image to the plot axes.
ax.imshow(img)
anim = animation.FuncAnimation(fig, update_image, frames=img_filepaths, interval=250)
plt.show()
I'm working on a project that involves Python. I've NEVER used it along with OpenCV. The objective is to take a 16x16 section of an video, I'm practicing with a single Image, and get it's RBG value. I'm suppose to run this for thousands of frame on a video, which i dont know how to loop. Once I have it ([ 71 155 90]) for example, I want to save it to a notepad, excel sheet, or some simple way or referring to my results.
I've tried looking up tutorials on how to export values, but they've used so many different terms that I don't know where to start.
import numpy as np
import cv2
img = cv2.imread('dog.jpg', cv2.IMREAD_COLOR)
px = img[16,16]
print(px)
The only thing I get is the RBG output [ 71 155 90] in the terminal. I don't know where to do from there. I don't know how to export the value.
you can use openpyxl or
import numpy as np import cv2
img = cv2.imread('dog.jpg', cv2.IMREAD_COLOR)
px = img[16,16]
import pandas as px
df = pd.DataFrame(px)
df.to_excel('filename.xlsx')
You'll need to open a file and then write the results to that file, here is one possible way to do this (although perhaps not the most optimal):
fp = open('output.csv', 'w')
fp.write('{},{},{}'.format(px[0],px[1],px[2])
# write more values here
fp.close() # do this at the end of your writes
I am currently working on something similar, instead of videos I am working with images so I went around searching for tutorials on how to do bulk export of images/ frames from a folder and saving the data into a numpy array.
This is a sample of my code *not sure how much errors are inside but it is able to load and save image frames into an array. I use tqdm to show a simple progress bar so I know what is the status of the image loading when I call this function.
def img_readph(path):
readph =[i for i in listdir(path) if isfile(join(path,i))]
img = np.empty(len(readph), dtype=object)
for j in tqdm(range(0, len(readph))):
img[j] = cv2.imread(join(path,readph[j]))
return img
In order to load and work on the images that are currently saved in a numpy array stack, I use this set of code to do the extraction, perform a basic psnr calculation and save the data to a .txt (learning how to convert the result to a .csv that I can load/save/append in python for future edits as well).
for index in tqdm(range(len(img))):
(psnr, meanerror) = calculate_psnr(imgGT[index], imgSR[index])
print('Image No.{} has average mean square error of {} and the average PSNR is {}'.format(index,meanerror,psnr))
Doing it this way lets me loop every video frame I have in the previous numpy array to perform my operation to calculate psnr.
What you could do is to try write your code to get the RGB values into a function using,
txtfilename = input("enter filename: ")
with open(str(txtfilename)+".txt","w") as results:
for index in tqdm(range(0, len(img))) #the array from imread
img = cv2.imread('img', cv2.IMREAD_COLOR)
px = img[width, height]
print("The RBG values are {}".format(px), file=results)
Something along the lines of this I guess, hope it helps.
I'm working with a map created using python, folium, and geojson, similar to this one.
However, instead of this image being an interactive HTML document, I would rather simply export it to png or svg.
Using the syntax:
m = folium.Map( # etc..)
m.save("filename.png")
Saves a file, but it is still HTML, rather than png. What's the correct output command to render not-to-html?
I use this:
... where m is my map object.
And 5 is the time (seconds) to render the map.
import io
from PIL import Image
img_data = m._to_png(5)
img = Image.open(io.BytesIO(img_data))
img.save('image.png')
So instead of storing every data we have in yet another format to make it displayable by ParaView, I wanted to use the python interface ParaView offers to directly load our data from our current file format and display it.
To test this out I wanted to create a simple ProgrammableSource filter that outputs a vtkImageData and fill it with some data.
I encountered three issues:
First, the data is not displayed (not even as an outline representation)
I could not find a way to set the values without looping
I did not find a good online source that could help me
Here is what I have so far. No complaints from ParaView, but also nothing is rendered.
import numpy as np
import vtk
import vtk.util.numpy_support as ns
img = self.GetImageDataOutput()
img.SetDimensions(3,4,5)
img.AllocateScalars(vtk.VTK_DOUBLE, 1)
dims = img.GetDimensions()
img.SetOrigin(0,0,0)
img.SetSpacing(0.55, 0.55, 0.55)
for z in range(dims[2]):
for y in range(dims[1]):
for x in range(dims[0]):
img.SetScalarComponentFromDouble(x,y,z,0, 1.0*x*y*z)
NOTE: If it is easier to use the python shell of ParaView directly instead of the ProgrammableSource, this would also be ok.
For defining vtkImageData output with the Programmable Source, one also has to take care of setting some information in the RequestInformation phase of the pipeline execution. Insert the following into the Script (RequestInformation) property:
from paraview import util
op = self.GetOutput()
util.SetOutputWholeExtent(self, [0, 2, 0, 3, 0, 4])
This information was adapted from information available at http://www.paraview.org/Wiki/Python_Programmable_Filter.