Python rendering 3D, 2D images within a same window - vtk

I am trying to create a simple robot simulator with 3D + 2D(bird-eye view mini-map) like the below image.
My map file is just a list of vertices for polygon and center/radius for circles (all objects are heights of 1 where z = 0).
I found that python VTK plotter makes it really easy to visualize simple object but there is a lack of documentation for the multi-view windows. I also tried open-cv but it creates a 2D image in a separate window.
What would be the easiest way to achieve a simulator like below? There would be very few objects on the map so efficiency is not my concern.

My strategy for making a 2D mini-map overlay like this is to use glWindowPos2d and glDrawPixels, and I have found it to be very successful. You'll want to turn off common OpenGL features like texturing, lighting, and the depth test. In the following example, minimap_x and minimap_y are the window coordinates of the upper-left corner of the minimap.
For example:
glDisable(GL_TEXTURE_2D)
glDisable(GL_LIGHTING)
glDisable(GL_DEPTH_TEST)
glWindowPos2d(minimap_x, window_height - (minimap_y + minimap_height))
glDrawPixels(minimap_width, minimap_height, GL_RGBA, GL_UNSIGNED_BYTE, minimap_image)
glEnable(GL_TEXTURE_2D)
glEnable(GL_LIGHTING)
glEnable(GL_DEPTH_TEST)
You'll need to provide the minimap_image data.
In my applications, I'm typically using PyGame, and so the minimap is on a PyGame Surface. Converting the Surface to raw image data usable by glDrawPixels looks like this:
minimap_image = pygame.image.tostring(minimap_surface, "RGBA", True)

Related

Creating a surface plot from an Unstructured grid vtk file using Vedo

I have an unstructured grid vtk file that contains three different types of cells (Tetrahedral, Wedge and Hexahedral). This file contains multiple Scalars (8 attributes such as Pressure, Temperature e.t.c.) and a Single Vector (U,V,W) and I am trying to create a surface plot from this file for a Scalar or Vector at a time using the Vedo python wrapper for vtk. The vtk file contains a scalar or vector value for each cell, including the point coordinates.
I have read the documentation over and over, with examples here https://vtkplotter.embl.es/content/vtkplotter/index.html. These are the things that I have tried with the challenge that I am having with each method:
Method 1: Loading the file as a TetMesh
vp = Plotter()
test = load('Case_60.vtk')
vp.show(test)
This method doesn't plot Scalar Values and only shows points. No Solid Surface. Tried using a cuttertool() with it , it throws an error saying non-Tetrahedral Cell Encountered.
Method 2: Using the UGrid
ug = UGrid('Case_60.vtk')
show(ug)
This method plots as surface with a solid color. Does not seem to be picking the Scalars.
What is the proper way for me to display surface plot and display the scalar value for each cell? Is Vedo able to do what I'm trying to do?
You might need to specify which array is to be used for coloring, e.g.:
from vedo import *
ug = UGrid(datadir+'limb_ugrid.vtk')
print(ug.getArrayNames())
ug.selectCellArray('chem_0')
show(ug, axes=True)
if this doesn't work for your mesh please submit an issue here.

Python extract part of SVG to PNG

I have been doing a ton of searching but cant quite find the answer to this one.
I have a series of relatively simple SVG images. I have drawn SVG rectangles over key areas of the images that I am interested in and would now like to extract those areas as PNG images. I have no idea the best way to approach this problem.
Idea 1) Convert the whole SVG to PNG then use say PIL to crop the image down after somehow converting the SVG rect coordinates to PNG coordinates. I am starting to work towards this method now, but I am hoping there is a better, and/or easier way to do this!
I am using Python 3.7 for this.
Edit 1:
This is a screen shot of what I am looking at. The original image is SVG, I would like to extract the areas under the green rectangles as PNG images.
Edit 2:
Working from Idea 1, I have the following code that basically sets the viewBox on the SVG image to one of the green rectangles, then sets the width and height of it. From there I am using CairoSVG to export the SVG as PNG.
import cairosvg
import xml.etree.ElementTree as ET
...
with gzip.open(fileObj.filePath,'rb') as file:
svg=file.read()
svg=svg.decode('utf-8')
svgRoot=ET.fromstring(svg)
ET.register_namespace("","http://www.w3.org/2000/svg")
ET.register_namespace('xlink', "http://www.w3.org/1999/xlink")
annots = meta['annots']
for a in annots:
r = ET.fromstring(a['g'])
vb=" ".join([r.get('x'),r.get('y'),r.get('width'),r.get('height')])
svgRoot.set("viewBox",vb)
svgRoot.set("width",'128px')
svgRoot.set("height",'128px')
svg = ET.tostring(svgRoot, encoding="unicode")
cairosvg.svg2png(svg,write_to="/home/test.png")
Unfortunately it is EXTREMELY slow! On the order of more than a minute to extract two PNGs. The SVG files are quite large (2 - 3 mb zipped) and very detailed. I am not certain how CairoSVG works, but does it render everything in the SVG even if it isnt visible before saving the visible part to PNG?
Any advise on optimising or speeding this up would be a huge help.
This worked for me in the end, though it is quite slow on larger SVG images:
import gzip
import cairosvg
import xml.etree.ElementTree as ET
...
with gzip.open(fileObj.filePath,'rb') as file:
svg=file.read()
svg=svg.decode('utf-8')
svgRoot=ET.fromstring(svg)
ET.register_namespace("","http://www.w3.org/2000/svg")
ET.register_namespace('xlink', "http://www.w3.org/1999/xlink")
annots = meta['annots']
for a in annots:
r = ET.fromstring(a['g'])
vb=" ".join([r.get('x'),r.get('y'),r.get('width'),r.get('height')])
svgRoot.set("viewBox",vb)
svgRoot.set("width",'128px')
svgRoot.set("height",'128px')
svg = ET.tostring(svgRoot, encoding="unicode")
cairosvg.svg2png(svg,write_to="/home/test.png")

pixel tracing not working properly

so i got an image with a curve, and i got a function that looks for 1 pixel and then connect the adjacent pixels (like forming a path), but somehow when it is going south-west or west it does not find any pixels even if there is one.
the function goes like:
pixels=img.getpixels()
window=((1,0),(0,-1),(-1,0),(0,1),(1,1),(1,-1),(-1,-1),(-1,1))
objs=[]
obj=[pixels.pop(),]
while pixels:
p=obj[-1]
neighbours=tuple((x+p[0],y+p[1]) for x,y in window)
for n in neighbours:
if n in pixels:
obj.append(n)
pixels.remove(n)
break
if p==obj[-1]:
objs.append(obj)
obj=[pixels.pop(),]
and an example of the failure:
the original image
the objects image
each different color represents a different "object"
should it not be showing just one object?
i appreciate any thoughts on this, tyvm :D

Holding the windows to display an HSI using spectral in Python

I am using spectral to view an hyperspectral image for a specific band in python. This is my code.
from spectral import *
img=open_image('flc1.lan')
view = imshow(img)
print(view)
gt=open_image('flc1.lan').read_band(0)
view1= imshow(classes=gt)
print(view1)
The image does pop up, but then closes. Is there any kind of function like waitkey to hold the window?
As an alternative you can use :
envi.save_image(give_file_name, image_name, ext='hdr')
to save the image locally and view it later, at your discretion

How can I rotate an image (loaded by the PhotoImage class) on a canvas, without PIL or pillow?

I would like to rotate an image to follow my mouse and my school computers don't have PIL.
Bryan's answer is technically correct in that the PhotoImage class doesn't contain rotation methods, nor does tk.Canvas. But that doesn't mean we can't fix that.
def copy_img(img):
newimg = tk.PhotoImage(width=img.width(), height=img.height())
for x in range(img.width()):
for y in range(img.height()):
rgb = '#%02x%02x%02x' % img.get(x, y)
newimg.put(rgb, (x, y))
return newimg
The above function creates a blank PhotoImage object, then fills each pixel of a new PhotoImage with data from the image passed into it, making a perfect copy, pixel by pixel... Which is a useless thing to do.
But! Let's say you wanted a copy of the image that was upside-down. Change the last line in the function to:
newimg.put(rgb, (x, img.height()-1 - y))
And voila! The function still reads from the top down, but it writes from the bottom up, resulting in an image mirrored on the y axis. Want it rotated 90-degrees to the right, instead?:
newimg.put(rgb, (img.height() - y, x))
Substituting the y for the x makes it write columns for rows, effectively rotating it.
How deep you go into image processing PhotoImage objects is up to you. If you can get access to PIL (Python Imaging Library)... someone has basically already done this work, refined it to be optimal for speed and memory consumption, and packaged it into convenient classes and functions for you. But if you can't or don't want PIL, you absolutely CAN rotate PhotoImage's. You'll just have to write the methods yourself.
Thanks to acw1668's post that hipped me to the basics of PhotoImage manipulation here:
https://stackoverflow.com/a/41254261/9710971
You can't. The canvas doesn't support the ability to rotate images, and neither does the built-in PhotoImage class.
From the official Canvas documentation:
Individual items may be moved or scaled using widget commands described below, but they may not be rotated.

Resources