How to remove or replace the PyVista window icon? - python

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.

Related

How to save open3d image without the pop-up window

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)

PyQtGraph ROI RemoveHandle Does Not Remove the Circular Handle for the Ellipse ROI

My objective is code out an ellipse ROI that cannot be rotated. Consider the following piece of code modified from one of the PyQtGraph examples :
import numpy as np
import cv2
import pyqtgraph as pg
from PyQt5 import QtGui
import numpy.ma as ma
from PyQt5.QtWidgets import QMessageBox
pg.setConfigOptions(imageAxisOrder='row-major')
## Create image to display
image = cv2.imread('panda.jpg')
def picturetranspose(picture):
shape = picture.shape
result = np.empty((shape[1],shape[0],shape[2]),dtype= np.uint8)
for i in range(0,3):
result[:,:,i] = np.transpose(picture[:,:,i])
return result
arr = np.rot90(picturetranspose(image))
app = pg.mkQApp("ROI Examples")
w = pg.GraphicsLayoutWidget(show=True, size=(1000,800), border=True)
w.setWindowTitle('pyqtgraph example: ROI Examples')
w1 = w.addLayout(row=0, col=0)
v1a = w1.addViewBox(row=1, col=0, lockAspect = True)
v1a.setLimits(minXRange = arr.shape[0]//10, minYRange = arr.shape[1]//10, maxXRange = 5*arr.shape[0], maxYRange = 5*arr.shape[1])
img1a = pg.ImageItem(arr)
v1a.addItem(img1a)
rois = []
x=pg.EllipseROI([60, 10], [30, 20], pen=pg.mkPen('b', width=5),rotatable = False)
x.removeHandle(0)
rois.append(x)
for roi in rois:
roi.sigRegionChanged.connect(img1a.setImage(arr))
v1a.addItem(roi)
img1a.setImage(arr)
Here the image "panda.jpg" is given by: https://drive.google.com/drive/folders/1ejY0CjfEwS6SGS2qe_uRX2JvlruMKvPX?usp=sharing. Running the code and moving the ROI will give:
By clicking on the square light blue handle, the size of ROI can be changed. Since I set rotatable = False, the ROI cannot be rotated and clicking on the circular handle will not rotate the ROI .
However, the line x.removeHandle(0) should delete the light blue circular handle so that it does not show up on the screen at all . Is this a bug? What am I missing ?
When a QGraphicsItem is created it's not immediately added to a scene, and in that time frame some scene-related aspects are "stored" until the item is actually put to a scene. Some of those properties are pretty obvious (such as the item position), but others are not. One of them is adding child items. When a "main" item is added to the scene, all of its children (and grandchildren, great-grandchildren, etc.) are added along with it.
This is what happens when a ROI is created: its handles are created in its __init__ (see the sources), but removeHandle() only removes the handle from the scene if the ROI actually has a scene().
Remember that PyQt (and PySide) are bindings to Qt, meaning that we always work with python wrappers around C++ objects. Even when the last reference to a python object is deleted, only the python object is actually deleted, but if that object is a wrapper around a C++ object and that object has a parent, the actual object is not deleted after all.
While pyqtgraph removes the handle from its internal list, the C++ object that represents the handle still exists as a child of the ROI, so, when the ROI is added to the scene, the handle still exists.
A possible solution is to remove the handles after the ROI has been added to the scene:
for roi in rois:
roi.sigRegionChanged.connect(img1a.setImage(arr))
v1a.addItem(roi)
roi.removeHandle(0)
This works because removeHandle only removes the handle when a scene exists for the item, and in this way the child item can be actually removed from the scene.
Note that, according to the sources, EllipseROI adds two handles: rotate and scale. You will probably want to remove all of them:
for roi in rois:
roi.sigRegionChanged.connect(img1a.setImage(arr))
v1a.addItem(roi)
while roi.handles:
roi.removeHandle(0)
I suggest you to file a report on the pyqtgraph repository about this, solving it on their side should be pretty easy.

animating image stack with vispy

I'm trying to migrate from MATLAB to Python and one of the things I frequently rely on during development in Matlab is the ability to rapidly visualize slices of a datacube by looping through layers and calling drawnow, e.g.
tst = randn(1000,1000,100);
for n = 1:size(tst, 3)
imagesc(tst(:,:,n));
drawnow;
end
When I tic/toc this in MATLAB it shows that the figure is updating at about 28fps. In contrast, when I try to do this using matplotlib's imshow() command this runs at a snails pace in comparison, even using set_data().
import matplotlib as mp
import matplotlib.pyplot as plt
import numpy as np
tmp = np.random.random((1000,1000,100))
myfig = plt.imshow(tmp[:,:,i], aspect='auto')
for i in np.arange(0,tmp.shape[2]):
myfig.set_data(tmp[:,:,i])
mp.pyplot.title(str(i))
mp.pyplot.pause(0.001)
On my computer this runs at about 16fps with the default (very small) scale, and if I resize it to be larger and the same size as the matlab figure it slows down to about 5 fps. From some older threads I saw a suggestion to use glumpy and I installed this along with all of the appropriate packages and libraries (glfw, etc.), and the package itself works fine but it no longer supports the easy image visualization that was suggested in a previous thread.
I then downloaded vispy, and I can make an image with it using code from this thread as a template:
import sys
from vispy import scene
from vispy import app
import numpy as np
canvas = scene.SceneCanvas(keys='interactive')
canvas.size = 800, 600
canvas.show()
# Set up a viewbox to display the image with interactive pan/zoom
view = canvas.central_widget.add_view()
# Create the image
img_data = np.random.random((800,800, 3))
image = scene.visuals.Image(img_data, parent=view.scene)
view.camera.set_range()
# unsuccessfully tacked on the end to see if I can modify the figure.
# Does nothing.
img_data_new = np.zeros((800,800, 3))
image = scene.visuals.Image(img_data_new, parent=view.scene)
view.camera.set_range()
Vispy seems very fast and this looks like it will get me there, but how do you update the canvas with new data? Thank you,
See ImageVisual.set_data method
# Create the image
img_data = np.random.random((800,800, 3))
image = scene.visuals.Image(img_data, parent=view.scene)
view.camera.set_range()
# Generate new data :
img_data_new = np.zeros((800,800, 3))
img_data_new[400:, 400:, 0] = 1. # red square
image.set_data(img_data_new)

Manipulate color of QImage - QT

I have one generic icon image, which has an alpha. Lets say a black sphere placed on an square button, with transparancy.
Now I would like to change the color of the icon on the fly, without having several image of sphere_black.png, sphere_red.png etc etc.
Is there a way to colorize the pixmap, respecting the alpha and change HSV on that pixel, for all in the map?
I have something like this, but stuck:
img = QtGui.QImage(kwargs['icon_path']
pxmap = QtGui.QPixmap(img)
for x in range(img.width()):
for y in range(img.height()):
print img.pixel(1, 1), '###'
# ???? #
Any help is appreciated!
QGraphicsColorizeEffect might be what you are looking for. Sadly the QGraphicsEffect class is made to be used with the graphics view framework, it can't easily be applied to a QImage. However there are workarounds for that, as this discussion shows.
The implementation of the effect in QPixmapColorizeFilter::draw() shows how the colourization is done: A coloured rect (with the color having the alpha set to something else than fully opaque) is drawn over the image with QPainter::fillRect(), with an appropriate composition mode set.

How to scale down pixbuf image without losing quality?

I have a pixbuf image and I want to save it to pdf using cairo. Because the pixbuf is too large, I want to scale it down. I use scale_simple method. But, the scaled result became blur. Below is the screenshot I take. The real image is on the right and on the left is image from pdf
Do you know how to scale down pixbuf without losing its quality? Below is just my sample code.
from gi.repository import GdkPixbuf, Gdk
import cairo
class gui():
def __init__(self):
pix = GdkPixbuf.Pixbuf.new_from_file('tux2.png')
pix = pix.scale_simple(pix.get_width() / 3, pix.get_height() / 3, GdkPixbuf.InterpType.HYPER)
ps = cairo.PDFSurface('pix.pdf', 500, 500)
cr = cairo.Context(ps)
Gdk.cairo_set_source_pixbuf(cr, pix, 0, 0)
cr.paint()
if __name__ == '__main__':
gui()
You should not scale the pixbuf at all.
Instead you should scale the object (pixbuf as is).
It will look something like this:
cr.save()
cr.scale(scale_xy, scale_xy)
cr.xxx_place_image(...)
cr.restore()
What about recreating this particular image using PDF commands? It's vector format and you may design similar image in svg and import it.Image scaling is a fatal process of loosing actual color data, cause approximation takes place. Use advanced scaling algorithm, Lanczos filtering for example.

Categories