Buffer function for python 3+ - python

I'm trying to open a vtk window using vtk_show, but my Ipython console crashes every time i do this, apparently this is because Ipython can't display an external window, which is exactly what vtk_show does. I searched on google for a solution, but it's written for python2 (i'm using python 3.6.3). Here's the solution i found:
import vtk
from IPython.display import Image
def vtk_show(renderer, width=400, height=300):
"""
Takes vtkRenderer instance and returns an IPython Image with the
rendering.
"""
renderWindow = vtk.vtkRenderWindow()
renderWindow.SetOffScreenRendering(1)
renderWindow.AddRenderer(renderer)
renderWindow.SetSize(width, height)
renderWindow.Render()
windowToImageFilter = vtk.vtkWindowToImageFilter()
windowToImageFilter.SetInput(renderWindow)
windowToImageFilter.Update()
writer = vtk.vtkPNGWriter()
writer.SetWriteToMemory(1)
writer.SetInputConnection(windowToImageFilter.GetOutputPort())
writer.Write()
data = str(buffer(writer.GetResult()))
return Image(data)
I'm getting an error while trying to use the buffer built-in function of python2, but as this function doesn't exist on python3+ i'm stuck.. If anyone could help me with this i would be very appreciated. Thanks in advance!

At least these two points must be modified on your code to have the same behavior with Python 3:
The buffer(...) built-in function in Python 2 has been replaced by memoryview(...) in Python 3: What is Python buffer type for?. Replace the buffer call by memoryview
the str(...) built-in function has to replaced by a bytes(...) call to get a bytes object: https://docs.python.org/2/howto/pyporting.html#text-versus-binary-data
So the data = ... line should read:
data = bytes(memoryview(writer.GetResult()))

To clarify, I believe this example was an adaptation of a very informative blog example showing how to extract surfaces from medical images using VTK's marching cubes algorithm. The accompanying Jupyter notebook was intended for Python 2.7, and as mentioned for it to be used in Python 3.6+, the data=... portion needs to be changed.
import vtk
from IPython.display import Image
def vtk_show(renderer, width=400, height=300):
"""
Takes vtkRenderer instance and returns an IPython Image with the
rendering.
"""
renderWindow = vtk.vtkRenderWindow()
renderWindow.SetOffScreenRendering(1)
renderWindow.AddRenderer(renderer)
renderWindow.SetSize(width, height)
renderWindow.Render()
windowToImageFilter = vtk.vtkWindowToImageFilter()
windowToImageFilter.SetInput(renderWindow)
windowToImageFilter.Update()
writer = vtk.vtkPNGWriter()
writer.SetWriteToMemory(1)
writer.SetInputConnection(windowToImageFilter.GetOutputPort())
writer.Write()
data = memoryview(writer.GetResults()).tobytes()
return Image(data)
Credit for the solution definitely goes to #MafiaSkafia and #jcgiret, but I wanted to post a full and final solution.

Related

Displaying CadQuery data in a QT5 window in Python

I wrote a python program using the PyQt5 libraries. This program I can make into an executable with pyinstaller.
I would like to add the functionality to show a 3D cad image based on user inputs. The CadQuery package has a nice intuitive approach and I would like to use it.
From the OCC.Display.qtDisplay I take my viewer. The problem is that the viewer does not accept the workplanes generated by CadQuery. I prefer not to export to files, but directly port the results from the cad generator to the viewer. Does anyone have any suggestions or experiences?
The following (partial) code works to display an AIS shape:
import OCC.Display.qtDisplay as qtDisplay
import cadquery as cq
self.canvas = qtDisplay.qtViewer3d(self)
self.horizontalLayout.addWidget(self.canvas)
a_box = BRepPrimAPI_MakeBox(10., 20., 30.).Shape()
self.ais_box = self.canvas._display.DisplayShape(a_box)[0]
self.canvas._display.FitAll()
but adding the following code (including the example bottle) does not:
self.makebottle()
self.canvas._display.DisplayShape(self.result.solids())
self.canvas._display.FitAll()
def makebottle(self):
(L,w,t) = (20.0, 6.0, 3.0)
s = cq.Workplane("XY")
# Draw half the profile of the bottle and extrude it
p = (s.center(-L/2.0, 0).vLine(w/2.0)
.threePointArc((L/2.0, w/2.0 + t),(L, w/2.0)).vLine(-w/2.0)
.mirrorX().extrude(30.0,True))
#make the neck
p = p.faces(">Z").workplane(centerOption="CenterOfMass").circle(3.0).extrude(2.0,True)
#make a shell
self.result = p.faces(">Z").shell(0.3)
Should I try to convert the workplanes? or use another package to make this work.

Rendering in blender dont take rotation updates of camera and light directions

I'm trying to render a cube (default blender scene) with a camera facing it. I have added a spotlight at the same location as the camera. Spotlight direction also faces towards the cube.
When I render, location changes take effect for both camera and spotlight but, rotations don't. scene context update is deprecated now. I have seen other update answers, but they don't seem to help.
I have done some workarounds and they seem to work, but this is not the correct way.
If I render the same set of commands twice (in a loop), I get the correct render.
If I run the script from the blender's python console (only once), I get the correct render. But If the same code is run as a script inside the blender, render is again wrong.
import pdb
import numpy as np
import bpy
def look_at(obj_camera, point):
loc_camera = obj_camera.matrix_world.to_translation()
direction = point - loc_camera
rot_quat = direction.to_track_quat('-Z', 'Y')
obj_camera.rotation_euler = rot_quat.to_euler()
data_path='some folder'
locs=np.array([ 0.00000000e+00, -1.00000000e+01, 3.00000011e-06]) #Assume, (I have big array where camera and spotlight needs to be placed, and then made to look towards cube)
obj_camera = bpy.data.objects["Camera"]
obj_other = bpy.data.objects["Cube"]
bpy.data.lights['Light'].type='SPOT'
obj_light=bpy.data.objects['Light']
loc=locs
i=0
##### if I run following lines two times, correct render is obtained.
obj_camera.location = loc
obj_light.location= obj_camera.location
look_at(obj_light, obj_other.matrix_world.to_translation())
look_at(obj_camera, obj_other.matrix_world.to_translation())
bpy.context.scene.render.filepath = data_path+'image_{}.png'.format(i)
bpy.ops.render.render(write_still = True)
You might need to call bpy.context.view_layer.update() (bpy.context.scene.update() with older versions than blender 2.8) after changing the camera orientation by obj_camera.rotation_euler = rot_quat.to_euler() and make sure that the layers that are going to be rendered are active when calling update() (see here https://blender.stackexchange.com/questions/104958/object-locations-not-updating-before-render-python).
(A bit late ;-) but this was one of the rare questions I found for a related issue.)

Adding image into Pygoocanvas

I have been trying to create a CanvasImage item in python using goocanvas however when I try to use the CanvasImage function it gives me an error.
pb = GdkPixbuf.Pixbuf.new_from_file_at_scale("image2.jpg", 1920, 1080, True)
image = GooCanvas.CanvasImage(pb, 200, 200)
TypeError: GObject.init() takes exactly 0 arguments (3 given)
Am I missing something or am I using a wrong function to create an image on the canvas.
I am referring to this as there is no proper documentation for goocanvas bindings in python: https://developer.gnome.org/goocanvas/stable/GooCanvasImage.html
If Goocanvas is not suitable for python, please suggest a different canvas that I could integrate and use in python.
Thank You
Perhaps it's the call.
This is from the goocanvas github : https://github.com/GNOME/goocanvas/blob/33694b33cc337be86d8c848825a463e52bb1a2c0/bindings/python/demo.py#L190
Also the project's github states that it is no longer supported.
An actively developed and better documented library is PyGObject.
https://pygobject.readthedocs.io/en/latest/index.html
To display images: https://lazka.github.io/pgi-docs/#Gtk-3.0/classes/Image.html#Gtk.Image

Changing Screen Resolution of Computer using python

I'm creating a python program that is supposed to streamline the process of setting up a computer. I want this python program to change the screen resolution of the computer and scaling of it. I'm not sure what the best approach is however, or how to approach it.
I've tried using an example pywin32 program, but it only outputted an array of resolution sizes
I had a look how to change screen resolution using C++ and then translated it to Python:
import win32api
import win32con
import pywintypes
devmode = pywintypes.DEVMODEType()
devmode.PelsWidth = 1366
devmode.PelsHeight = 768
devmode.Fields = win32con.DM_PELSWIDTH | win32con.DM_PELSHEIGHT
win32api.ChangeDisplaySettings(devmode, 0)
We needed a DEVMODE object to pass to the ChangeDisplaySettings function. The pywintypes module which is also part of pywin32 has a function to create objects of type DEVMODE.
We then set the PelsWidth and PelsHeight fields and also the Fields field to tell the API which field's values we want to use.
To change back to the previous resolution, simply call:
win32api.ChangeDisplaySettings(None, 0)
Thanks for asking the question. I've learned something.

Import image as plane in blender script

Import images as planes work great in blender GUI, but when I try to use it in python module, I've got this error:
RuntimeError: Operator bpy.ops.mesh.primitive_plane_add.poll() Missing 'window' in context
My code is:
import bpy
import addon_utils
# enable plugins
addon_utils.enable("io_import_images_as_planes")
# remove Cube object
bpy.data.objects['Cube'].select = True
bpy.ops.object.delete()
file = "test.jpg"
bpy.ops.import_image.to_plane(files=[{'name':file}], directory='.')
The import images as planes operator only functions within the 3dview, the current context is the window under the cursor when the script is run which would be the text editor where the script is. It is possible to override the current context, read this answer for more info.
Another option is to put your code into an operator and either run it by searching in the spacebar menu or from a button you add to the sidebar in the 3dview. You can find a template for creating a simple operator in blenders text editor or view it online.

Categories

Resources