I need to directly save an open3d geometry/viewport as a part of a python loop,
The problem is that in each run, a visualization python window pops up and interferes with running the loop.
The visualisation part of my code looks like this:
vis = o3d.visualization.Visualizer()
vis.create_window(visible=False)
vis.add_geometry(mesh1)
vis.add_geometry(mesh2)
# Set the camera view to the isometric view
vis.get_view_control().set_zoom(1)
vis.get_view_control().set_lookat([4, 5, 3])
vis.get_view_control().set_front([-0.5, -0.5, +0.5])
vis.get_view_control().set_up([0.0, 0.0, 1.0])
vis.get_view_control().set_constant_z_far(300)
# Hide the visualization window and capture a screenshot of the window
vis.poll_events()
vis.update_renderer()
vis.capture_screen_image(f'{images_folder}{iterationName}.jpg')
# Close the visualization window
vis.destroy_window()
I set the visible=False option on the create_window function to address this issue, which improved the outcome, but I still see (incrementally increasing) number of python window icons on my Dock. (below)
Related
How can I remove or change the PyVista render window's icon? I have tried to search the issue also from the docs but didn't find any answers.
This is not currently supported directly in PyVista, but this is a great idea and I'll open a pull request to implement this once a major refactor of render windows is done.
In the meantime you can use raw VTK, the SetIcon() method on render windows. According to the docs this only works on Windows and Linux though.
As of PyVista 0.36.1 you have direct access to plotter.ren_win which is a VTK render window object. According to the docs the icon should be a vtkImageData; in practical PyVista terms this means UniformGrids with dimensions (n, m, 1).
Some experimentation suggests that the icon has to have uint8 active scalars of shape (n_points, 3) or (n_points, 4), but I could only get the icon to actually show up on my linux machine with the latter setup. It seems that non-square shaped icons get tiled to square shape, so you have to crop your image to square shape first. Finally, you need to call ren_win.Render() before setting the icon, otherwise problems arise (on my linux machine: a segmentation fault).
Here's a small example:
import numpy as np
import pyvista as pv
from pyvista import examples
# example icon: cropped puppy mesh turned from RGB to RGBA
icon = examples.download_puppy().extract_subset([0, 1199, 0, 1199, 0, 0])
data = np.empty((icon.n_points, 4), dtype=np.uint8)
data[:, :-1] = icon.point_data['JPEGImage']
data[:, -1] = 255 # pad with full opacity
icon.point_data['JPEGImage'] = data
# create a plotter with a dummy mesh and set its icon
plotter = pv.Plotter()
plotter.add_mesh(pv.Dodecahedron())
ren_win = plotter.ren_win # render window
ren_win.Render() # important against segfault
ren_win.SetIcon(icon)
plotter.show()
With this my bottom panel looks like this:
It also works for my window switcher:
(Interestingly, the window title in the title bar is "PyVista" which is the default title in pyvista.Plotter.__init__(), but in the window switcher I see "Vtk". I don't know why this is but I'll also try to see if we can fix this.)
Opacity handling seems to work too:
# add opacity in a nontrivial pattern
i, j = np.indices(icon.dimensions[:-1])
alpha = ((np.sin(2*i/icon.dimensions[0]*2*np.pi) * np.cos(j/icon.dimensions[1]*2*np.pi)) * 255).round().astype(np.uint8)
icon.point_data['JPEGImage'][:, -1] = alpha.ravel()
with this icon the window switcher looks like this:
It looks funky but that's just because the opacity pattern itself is funky. Transparency shows up as the switcher's semitransparent background colour on my system.
I'm currently looking for a simple step-by-step window renderer library for Python.
The main idea behind what I need is that I want to be able to change the input data before I call the window render function, by doing so the window would render a moving point with some additional static points. The rendered window would refresh while the program is running. For example:
# Some points
data_points_x = [2,4,6,11,22]
data_points_y = [5,-1,23,41,1]
window.add(x, y, style="point")
# Another point
important_point_x = 23
important_point_y = 13
window.add(important_point_x, important_point_y, style="star")
# Main rendering loop
while True:
# Move one point
important_point_x = important_point_x + 1
window.render()
I know matplotlib can do something similar, but I'm interested if there is any other library capable of doing more, for example, rendering text, lines and so on. Finally, pyplot does not refresh the window when calling plot.show() when the program is running.
My goal is to update an image after putting it through a filter. The image is represented as a numpy Array, and displayed with pyplot in a figure.
So far, I have tried changing the interactive mode, and calling draw() on the figure. However after doing some research, it was to my understanding that draw() is not necessary if you are using plt functions in interactive mode.
I can have it so I repeatedly show a new figure, but I'd like to update the current one so I can keep it in one window.
This is where I initially display the image:
# populating pixelData
self.pixelData = cv.imread(filename)
self.pixelData = cv.cvtColor(self.pixelData, cv.COLOR_BGR2RGB)
plt.ion()
self.image_figure.figimage(self.pixelData, resize=True)
self.image_figure.show()
and then I have a function to call after changing pixelData with one of our filters:
def update_display(self):
self.image_figure.clf()
self.image_figure.figimage(self.pixelData, resize=True)
So, to recap, I want to open up an image, then with my cli tool, modify self.pixelData, then have the displayed image update to reflect the change in self.pixelData
I have this little python script which opens up a window and puts an animated GIF inside the window. I'm using it as a screensaver (nothing fancy, really). My problem is that the GIF isn't the size of my monitor; it's quite small on the screen. What I'd like to do is to scale it to the size of the screen. I have looked into PIL as well as images2gif, but they don't give me the scaling options I require.
What I would like to do is load the animated GIF in the script, then scale it, and finally play in the window generated by PyGTK. What I've tried doing is using subprocess to capture the output from gifsicle. While this does scale the GIF I can't use it in the PyGTK part of the script because of the data returned from subprocess. What I do is:
p = subprocess.check_output(["gifsicle --scale 3.3 foo.gif"], shell=True)
The variable p has the animated GIF data, but I can't use with PyGTK in that condition. Ideally I would like to load it like this:
pixbufAn = gtk.gdk.pixbufAnimation(p)
image = gtk.Image()
image.set_from_animation(pixbufAn)
Is there a way for me to use the data from the gifsicle --scale 3.3 foo.gif call? Or is there a pure Python way of scaling the animated GIF and using it with PyGTK?
logically you can use
GdkPixbuf.Pixbuf.scale_simple ()
on all the GdkPixbuf contains within GdkPixbuf.PixbufAnimation. How to get the single GdkPixbuf.Pixbuf? Use the iter to walk through GdkPixbuf.PixbufAnimation. first iter would be
iter = GdkPixbuf.PixbufAnimation.get_iter (GLib.get_current_time() )
pbuf = iter.get_pixbuf ()
# scale the pbuf below
......
# make this on a loop
iter = iter.advance (GLib.get_current_time())
# after getting all the pbuf, pack again into GdkPixbuf.PixbufSimpleAnim
simpleanim = GdkPixbuf.PixbufSimpleAnim (width, height, rate)
# loop again
simpleanim.add_frame (pbuf)
# after done all the chores, call the
Gtk.Image.set_from_animation (simpleanim) #simpleanim implemented anim
I'm trying to use Python to programmatically save a QWidget in PyQt4 as an image (any format would be fine - PNG, PDF, JPEF, GIF...etc)
I thought this would be very straightforward, but I actually wasn't able to find anything on the web about it. Can someone point me in the right direction?
To be clear, I'm trying to do this
gui = <SOME QMainWindow>
gui.show() # this displays the gui. it's useful, but what i need is to save the image
gui.save("image.png") ## How do I do this?
You can do this using the QPixmap.grabWindow() method.
From the docs:
Grabs the contents of the window window and makes a pixmap out of it.
Returns the pixmap.
The arguments (x, y) specify the offset in the window, whereas (w, h)
specify the width and height of the area to be copied.
If w is negative, the function copies everything to the right border
of the window. If h is negative, the function copies everything to the
bottom of the window.
Note that grabWindow() grabs pixels from the screen, not from the
window. If there is another window partially or entirely over the one
you grab, you get pixels from the overlying window, too.
Note also that the mouse cursor is generally not grabbed.
The reason we use a window identifier and not a QWidget is to enable
grabbing of windows that are not part of the application, window
system frames, and so on.
Warning: Grabbing an area outside the screen is not safe in general.
This depends on the underlying window system.
Warning: X11 only: If window is not the same depth as the root window
and another window partially or entirely obscures the one you grab,
you will not get pixels from the overlying window. The contests of the
obscured areas in the pixmap are undefined and uninitialized.
Sample code:
import sys
from PyQt4.QtGui import *
filename = 'Screenshot.jpg'
app = QApplication(sys.argv)
widget = QWidget()
widget.setLayout(QVBoxLayout())
label = QLabel()
widget.layout().addWidget(label)
def take_screenshot():
p = QPixmap.grabWindow(widget.winId())
p.save(filename, 'jpg')
widget.layout().addWidget(QPushButton('take screenshot', clicked=take_screenshot))
widget.show()
app.exec_()
This will produce a window that looks like this:
When you click the button, it will create a file named Screenshot.jpg in the current directory. Said image will look like this (notice the window frame is missing):