def test_surface(): N = 128 x = np.linspace(-1,1,N) Z,Y,X = np.meshgrid(x,x,x,indexing="ij") R = np.sqrt(X**2+Y**2+Z**2) data = 900.*np.exp(-10*R) #data = 200*(1+Z) rend = VolumeRenderer((400,400)) rend.set_modelView(mat4_translate(0,0,-5.)) rend.render(data=data.astype(np.uint16), maxVal = 20., method="iso_surface") #rend.render(data=data.astype(np.float32), maxVal = 100., method="max_project") # drawing plt.ion() plt.figure(1) plt.clf() plt.imshow(rend.output) plt.axis("off") plt.show() plt.pause(1.) plt.close() return rend
def rend_const(): from gputools.utils.utils import remove_cache_dir, get_cache_dir remove_cache_dir() data = (123*np.ones((100,100,100))).astype(np.float32) rend = VolumeRenderer((4,4)) rend.render(data, maxVal = 200.) return rend
def __init__(self, parent=None, N_PREFETCH=0, interpolation="linear", **kwargs): logger.debug("init") # # fmt = QtOpenGL.QGLFormat(QtOpenGL.QGL.AlphaChannel) # # super(GLWidget, self).__init__(fmt,parent, **kwargs) super(GLWidget, self).__init__(parent, **kwargs) self.parent = parent self.texture_LUT = None self.setAcceptDrops(True) self.renderer = VolumeRenderer( (spimagine.config.__DEFAULT_TEXTURE_WIDTH__, spimagine.config.__DEFAULT_TEXTURE_WIDTH__), interpolation=interpolation) self.renderer.set_projection(mat4_perspective(60, 1., .1, 100)) # self.renderer.set_projection(projMatOrtho(-2,2,-2,2,-10,10)) self.output = np.zeros([self.renderer.height, self.renderer.width], dtype=np.float32) self.output_alpha = np.zeros( [self.renderer.height, self.renderer.width], dtype=np.float32) self.sliceOutput = np.zeros((100, 100), dtype=np.float32) self.setTransform(TransformModel()) self.renderTimer = QtCore.QTimer(self) self.renderTimer.setInterval(10) self.renderTimer.timeout.connect(self.onRenderTimer) self.renderTimer.start() self.renderedSteps = 0 self.N_PREFETCH = N_PREFETCH self.NSubrenderSteps = 1 self.dataModel = None self.meshes = [] # self.setMouseTracking(True) self._dataModelChanged.connect(self.dataModelChanged) self.refresh()
def rend_const(): from gputools.utils.utils import remove_cache_dir, get_cache_dir remove_cache_dir() data = (123 * np.ones((100, 100, 100))).astype(np.float32) rend = VolumeRenderer((4, 4)) rend.render(data, maxVal=200.) return rend
def test_speed_multipass(): import time from gputools import get_device N = 256 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R = np.sqrt(X**2 + Y**2 + Z**2) d = 200 * np.exp(-10 * R**2) rend = VolumeRenderer((800, ) * 2) rend.set_modelView(mat4_translate(0, 0, -10.)) rend.set_data(d.astype(np.float32)) get_device().queue.finish() for niter in range(1, 10): get_device().queue.finish() t = time.time() rend.render(method="max_project", maxVal=200., currentPart=0, numParts=niter) get_device().queue.finish() print("time to render with %s substeps:\t %.2f ms" % (niter, 1000 * (time.time() - t))) return rend
def test_simple(): N = 64 d = np.linspace(0, 1, N**3).reshape((N,)*3).astype(np.float32) rend = VolumeRenderer((400, 400)) rend.set_data(d) rend.render() out = rend.output plt.imshow(out) plt.show() plt.pause(0.1) plt.close() return 1
def test_nearest(): import matplotlib.pyplot as plt N = 64 d = np.random.rand(N**3).reshape((N,)*3).astype(np.float32) rend = VolumeRenderer((400, 400), 'nearest') rend.set_data(d) rend.render() out = rend.output plt.imshow(out) plt.show() plt.pause(.1) plt.close() return 1
def test_speed_multipass(): import time from gputools import get_device N = 256 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R = np.sqrt(X ** 2 + Y ** 2 + Z ** 2) d = 200 * np.exp(-10 * R ** 2) rend = VolumeRenderer((800,) * 2) rend.set_modelView(mat4_translate(0, 0, -10.)) rend.set_data(d.astype(np.float32)) get_device().queue.finish() for niter in range(1, 10): get_device().queue.finish() t = time.time() rend.render(method="max_project", maxVal=200., currentPart=0, numParts=niter) get_device().queue.finish() print("time to render with %s substeps:\t %.2f ms" % (niter, 1000 * (time.time() - t))) return rend
def test_surface(): N = 128 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R = np.sqrt(X**2 + Y**2 + Z**2) data = 900. * np.exp(-10 * R) #data = 200*(1+Z) rend = VolumeRenderer((400, 400)) rend.set_modelView(mat4_translate(0, 0, -5.)) rend.render(data=data.astype(np.uint16), maxVal=20., method="iso_surface") #rend.render(data=data.astype(np.float32), maxVal = 100., method="max_project") # drawing #plt.ioff() plt.figure(1) plt.clf() plt.imshow(rend.output) plt.axis("off") plt.close() plt.show() plt.pause(.1) plt.close() return rend
def test_opacity(): N = 128 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R = np.sqrt(X**2 + Y**2 + Z**2) d = 200 * np.exp(-10 * R**2) rend = VolumeRenderer((600, ) * 2) rend.set_modelView(mat4_translate(0, 0, -10.)) rend.set_alpha_pow(.6) rend.set_data(d.astype(np.float32)) rend.render(method="max_project", maxVal=200.) out = rend.output plt.imshow(out, cmap="magma") plt.axis("off") plt.show() return rend
def test_simple_rendering(): from gputools.utils.utils import remove_cache_dir, get_cache_dir remove_cache_dir() dtypes = [np.float32, np.uint16] # build some test data N = 128 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R1 = np.sqrt((X - .2)**2 + Y**2 + Z**2) R2 = np.sqrt((X + .2)**2 + Y**2 + Z**2) data = 255 * np.exp(-30 * R1**2) + np.exp(-30 * R2**2) rend = VolumeRenderer((400, 400)) outs = [] for dtype in dtypes: rend.render(data=data.astype(dtype), maxVal=255.) outs.append(rend.output) # drawing plt.figure(1) plt.clf() for i, out in enumerate(outs): plt.subplot(1, len(outs), i + 1) plt.imshow(out) plt.axis("off") plt.title("%s" % (dtype)) plt.pause(.1) plt.close() plt.show() plt.pause(.1) plt.close() return rend
def test_simple_rendering(): from gputools.utils.utils import remove_cache_dir, get_cache_dir remove_cache_dir() dtypes = [np.float32, np.uint16] # build some test data N = 128 x = np.linspace(-1,1,N) Z,Y,X = np.meshgrid(x,x,x,indexing="ij") R1 = np.sqrt((X-.2)**2+Y**2+Z**2) R2 = np.sqrt((X+.2)**2+Y**2+Z**2) data = 255*np.exp(-30*R1**2)+ np.exp(-30*R2**2) rend = VolumeRenderer((400,400)) outs = [] for dtype in dtypes: rend.render(data=data.astype(dtype), maxVal = 255.) outs.append(rend.output) # drawing plt.figure(1) plt.ion() plt.clf() for i,out in enumerate(outs): plt.subplot(1,len(outs),i+1) plt.imshow(out) plt.axis("off") plt.title("%s"%(dtype)) plt.pause(.1) plt.show() plt.pause(1.) plt.close() return rend
def __init__(self, parent=None, N_PREFETCH=0, interpolation="linear", **kwargs): logger.debug("init") # # fmt = QtOpenGL.QGLFormat(QtOpenGL.QGL.AlphaChannel) # # super(GLWidget, self).__init__(fmt,parent, **kwargs) super(GLWidget, self).__init__(parent, **kwargs) self.parent = parent self.texture_LUT = None self.setAcceptDrops(True) self.renderer = VolumeRenderer((spimagine.config.__DEFAULT_TEXTURE_WIDTH__, spimagine.config.__DEFAULT_TEXTURE_WIDTH__), interpolation=interpolation) self.renderer.set_projection(mat4_perspective(60, 1., .1, 100)) # self.renderer.set_projection(projMatOrtho(-2,2,-2,2,-10,10)) self.output = np.zeros([self.renderer.height, self.renderer.width], dtype=np.float32) self.output_alpha = np.zeros([self.renderer.height, self.renderer.width], dtype=np.float32) self.sliceOutput = np.zeros((100, 100), dtype=np.float32) self.setTransform(TransformModel()) self.renderTimer = QtCore.QTimer(self) self.renderTimer.setInterval(10) self.renderTimer.timeout.connect(self.onRenderTimer) self.renderTimer.start() self.renderedSteps = 0 self.N_PREFETCH = N_PREFETCH self.NSubrenderSteps = 1 self.dataModel = None self.meshes = [] # self.setMouseTracking(True) self._dataModelChanged.connect(self.dataModelChanged) self.refresh()
def test_opacity(): N = 128 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R = np.sqrt(X ** 2 + Y ** 2 + Z ** 2) d = 200 * np.exp(-10 * R ** 2) rend = VolumeRenderer((600,) * 2) rend.set_modelView(mat4_translate(0, 0, -10.)) rend.set_alpha_pow(.6) rend.set_data(d.astype(np.float32)) rend.render(method="max_project", maxVal=200.) out = rend.output plt.imshow(out, cmap="magma") plt.axis("off") plt.show() return rend
def test_simple(): N = 64 d = np.linspace(0, 1, N**3).reshape((N, ) * 3).astype(np.float32) rend = VolumeRenderer((400, 400)) rend.set_data(d) rend.render() out = rend.output plt.imshow(out) plt.show() plt.pause(0.1) plt.close() return 1
def test_nearest(): import matplotlib.pyplot as plt N = 64 d = np.random.rand(N**3).reshape((N, ) * 3).astype(np.float32) rend = VolumeRenderer((400, 400), 'nearest') rend.set_data(d) rend.render() out = rend.output plt.imshow(out) plt.show() plt.pause(.1) plt.close() return 1
def test_time_to_render(): import time from gputools import get_device get_device().print_info() N = 256 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R = np.sqrt(X**2 + Y**2 + Z**2) d = 10000 * np.exp(-10 * R**2) rend = VolumeRenderer((600, 600)) rend.set_modelView(mat4_translate(0, 0, -10.)) # rend.set_box_boundaries(.3*np.array([-1,1,-1,1,-1,1])) t1 = time.time() get_device().queue.finish() rend.set_data(d, autoConvert=True) get_device().queue.finish() t2 = time.time() get_device().queue.finish() rend.render(maxVal=10000.) out = rend.output get_device().queue.finish() print("time to set data %s^3:\t %.2f ms" % (N, 1000 * (t2 - t1))) print("time to render %s^3:\t %.2f ms" % (N, 1000 * (time.time() - t2))) return d, rend, out
def render_iso(data, t = -.8): from gputools.utils.utils import remove_cache_dir, get_cache_dir remove_cache_dir() rend = VolumeRenderer((400,400)) # rend.set_occ_strength(0) # rend.set_occ_radius(21) # rend.set_occ_n_points(30) rend.set_modelView(mat4_translate(0, 0, t)) rend.render(data, maxVal = 130., method="iso_surface") return rend
def test_time_to_render(): import time from gputools import get_device get_device().print_info() N = 256 x = np.linspace(-1, 1, N) Z, Y, X = np.meshgrid(x, x, x, indexing="ij") R = np.sqrt(X**2+Y**2+Z**2) d = 10000*np.exp(-10*R**2) rend = VolumeRenderer((600, 600)) rend.set_modelView(mat4_translate(0, 0, -10.)) # rend.set_box_boundaries(.3*np.array([-1,1,-1,1,-1,1])) t1 = time.time() get_device().queue.finish() rend.set_data(d, autoConvert=True) get_device().queue.finish() t2 = time.time() get_device().queue.finish() rend.render(maxVal=10000.) out = rend.output get_device().queue.finish() print("time to set data %s^3:\t %.2f ms"%(N, 1000*(t2-t1))) print("time to render %s^3:\t %.2f ms"%(N, 1000*(time.time()-t2))) return d, rend, out
class GLWidget(QtOpenGL.QGLWidget): _dataModelChanged = QtCore.pyqtSignal() _BACKGROUND_BLACK = (0., 0., 0., 0.) _BACKGROUND_WHITE = (1., 1., 1., 0.) def __init__(self, parent=None, N_PREFETCH=0, interpolation="linear", **kwargs): logger.debug("init") # # fmt = QtOpenGL.QGLFormat(QtOpenGL.QGL.AlphaChannel) # # super(GLWidget, self).__init__(fmt,parent, **kwargs) super(GLWidget, self).__init__(parent, **kwargs) self.parent = parent self.texture_LUT = None self.setAcceptDrops(True) self.renderer = VolumeRenderer( (spimagine.config.__DEFAULT_TEXTURE_WIDTH__, spimagine.config.__DEFAULT_TEXTURE_WIDTH__), interpolation=interpolation) self.renderer.set_projection(mat4_perspective(60, 1., .1, 100)) # self.renderer.set_projection(projMatOrtho(-2,2,-2,2,-10,10)) self.output = np.zeros([self.renderer.height, self.renderer.width], dtype=np.float32) self.output_alpha = np.zeros( [self.renderer.height, self.renderer.width], dtype=np.float32) self.sliceOutput = np.zeros((100, 100), dtype=np.float32) self.setTransform(TransformModel()) self.renderTimer = QtCore.QTimer(self) self.renderTimer.setInterval(10) self.renderTimer.timeout.connect(self.onRenderTimer) self.renderTimer.start() self.renderedSteps = 0 self.N_PREFETCH = N_PREFETCH self.NSubrenderSteps = 1 self.dataModel = None self.meshes = [] # self.setMouseTracking(True) self._dataModelChanged.connect(self.dataModelChanged) self.refresh() # self.installEventFilter(self) def set_background_mode_black(self, mode_back=True): self._background_mode_black = mode_back self.refresh() def setModel(self, dataModel): logger.debug("setModel to %s" % dataModel) if self.dataModel is None or (self.dataModel != dataModel): self.dataModel = dataModel self.transform.setModel(dataModel) self.dataModel._dataSourceChanged.connect(self.dataSourceChanged) self.dataModel._dataPosChanged.connect(self.dataPosChanged) self._dataModelChanged.emit() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): for url in event.mimeData().urls(): # path = url.toLocalFile().toLocal8Bit().data() path = url.toLocalFile() if spimagine.config.__SYSTEM_DARWIN__: path = spimagine.config._parseFileNameFix(path) self.setCursor(QtCore.Qt.BusyCursor) if self.dataModel: self.dataModel.loadFromPath(path, prefetchSize=self.N_PREFETCH) else: self.setModel( DataModel.fromPath(path, prefetchSize=self.N_PREFETCH)) self.setCursor(QtCore.Qt.ArrowCursor) def set_colormap(self, name): """name should be either jet, hot, gray, coolwarm""" try: arr = spimagine.config.__COLORMAPDICT__[name] self._set_colormap_array(arr) except KeyError: print("could not load colormap '%s'" % name) print("valid names: %s" % list(spimagine.config.__COLORMAPDICT__.keys())) def set_colormap_rgb(self, color=[1., 1., 1.]): self._set_colormap_array( np.outer(np.linspace(0, 1., 255), np.array(color))) def _set_colormap_array(self, arr): """arr should be of shape (N,3) and gives the rgb components of the colormap""" self.makeCurrent() self.texture_LUT = fillTexture2d(arr.reshape((1, ) + arr.shape), self.texture_LUT) self.refresh() def _shader_from_file(self, fname_vert, fname_frag): shader = QOpenGLShaderProgram() shader.addShaderFromSourceFile(QOpenGLShader.Vertex, fname_vert) shader.addShaderFromSourceFile(QOpenGLShader.Fragment, fname_frag) shader.link() shader.bind() logger.debug("GLSL program log:%s", shader.log()) return shader def initializeGL(self): self.resized = True logger.debug("initializeGL") self.programTex = self._shader_from_file( absPath("shaders/texture.vert"), absPath("shaders/texture.frag")) self.programCube = self._shader_from_file(absPath("shaders/box.vert"), absPath("shaders/box.frag")) self.programSlice = self._shader_from_file( absPath("shaders/slice.vert"), absPath("shaders/slice.frag")) self.programMesh = self._shader_from_file(absPath("shaders/mesh.vert"), absPath("shaders/mesh.frag")) self.programMeshLight = self._shader_from_file( absPath("shaders/mesh_light.vert"), absPath("shaders/mesh_light.frag")) self.texture = None self.textureAlpha = None self.textureSlice = None self.quadCoord = np.array([[-1., -1., 0.], [1., -1., 0.], [1., 1., 0.], [1., 1., 0.], [-1., 1., 0.], [-1., -1., 0.]]) self.quadCoordTex = np.array([[0, 0], [1., 0.], [1., 1.], [1., 1.], [0, 1.], [0, 0]]) # self.cubeCoords = create_cube_coords([-1,1,-1,1,-1,1]) self.set_colormap(spimagine.config.__DEFAULTCOLORMAP__) glEnable(GL_BLEND) # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # self.set_interpolation(spimagine.config.__DEFAULT_INTERP__ != "nearest") # glLineWidth(1.0); glBlendFunc(GL_ONE, GL_ONE) glEnable(GL_LINE_SMOOTH) glDisable(GL_DEPTH_TEST) glLineWidth(spimagine.config.__DEFAULT_BOX_LINEWIDTH__) # self.set_background_color(0,0,0,.0) self.set_background_mode_black(True) self.clear_canvas() # self.set_background_color(1,1,1,.6) def clear_canvas(self): if self._background_mode_black: glClearColor(*self._BACKGROUND_BLACK) else: glClearColor(*self._BACKGROUND_WHITE) if glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) def set_interpolation(self, interpolate=True): interp = "linear" if interpolate else "nearest" self.renderer.rebuild_program(interpolation=interp) self.refresh() def setTransform(self, transform): self.transform = transform self.transform._transformChanged.connect(self.refresh) self.transform._stackUnitsChanged.connect(self.setStackUnits) self.transform._boundsChanged.connect(self.setBounds) def dataModelChanged(self): logger.debug("+++++++++ data model changed") if self.dataModel: logger.debug("dataModelchanged") self.renderer.set_data(self.dataModel[0], autoConvert=True) mi, ma = self._get_min_max() self.transform.reset(minVal=mi, maxVal=ma, stackUnits=self.dataModel.stackUnits()) self.meshes = [] self.refresh() def _get_min_max(self): # as amax is too slow for bug arrays, do it on the gpu if self.dataModel: try: im = self.renderer.dataImg tmp_buf = OCLArray.empty(im.shape, im.dtype) tmp_buf.copy_image(im) mi = float(cl_array.min(tmp_buf).get()) ma = float(cl_array.max(tmp_buf).get()) except Exception as e: print(e) mi = np.amin(self.dataModel[0]) ma = np.amax(self.dataModel[0]) return mi, ma def set_background_color(self, r, g, b, a=1.): self._background_color = (r, g, b, a) glClearColor(r, g, b, a) def dataSourceChanged(self): logger.debug("dataSourcechanged") self.renderer.set_data(self.dataModel[0], autoConvert=True) mi, ma = self._get_min_max() self.transform.reset(minVal=mi, maxVal=ma, stackUnits=self.dataModel.stackUnits()) self.refresh() def setBounds(self, x1, x2, y1, y2, z1, z2): self.cubeCoords = create_cube_coords([x1, x2, y1, y2, z1, z2]) self.renderer.set_box_boundaries([x1, x2, y1, y2, z1, z2]) def setStackUnits(self, px, py, pz): logger.debug("setStackUnits to %s" % [px, py, pz]) self.renderer.set_units([px, py, pz]) def dataPosChanged(self, pos): self.renderer.update_data(self.dataModel[pos]) self.refresh() def refresh(self): # if self.parentWidget() and self.dataModel: # self.parentWidget().setWindowTitle("SpImagine %s"%self.dataModel.name()) self.renderUpdate = True self.renderedSteps = 0 def resizeGL(self, width, height): # somehow in qt5 the OpenGLWidget width/height parameters above are double the value of self.width/height self._viewport_width, self._viewport_height = width, height def add_mesh(self, mesh=SphericalMesh()): """ adds a mesh with vertices and facecolor/edgecolor to be drawn mesh is an instance of spimagine.gui.Mesh, e.g. mesh = Mesh(vertices = [[0,1,0],[0,1,0],...], normals = [[0,1,0],[0,1,0],...], facecolor = (1.,.4,.4,.2), edgecolor = None,...) there are some predefined meshes like SphericalMesh, EllipsoidMesh ... """ self.meshes.append([ mesh, glvbo.VBO(mesh.vertices.astype(np.float32, copy=False)), glvbo.VBO(np.array(mesh.normals).astype(np.float32, copy=False)), glvbo.VBO(np.array(mesh.indices).astype(np.uint32, copy=False), target=GL_ELEMENT_ARRAY_BUFFER) ]) self.refresh() # sort according to opacity as the opaque objects should be drawn first # self.meshes.sort(key=lambda x: x[0].alpha, reverse=True) def _paintGL_render(self): # Draw the render texture self.programTex.bind() self.texture = fillTexture2d(self.output, self.texture) # self.textureAlpha = fillTexture2d(self.output_alpha, self.textureAlpha) glEnable(GL_BLEND) glEnable(GL_TEXTURE_2D) glDisable(GL_DEPTH_TEST) self.programTex.enableAttributeArray("position") self.programTex.enableAttributeArray("texcoord") self.programTex.setAttributeArray("position", self.quadCoord) self.programTex.setAttributeArray("texcoord", self.quadCoordTex) self.programTex.setUniformValue("is_mode_black", self._background_mode_black) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, self.texture) self.programTex.setUniformValue("texture", 0) glActiveTexture(GL_TEXTURE1) glBindTexture(GL_TEXTURE_2D, self.textureAlpha) self.programTex.setUniformValue("texture_alpha", 1) glActiveTexture(GL_TEXTURE2) glBindTexture(GL_TEXTURE_2D, self.texture_LUT) self.programTex.setUniformValue("texture_LUT", 2) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDrawArrays(GL_TRIANGLES, 0, len(self.quadCoord)) def _paintGL_slice(self): # draw the slice self.programSlice.bind() self.programSlice.setUniformValue( "mvpMatrix", QtGui.QMatrix4x4(*self._mat_modelviewproject.flatten())) self.programSlice.setUniformValue("is_mode_black", self._background_mode_black) self.programSlice.enableAttributeArray("position") pos, dim = self.transform.slicePos, self.transform.sliceDim coords = slice_coords(1. * pos / self.dataModel.size()[2 - dim + 1], dim) texcoords = [[0., 0.], [1, 0.], [1., 1.], [1., 1.], [0., 1.], [0., 0.]] self.programSlice.setAttributeArray("position", coords) self.programSlice.setAttributeArray("texcoord", texcoords) self.textureSlice = fillTexture2d(self.sliceOutput, self.textureSlice) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, self.textureSlice) self.programSlice.setUniformValue("texture", 0) glActiveTexture(GL_TEXTURE1) glBindTexture(GL_TEXTURE_2D, self.texture_LUT) self.programSlice.setUniformValue("texture_LUT", 1) glDrawArrays(GL_TRIANGLES, 0, len(coords)) def _paintGL_box(self): glEnable(GL_BLEND) # Draw the cube self.programCube.bind() self.programCube.setUniformValue( "mvpMatrix", QtGui.QMatrix4x4(*self._mat_modelviewproject.flatten())) self.programCube.enableAttributeArray("position") if self._background_mode_black: self.programCube.setUniformValue("color", QtGui.QVector4D(1, 1, 1, 0.6)) else: self.programCube.setUniformValue("color", QtGui.QVector4D(0, 0, 0, 0.6)) self.programCube.setAttributeArray("position", self.cubeCoords) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, self.textureAlpha) self.programCube.setUniformValue("texture_alpha", 0) glEnable(GL_DEPTH_TEST) # glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDrawArrays(GL_LINES, 0, len(self.cubeCoords)) glDisable(GL_DEPTH_TEST) def _paintGL_mesh(self, mesh, vbo_vertices, vbo_normals, vbo_indices): """ paint a mesh (which has all the coordinates and colors in it """ glEnable(GL_DEPTH_TEST) glDisable(GL_BLEND) prog = self.programMeshLight prog.bind() prog.setUniformValue( "mvpMatrix", QtGui.QMatrix4x4(*self._mat_modelviewproject.flatten())) prog.setUniformValue("mvMatrix", QtGui.QMatrix4x4(*self._mat_modelview.flatten())) prog.setUniformValue("normMatrix", QtGui.QMatrix4x4(*self._mat_normal.flatten())) if mesh.light: prog.setUniformValue("light", QtGui.QVector3D(*mesh.light)) prog.setUniformValue("light_components", QtGui.QVector3D(.2, .5, .3)) else: prog.setUniformValue("light", QtGui.QVector3D(0, 0, 0)) prog.setUniformValue("light_components", QtGui.QVector3D(1., 0, 0)) if not mesh.facecolor is None: r, g, b = mesh.facecolor[:3] a = mesh.alpha prog.setUniformValue("color", QtGui.QVector4D(r, g, b, a)) prog.enableAttributeArray("position") vbo_vertices.bind() glVertexAttribPointer(prog.attributeLocation("position"), 3, GL_FLOAT, GL_FALSE, 0, vbo_vertices) prog.enableAttributeArray("normal") vbo_normals.bind() glVertexAttribPointer(prog.attributeLocation("normal"), 3, GL_FLOAT, GL_FALSE, 0, vbo_normals) vbo_indices.bind() glDrawElements(GL_TRIANGLES, len(vbo_indices.data), GL_UNSIGNED_INT, None) vbo_indices.unbind() vbo_vertices.unbind() glDisable(GL_DEPTH_TEST) prog.disableAttributeArray("position") prog.disableAttributeArray("normal") # # if not mesh.edgecolor is None: # r, g, b = mesh.edgecolor # a = mesh.alpha # # prog.enableAttributeArray("position") # vbo_vertices.bind() # glVertexAttribPointer(prog.attributeLocation("position"), 2, GL_FLOAT, GL_FALSE, 0, vbo_edges) # # prog.setUniformValue("color", # QtGui.QVector4D(r, g, b, a)) # # glDrawArrays(GL_LINES, 0, len(mesh.edges)) def paintGL(self): self.makeCurrent() if not glCheckFramebufferStatus( GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE: return w = max(self._viewport_width, self._viewport_height) # force viewport to always be a square glViewport((self._viewport_width - w) // 2, (self._viewport_height - w) // 2, w, w) self.clear_canvas() self._mat_modelview = self.transform.getModelView() self._mat_proj = self.transform.getProjection() self._mat_normal = np.linalg.inv(self._mat_modelview).T self._mat_modelviewproject = np.dot(self._mat_proj, self._mat_modelview) if self.dataModel: self.textureAlpha = fillTexture2d(self.output_alpha, self.textureAlpha) if self.transform.isBox: self._paintGL_box() if self.transform.isSlice and self.sliceOutput is not None: self._paintGL_slice() self._paintGL_render() for (m, vbo_verts, vbo_normals, vbo_indices) in self.meshes: self._paintGL_mesh(m, vbo_verts, vbo_normals, vbo_indices) def render(self): logger.debug("render") if self.dataModel: self.renderer.set_modelView(self.transform.getUnscaledModelView()) self.renderer.set_projection(self.transform.getProjection()) self.renderer.set_min_val(self.transform.minVal) self.renderer.set_max_val(self.transform.maxVal) self.renderer.set_gamma(self.transform.gamma) self.renderer.set_alpha_pow(self.transform.alphaPow) self.renderer.set_occ_strength(self.transform.occ_strength) self.renderer.set_occ_radius(self.transform.occ_radius) self.renderer.set_occ_n_points(self.transform.occ_n_points) if self.transform.isIso: renderMethod = "iso_surface" else: renderMethod = "max_project" self.renderer.render( method=renderMethod, return_alpha=True, numParts=self.NSubrenderSteps, currentPart=(self.renderedSteps * _next_golden(self.NSubrenderSteps)) % self.NSubrenderSteps) self.output, self.output_alpha = self.renderer.output, self.renderer.output_alpha if self.transform.isSlice: if self.transform.sliceDim == 0: out = self.dataModel[ self.transform.dataPos][:, :, self.transform.slicePos] elif self.transform.sliceDim == 1: out = self.dataModel[ self.transform.dataPos][:, self.transform.slicePos, :] elif self.transform.sliceDim == 2: out = self.dataModel[self.transform.dataPos][ self.transform.slicePos, :, :] min_out, max_out = np.amin(out), np.amax(out) if max_out > min_out: self.sliceOutput = (1. * (out - min_out) / (max_out - min_out)) else: self.sliceOutput = np.zeros_like(out) # def getFrame(self): # self.render() # self.paintGL() # glFlush() # im = self.grabFrameBuffer() # im = im.convertToFormat(QtGui.QImage.Format_RGB32) # # width = im.width() # height = im.height() # # ptr = im.bits() # ptr.setsize(im.byteCount()) # arr = np.array(ptr).reshape(height, width, 4) # Copies the data # return arr[..., [2, 1, 0, 3]].copy() def saveFrame(self, fName, with_alpha=False): """FIXME: scaling behaviour still hast to be implemented (e.g. after setGamma)""" logger.info("saving frame as %s", fName) # has to be png name, ext = os.path.splitext(fName) if ext != ".png": fName = name + ".png" self.render() self.paintGL() glFlush() im = self.grabFrameBuffer(withAlpha=with_alpha) im.save(fName) def onRenderTimer(self): # if self.renderUpdate: # self.render() # self.renderUpdate = False # self.updateGL() if self.renderedSteps < self.NSubrenderSteps: # print ((self.renderedSteps*7)%self.NSubrenderSteps) s = time.time() self.render() logger.debug("time to render: %.2f" % (1000. * (time.time() - s))) self.renderedSteps += 1 self.updateGL() def wheelEvent(self, event): """ self.transform.zoom should be within [1,2]""" newZoom = self.transform.zoom * 1.2**(event.angleDelta().y() / 1000.) newZoom = np.clip(newZoom, .4, 3) self.transform.setZoom(newZoom) logger.debug("newZoom: %s", newZoom) # self.refresh() def posToVec3(self, x, y, r0=.8, isRot=True): x, y = 2. * x / self.width() - 1., 1. - 2. * y / self.width() r = np.sqrt(x * x + y * y) if r > r0 - 1.e-7: x, y = 1. * x * r0 / r, 1. * y * r0 / r z = np.sqrt(max(0, r0**2 - x * x - y * y)) if isRot: M = np.linalg.inv(self.transform.quatRot.toRotation3()) x, y, z = np.dot(M, [x, y, z]) return x, y, z def posToVec2(self, x, y): x, y = 2. * x / self.width() - 1., 1. - 2. * y / self.width() return x, y def mousePressEvent(self, event): super(GLWidget, self).mousePressEvent(event) if event.buttons() == QtCore.Qt.LeftButton: self._x0, self._y0, self._z0 = self.posToVec3(event.x(), event.y()) if event.buttons() == QtCore.Qt.RightButton: (self._x0, self._y0), self._invRotM = self.posToVec2( event.x(), event.y()), linalg.inv(self.transform.quatRot.toRotation3()) # self.setCursor(QtCore.Qt.ClosedHandCursor) def mouseReleaseEvent(self, event): super(GLWidget, self).mouseReleaseEvent(event) # self.setCursor(QtCore.Qt.ArrowCursor) def mouseMoveEvent(self, event): # c = append(self.cubeCoords,ones(24)[:,newaxis],axis=1) # cUser = dot(c,self.finalMat) # cUser = cUser[:,:3]/cUser[:,-1,newaxis] # print self.finalMat # print c[0], cUser[0] # Rotation if event.buttons() == QtCore.Qt.LeftButton: x1, y1, z1 = self.posToVec3(event.x(), event.y()) logger.debug("mouse position: %s %s %s " % (x1, y1, z1)) n = np.cross(np.array([self._x0, self._y0, self._z0]), np.array([x1, y1, z1])) nnorm = linalg.norm(n) if np.abs(nnorm) >= 1.: nnorm *= 1. / np.abs(nnorm) w = np.arcsin(nnorm) n *= 1. / (nnorm + 1.e-10) q = Quaternion(np.cos(.5 * w), *(np.sin(.5 * w) * n)) self.transform.setQuaternion(self.transform.quatRot * q) # Translation if event.buttons() == QtCore.Qt.RightButton: x, y = self.posToVec2(event.x(), event.y()) dx, dy, foo = np.dot(self._invRotM, [x - self._x0, y - self._y0, 0]) self.transform.addTranslate(dx, dy, foo) self._x0, self._y0 = x, y self.refresh() def resizeEvent(self, event): # enforce each dimension to be divisable by 4 (and so the saved frames) super(GLWidget, self).resizeEvent(event) size = event.size() w, h = size.width(), size.height() if not ((w % 4 == 0) and (h % 4 == 0)): self.resize(QtCore.QSize((w // 4) * 4, (h // 4) * 4)) def _enforce_resize(self): """ this is to enforce the resizeGL event """ self.resize(self.width() + 1, self.height()) self.resize(self.width() - 1, self.height()) def onScreenNumberChange(self, evt): self._enforce_resize() def _get_screen_number(self): return QtGui.QGuiApplication.instance().desktop().screenNumber( QtGui.QCursor.pos()) def moveEvent(self, evt): current_screen = self._get_screen_number() if hasattr( self, "_current_screen") and self._current_screen != current_screen: self.onScreenNumberChange(evt) self._current_screen = current_screen
class GLWidget(QtOpenGL.QGLWidget): _dataModelChanged = QtCore.pyqtSignal() _BACKGROUND_BLACK = (0., 0., 0., 0.) _BACKGROUND_WHITE = (1., 1., 1., 0.) def __init__(self, parent=None, N_PREFETCH=0, interpolation="linear", **kwargs): logger.debug("init") # # fmt = QtOpenGL.QGLFormat(QtOpenGL.QGL.AlphaChannel) # # super(GLWidget, self).__init__(fmt,parent, **kwargs) super(GLWidget, self).__init__(parent, **kwargs) self.parent = parent self.texture_LUT = None self.setAcceptDrops(True) self.renderer = VolumeRenderer((spimagine.config.__DEFAULT_TEXTURE_WIDTH__, spimagine.config.__DEFAULT_TEXTURE_WIDTH__), interpolation=interpolation) self.renderer.set_projection(mat4_perspective(60, 1., .1, 100)) # self.renderer.set_projection(projMatOrtho(-2,2,-2,2,-10,10)) self.output = np.zeros([self.renderer.height, self.renderer.width], dtype=np.float32) self.output_alpha = np.zeros([self.renderer.height, self.renderer.width], dtype=np.float32) self.sliceOutput = np.zeros((100, 100), dtype=np.float32) self.setTransform(TransformModel()) self.renderTimer = QtCore.QTimer(self) self.renderTimer.setInterval(10) self.renderTimer.timeout.connect(self.onRenderTimer) self.renderTimer.start() self.renderedSteps = 0 self.N_PREFETCH = N_PREFETCH self.NSubrenderSteps = 1 self.dataModel = None self.meshes = [] # self.setMouseTracking(True) self._dataModelChanged.connect(self.dataModelChanged) self.refresh() # self.installEventFilter(self) def set_background_mode_black(self, mode_back=True): self._background_mode_black = mode_back self.refresh() def setModel(self, dataModel): logger.debug("setModel to %s" % dataModel) if self.dataModel is None or (self.dataModel != dataModel): self.dataModel = dataModel self.transform.setModel(dataModel) self.dataModel._dataSourceChanged.connect(self.dataSourceChanged) self.dataModel._dataPosChanged.connect(self.dataPosChanged) self._dataModelChanged.emit() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): def _url_to_path(url): path = url.toLocalFile() if spimagine.config.__SYSTEM_DARWIN__: path = spimagine.config._parseFileNameFix(path) return path self.setCursor(QtCore.Qt.BusyCursor) urls = event.mimeData().urls() if len(urls) == 0: return elif len(urls) == 1: path = _url_to_path(urls[0]) elif len(urls) > 1: path = tuple(_url_to_path(url) for url in urls) try: if self.dataModel: self.dataModel.loadFromPath(path, prefetchSize=self.N_PREFETCH) else: self.setModel(DataModel.fromPath(path, prefetchSize=self.N_PREFETCH)) self.setCursor(QtCore.Qt.ArrowCursor) except Exception as e: QtWidgets.QMessageBox.warning(self, "", "Error loading Data:\n %s" % str(e)) def set_colormap(self, name): """name should be either jet, hot, gray, coolwarm""" try: arr = spimagine.config.__COLORMAPDICT__[name] self._set_colormap_array(arr) except KeyError: print("could not load colormap '%s'" % name) print("valid names: %s" % list(spimagine.config.__COLORMAPDICT__.keys())) def set_colormap_rgb(self, color=[1., 1., 1.]): self._set_colormap_array(np.outer(np.linspace(0, 1., 255), np.array(color))) def _set_colormap_array(self, arr): """arr should be of shape (N,3) and gives the rgb components of the colormap""" if not arr.ndim == 2 and arr.shape[-1] == 3: raise ValueError("wrong shape of color array: should be (N,3) but is %s") self.makeCurrent() self.texture_LUT = fillTexture2d(arr.reshape((1,) + arr.shape), self.texture_LUT) self.refresh() def _shader_from_file(self, fname_vert, fname_frag): shader = QOpenGLShaderProgram() shader.addShaderFromSourceFile(QOpenGLShader.Vertex, fname_vert) shader.addShaderFromSourceFile(QOpenGLShader.Fragment, fname_frag) shader.link() shader.bind() logger.debug("GLSL program log:%s", shader.log()) return shader def initializeGL(self): self.resized = True logger.debug("initializeGL") self.programTex = self._shader_from_file(absPath("shaders/texture.vert"), absPath("shaders/texture.frag")) self.programCube = self._shader_from_file(absPath("shaders/box.vert"), absPath("shaders/box.frag")) self.programSlice = self._shader_from_file(absPath("shaders/slice.vert"), absPath("shaders/slice.frag")) self.programMesh = self._shader_from_file(absPath("shaders/mesh.vert"), absPath("shaders/mesh.frag")) self.programMeshLight = self._shader_from_file( absPath("shaders/mesh_light.vert"), absPath("shaders/mesh_light.frag")) self.texture = None self.textureAlpha = None self.textureSlice = None self.quadCoord = np.array([[-1., -1., 0.], [1., -1., 0.], [1., 1., 0.], [1., 1., 0.], [-1., 1., 0.], [-1., -1., 0.]]) self.quadCoordTex = np.array([[0, 0], [1., 0.], [1., 1.], [1., 1.], [0, 1.], [0, 0]]) # self.cubeCoords = create_cube_coords([-1,1,-1,1,-1,1]) self.set_colormap(spimagine.config.__DEFAULTCOLORMAP__) glEnable(GL_BLEND) # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # self.set_interpolation(spimagine.config.__DEFAULT_INTERP__ != "nearest") # glLineWidth(1.0); glBlendFunc(GL_ONE, GL_ONE) glEnable(GL_LINE_SMOOTH); glDisable(GL_DEPTH_TEST) glLineWidth(spimagine.config.__DEFAULT_BOX_LINEWIDTH__) # self.set_background_color(0,0,0,.0) self.set_background_mode_black(True) self.clear_canvas() # self.set_background_color(1,1,1,.6) def clear_canvas(self): if self._background_mode_black: glClearColor(*self._BACKGROUND_BLACK) else: glClearColor(*self._BACKGROUND_WHITE) if glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) def set_interpolation(self, interpolate=True): interp = "linear" if interpolate else "nearest" self.renderer.rebuild_program(interpolation=interp) self.refresh() def setTransform(self, transform): self.transform = transform self.transform._transformChanged.connect(self.refresh) self.transform._stackUnitsChanged.connect(self.setStackUnits) self.transform._boundsChanged.connect(self.setBounds) def dataModelChanged(self): logger.debug("+++++++++ data model changed") if self.dataModel: logger.debug("dataModelchanged") self.renderer.set_data(self.dataModel[0], autoConvert=True) mi, ma = self._get_min_max() self.transform.reset(minVal=mi, maxVal=ma, stackUnits=self.dataModel.stackUnits()) self.meshes = [] self.refresh() def _get_min_max(self): # as amax is too slow for bug arrays, do it on the gpu if self.dataModel: try: im = self.renderer.dataImg tmp_buf = OCLArray.empty(im.shape, im.dtype) tmp_buf.copy_image(im) mi = float(cl_array.min(tmp_buf).get()) ma = float(cl_array.max(tmp_buf).get()) except Exception as e: print(e) mi = np.amin(self.dataModel[0]) ma = np.amax(self.dataModel[0]) return mi, ma def set_background_color(self, r, g, b, a=1.): self._background_color = (r, g, b, a) glClearColor(r, g, b, a) def dataSourceChanged(self): logger.debug("dataSourcechanged") self.renderer.set_data(self.dataModel[0], autoConvert=True) mi, ma = self._get_min_max() self.transform.reset(minVal=mi, maxVal=ma, stackUnits=self.dataModel.stackUnits()) self.refresh() def setBounds(self, x1, x2, y1, y2, z1, z2): self.cubeCoords = create_cube_coords([x1, x2, y1, y2, z1, z2]) self.renderer.set_box_boundaries([x1, x2, y1, y2, z1, z2]) def setStackUnits(self, px, py, pz): logger.debug("setStackUnits to %s" % [px, py, pz]) self.renderer.set_units([px, py, pz]) def dataPosChanged(self, pos): self.renderer.update_data(self.dataModel[pos]) self.refresh() def refresh(self): # if self.parentWidget() and self.dataModel: # self.parentWidget().setWindowTitle("SpImagine %s"%self.dataModel.name()) self.renderUpdate = True self.renderedSteps = 0 def resizeGL(self, width, height): # somehow in qt5 the OpenGLWidget width/height parameters above are double the value of self.width/height self._viewport_width, self._viewport_height = width, height def add_mesh(self, mesh=SphericalMesh()): """ adds a mesh with vertices and facecolor/edgecolor to be drawn mesh is an instance of spimagine.gui.Mesh, e.g. mesh = Mesh(vertices = [[0,1,0],[0,1,0],...], normals = [[0,1,0],[0,1,0],...], facecolor = (1.,.4,.4,.2), edgecolor = None,...) there are some predefined meshes like SphericalMesh, EllipsoidMesh ... """ self.meshes.append([mesh, glvbo.VBO(mesh.vertices.astype(np.float32, copy=False)), glvbo.VBO(np.array(mesh.normals).astype(np.float32, copy=False)), glvbo.VBO(np.array(mesh.indices).astype(np.uint32, copy=False), target=GL_ELEMENT_ARRAY_BUFFER)]) self.refresh() # sort according to opacity as the opaque objects should be drawn first # self.meshes.sort(key=lambda x: x[0].alpha, reverse=True) def _paintGL_render(self): # Draw the render texture self.programTex.bind() self.texture = fillTexture2d(self.output, self.texture) # self.textureAlpha = fillTexture2d(self.output_alpha, self.textureAlpha) glEnable(GL_BLEND) glEnable(GL_TEXTURE_2D) glDisable(GL_DEPTH_TEST) self.programTex.enableAttributeArray("position") self.programTex.enableAttributeArray("texcoord") self.programTex.setAttributeArray("position", self.quadCoord) self.programTex.setAttributeArray("texcoord", self.quadCoordTex) self.programTex.setUniformValue("is_mode_black", self._background_mode_black) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, self.texture) self.programTex.setUniformValue("texture", 0) glActiveTexture(GL_TEXTURE1) glBindTexture(GL_TEXTURE_2D, self.textureAlpha) self.programTex.setUniformValue("texture_alpha", 1) glActiveTexture(GL_TEXTURE2) glBindTexture(GL_TEXTURE_2D, self.texture_LUT) self.programTex.setUniformValue("texture_LUT", 2) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDrawArrays(GL_TRIANGLES, 0, len(self.quadCoord)) def _paintGL_slice(self): # draw the slice self.programSlice.bind() self.programSlice.setUniformValue("mvpMatrix", QtGui.QMatrix4x4(*self._mat_modelviewproject.flatten())) self.programSlice.setUniformValue("is_mode_black", self._background_mode_black) self.programSlice.enableAttributeArray("position") pos, dim = self.transform.slicePos, self.transform.sliceDim coords = slice_coords(1. * pos / self.dataModel.size()[2 - dim + 1], dim) texcoords = [[0., 0.], [1, 0.], [1., 1.], [1., 1.], [0., 1.], [0., 0.]] self.programSlice.setAttributeArray("position", coords) self.programSlice.setAttributeArray("texcoord", texcoords) self.textureSlice = fillTexture2d(self.sliceOutput, self.textureSlice) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, self.textureSlice) self.programSlice.setUniformValue("texture", 0) glActiveTexture(GL_TEXTURE1) glBindTexture(GL_TEXTURE_2D, self.texture_LUT) self.programSlice.setUniformValue("texture_LUT", 1) glDrawArrays(GL_TRIANGLES, 0, len(coords)) def _paintGL_box(self): glEnable(GL_BLEND) # Draw the cube self.programCube.bind() self.programCube.setUniformValue("mvpMatrix", QtGui.QMatrix4x4(*self._mat_modelviewproject.flatten())) self.programCube.enableAttributeArray("position") if self._background_mode_black: self.programCube.setUniformValue("color", QtGui.QVector4D(1, 1, 1, 0.6)) else: self.programCube.setUniformValue("color", QtGui.QVector4D(0, 0, 0, 0.6)) self.programCube.setAttributeArray("position", self.cubeCoords) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, self.textureAlpha) self.programCube.setUniformValue("texture_alpha", 0) glEnable(GL_DEPTH_TEST) # glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDrawArrays(GL_LINES, 0, len(self.cubeCoords)) glDisable(GL_DEPTH_TEST) def _paintGL_mesh(self, mesh, vbo_vertices, vbo_normals, vbo_indices): """ paint a mesh (which has all the coordinates and colors in it """ glEnable(GL_DEPTH_TEST) glDisable(GL_BLEND) prog = self.programMeshLight prog.bind() prog.setUniformValue("mvpMatrix", QtGui.QMatrix4x4(*self._mat_modelviewproject.flatten())) prog.setUniformValue("mvMatrix", QtGui.QMatrix4x4(*self._mat_modelview.flatten())) prog.setUniformValue("normMatrix", QtGui.QMatrix4x4(*self._mat_normal.flatten())) if mesh.light: prog.setUniformValue("light", QtGui.QVector3D(*mesh.light)) prog.setUniformValue("light_components", QtGui.QVector3D(.2, .5, .3)) else: prog.setUniformValue("light", QtGui.QVector3D(0, 0, 0)) prog.setUniformValue("light_components", QtGui.QVector3D(1., 0, 0)) if not mesh.facecolor is None: r, g, b = mesh.facecolor[:3] a = mesh.alpha prog.setUniformValue("color", QtGui.QVector4D(r, g, b, a)) prog.enableAttributeArray("position") vbo_vertices.bind() glVertexAttribPointer(prog.attributeLocation("position"), 3, GL_FLOAT, GL_FALSE, 0, vbo_vertices) prog.enableAttributeArray("normal") vbo_normals.bind() glVertexAttribPointer(prog.attributeLocation("normal"), 3, GL_FLOAT, GL_FALSE, 0, vbo_normals) vbo_indices.bind() glDrawElements(GL_TRIANGLES, len(vbo_indices.data), GL_UNSIGNED_INT, None) vbo_indices.unbind() vbo_vertices.unbind() glDisable(GL_DEPTH_TEST) prog.disableAttributeArray("position") prog.disableAttributeArray("normal") # # if not mesh.edgecolor is None: # r, g, b = mesh.edgecolor # a = mesh.alpha # # prog.enableAttributeArray("position") # vbo_vertices.bind() # glVertexAttribPointer(prog.attributeLocation("position"), 2, GL_FLOAT, GL_FALSE, 0, vbo_edges) # # prog.setUniformValue("color", # QtGui.QVector4D(r, g, b, a)) # # glDrawArrays(GL_LINES, 0, len(mesh.edges)) def paintGL(self): self.makeCurrent() if not glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE: return w = max(self._viewport_width, self._viewport_height) # force viewport to always be a square glViewport((self._viewport_width - w) // 2, (self._viewport_height - w) // 2, w, w) self.clear_canvas() self._mat_modelview = self.transform.getModelView() self._mat_proj = self.transform.getProjection() self._mat_normal = np.linalg.inv(self._mat_modelview).T self._mat_modelviewproject = np.dot(self._mat_proj, self._mat_modelview) if self.dataModel: self.textureAlpha = fillTexture2d(self.output_alpha, self.textureAlpha) if self.transform.isBox: self._paintGL_box() if self.transform.isSlice and self.sliceOutput is not None: self._paintGL_slice() self._paintGL_render() for (m, vbo_verts, vbo_normals, vbo_indices) in self.meshes: self._paintGL_mesh(m, vbo_verts, vbo_normals, vbo_indices) def render(self): logger.debug("render") if self.dataModel: self.renderer.set_modelView(self.transform.getUnscaledModelView()) self.renderer.set_projection(self.transform.getProjection()) self.renderer.set_min_val(self.transform.minVal) self.renderer.set_max_val(self.transform.maxVal) self.renderer.set_gamma(self.transform.gamma) self.renderer.set_alpha_pow(self.transform.alphaPow) self.renderer.set_occ_strength(self.transform.occ_strength) self.renderer.set_occ_radius(self.transform.occ_radius) self.renderer.set_occ_n_points(self.transform.occ_n_points) if self.transform.isIso: renderMethod = "iso_surface" else: renderMethod = "max_project" self.renderer.render(method=renderMethod, return_alpha=True, numParts=self.NSubrenderSteps, currentPart=( self.renderedSteps * _next_golden( self.NSubrenderSteps)) % self.NSubrenderSteps) self.output, self.output_alpha = self.renderer.output, self.renderer.output_alpha if self.transform.isSlice: if self.transform.sliceDim == 0: out = self.dataModel[self.transform.dataPos][:, :, self.transform.slicePos] elif self.transform.sliceDim == 1: out = self.dataModel[self.transform.dataPos][:, self.transform.slicePos, :] elif self.transform.sliceDim == 2: out = self.dataModel[self.transform.dataPos][self.transform.slicePos, :, :] min_out, max_out = np.amin(out), np.amax(out) if max_out > min_out: self.sliceOutput = (1. * (out - min_out) / (max_out - min_out)) else: self.sliceOutput = np.zeros_like(out) # def getFrame(self): # self.render() # self.paintGL() # glFlush() # im = self.grabFrameBuffer() # im = im.convertToFormat(QtGui.QImage.Format_RGB32) # # width = im.width() # height = im.height() # # ptr = im.bits() # ptr.setsize(im.byteCount()) # arr = np.array(ptr).reshape(height, width, 4) # Copies the data # return arr[..., [2, 1, 0, 3]].copy() def saveFrame(self, fName, with_alpha=False): """FIXME: scaling behaviour still hast to be implemented (e.g. after setGamma)""" logger.info("saving frame as %s", fName) # has to be png name, ext = os.path.splitext(fName) if ext != ".png": fName = name + ".png" self.render() self.paintGL() glFlush() im = self.grabFrameBuffer(withAlpha=with_alpha) im.save(fName) def onRenderTimer(self): # if self.renderUpdate: # self.render() # self.renderUpdate = False # self.updateGL() if self.renderedSteps < self.NSubrenderSteps: # print ((self.renderedSteps*7)%self.NSubrenderSteps) s = time.time() self.render() logger.debug("time to render: %.2f" % (1000. * (time.time() - s))) self.renderedSteps += 1 self.updateGL() def wheelEvent(self, event): """ self.transform.zoom should be within [1,2]""" newZoom = self.transform.zoom * 1.2 ** (event.angleDelta().y() / 1000.) newZoom = np.clip(newZoom, .4, 3) self.transform.setZoom(newZoom) logger.debug("newZoom: %s", newZoom) # self.refresh() def posToVec3(self, x, y, r0=.8, isRot=True): x, y = 2. * x / self.width() - 1., 1. - 2. * y / self.width() r = np.sqrt(x * x + y * y) if r > r0 - 1.e-7: x, y = 1. * x * r0 / r, 1. * y * r0 / r z = np.sqrt(max(0, r0 ** 2 - x * x - y * y)) if isRot: M = np.linalg.inv(self.transform.quatRot.toRotation3()) x, y, z = np.dot(M, [x, y, z]) return x, y, z def posToVec2(self, x, y): x, y = 2. * x / self.width() - 1., 1. - 2. * y / self.width() return x, y def mousePressEvent(self, event): super(GLWidget, self).mousePressEvent(event) if event.buttons() == QtCore.Qt.LeftButton: self._x0, self._y0, self._z0 = self.posToVec3(event.x(), event.y()) if event.buttons() == QtCore.Qt.RightButton: (self._x0, self._y0), self._invRotM = self.posToVec2(event.x(), event.y()), linalg.inv( self.transform.quatRot.toRotation3()) # self.setCursor(QtCore.Qt.ClosedHandCursor) def mouseReleaseEvent(self, event): super(GLWidget, self).mouseReleaseEvent(event) # self.setCursor(QtCore.Qt.ArrowCursor) def mouseMoveEvent(self, event): # c = append(self.cubeCoords,ones(24)[:,newaxis],axis=1) # cUser = dot(c,self.finalMat) # cUser = cUser[:,:3]/cUser[:,-1,newaxis] # print self.finalMat # print c[0], cUser[0] # Rotation if event.buttons() == QtCore.Qt.LeftButton: x1, y1, z1 = self.posToVec3(event.x(), event.y()) logger.debug("mouse position: %s %s %s " % (x1, y1, z1)) n = np.cross(np.array([self._x0, self._y0, self._z0]), np.array([x1, y1, z1])) nnorm = linalg.norm(n) if np.abs(nnorm) >= 1.: nnorm *= 1. / np.abs(nnorm) w = np.arcsin(nnorm) n *= 1. / (nnorm + 1.e-10) q = Quaternion(np.cos(.5 * w), *(np.sin(.5 * w) * n)) self.transform.setQuaternion(self.transform.quatRot * q) # Translation if event.buttons() == QtCore.Qt.RightButton: x, y = self.posToVec2(event.x(), event.y()) dx, dy, foo = np.dot(self._invRotM, [x - self._x0, y - self._y0, 0]) self.transform.addTranslate(dx, dy, foo) self._x0, self._y0 = x, y self.refresh() def resizeEvent(self, event): # enforce each dimension to be divisable by 4 (and so the saved frames) super(GLWidget, self).resizeEvent(event) size = event.size() w, h = size.width(), size.height() if not ((w % 4 == 0) and (h % 4 == 0)): self.resize(QtCore.QSize((w // 4) * 4, (h // 4) * 4)) def _enforce_resize(self): """ this is to enforce the resizeGL event """ self.resize(self.width() + 1, self.height()) self.resize(self.width() - 1, self.height()) def onScreenNumberChange(self, evt): self._enforce_resize() def _get_screen_number(self): return QtGui.QGuiApplication.instance().desktop().screenNumber(QtGui.QCursor.pos()) def moveEvent(self, evt): current_screen = self._get_screen_number() if hasattr(self, "_current_screen") and self._current_screen != current_screen: self.onScreenNumberChange(evt) self._current_screen = current_screen
def test_linear_nearest_switch(): import matplotlib.pyplot as plt N = 32 d = .4 * np.random.rand(N**3).reshape((N, ) * 3).astype(np.float32) rend = VolumeRenderer((400, 400)) rend.rebuild_program(interpolation="linear") rend.set_data(d) rend.render() out1 = rend.output.copy() rend.rebuild_program(interpolation="nearest") rend.render() out2 = rend.output plt.subplot(1, 2, 1) plt.imshow(out1, cmap="magma") plt.axis("off") plt.subplot(1, 2, 2) plt.imshow(out2, cmap="magma") plt.axis("off") plt.show() plt.pause(.1) plt.close() return rend
def test_linear_nearest_switch(): import matplotlib.pyplot as plt N = 32 d = .4*np.random.rand(N ** 3).reshape((N,) * 3).astype(np.float32) rend = VolumeRenderer((400, 400)) rend.rebuild_program(interpolation="linear") rend.set_data(d) rend.render() out1 = rend.output.copy() rend.rebuild_program(interpolation="nearest") rend.render() out2 = rend.output plt.subplot(1, 2, 1) plt.imshow(out1, cmap = "magma") plt.axis("off") plt.subplot(1,2,2) plt.imshow(out2, cmap = "magma") plt.axis("off") plt.show() plt.pause(.1) plt.close() return rend
def render_iso(data, is_ao=True): from gputools.utils.utils import remove_cache_dir, get_cache_dir remove_cache_dir() rend = VolumeRenderer((400, 400)) if is_ao: rend.set_occ_strength(1) rend.set_occ_radius(101) rend.set_occ_n_points(1000) else: rend.set_occ_strength(0) rend.set_occ_radius(21) rend.set_occ_n_points(30) rend.set_modelView(mat4_translate(0, 0, -1.)) rend.render(data, maxVal=70., method="iso_surface") return rend
# np.int32(1), # d.data, # d.data, # im) # # print(out.get()) if __name__ == '__main__': from spimagine.volumerender.volumerender import VolumeRenderer from gputools.utils.utils import remove_cache_dir, get_cache_dir remove_cache_dir() data = (123 * np.ones((10, 10, 10))).astype(np.float32) rend = VolumeRenderer((4, 4)) rend.proc = OCLProgram("/Users/mweigert/python/spimagine/spimagine/volumerender/kernels/all_render_kernels.cl", build_options= ["-I", "/Users/mweigert/python/spimagine/spimagine/volumerender/kernels", "-D", "maxSteps=100", "-D","QUALIFIER_CONSTANT_TO_GLOBAL" "-cl-finite-math-only", "-cl-fast-relaxed-math", "-cl-unsafe-math-optimizations", "-cl-mad-enable"]) rend.set_data(data) rend.proc.run_kernel("max_project_float", (rend.width, rend.height), None,
def main(): parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description="""renders max projectios of 3d data example usage: Tif data: \t \tspim_render -i mydata.tif -o myoutput.png -t 0 0 -4 -u 1 1 4 Bscope data: \tspim_render -f bscope -i mydataFolder -o myoutput.png -t 0 0 -4 -u 1 1 4 """) parser.add_argument("-f","--format",dest="format",metavar="format", help = """format currently supported: tif (default) bscope """, type=str,default = "tif", required = False) parser.add_argument("-i","--input",dest="input",metavar="infile", help = "name of the input file to render, currently only 3d Tiff is supported", type=str,default = None, required = True) parser.add_argument("-o","--output",dest="output",metavar="outfile", help = "name of the output file, png extension is recommended", type=str,default = "out.png") parser.add_argument("-p","--pos",dest="pos",metavar="timepoint position", help = "timepoint to render if format=='bscope' ", type=int,default = 0) parser.add_argument("-w","--width",dest="width",metavar="width", help = "pixelwidth of the rendered output ", type=int,default = 400) parser.add_argument("-s","--scale",dest="scale",metavar="scale", type=float,nargs=1 ,default = [1.]) parser.add_argument("-u","--units",dest="units",metavar="units", type=float,nargs= 3 ,default = [1.,1.,5.]) parser.add_argument("-t","--translate",dest="translate", type = float, nargs=3,default = [0,0,-4], metavar=("x","y","z")) parser.add_argument("-r","--rotation",dest="rotation", type = float, nargs=4,default = [0,1,0,0], metavar=("w","x","y","z")) parser.add_argument("-R","--range",dest="range", type = float, nargs=2,default = None, help = "if --16bit is set, the range of the data values to consider, defaults to [min,max]", metavar=("min","max")) parser.add_argument("-O","--Orthoview",help="use parallel projection (default: perspective)", dest="ortho",action="store_true") parser.add_argument("--16bit",help="render into 16 bit png", dest="is16Bit",action="store_true") if len(sys.argv)==1: parser.print_help() return args = parser.parse_args() for k,v in six.iteritems(vars(args)): print(k,v) rend = VolumeRenderer((args.width,args.width)) if args.format=="tif": data = read3dTiff(args.input) elif args.format=="bscope": data = fromSpimFolder(args.input,pos=args.pos,count=1)[0,...] else: raise ValueError("format %s not supported (should be tif/bscope)" %args.format) rend.set_data(data) rend.set_units(args.units) M = mat4_scale(*(args.scale*3)) M = np.dot(mat4_rotation(*args.rotation),M) M = np.dot(mat4_translate(*args.translate),M) rend.set_modelView(M) if args.ortho: rend.set_projection(mat4_ortho(-1,1,-1,1,-1,1)) else: rend.set_projection(mat4_perspective(60,1.,1,10)) out = rend.render() # image is saved by scipy.misc.toimage(out,low,high,cmin,cmax) # p' = p * high/cmax if not args.is16Bit: imsave(args.output,out) # if not args.range: # imsave(args.output,out) # else: # img = toimage(out, low = args.range[0], high = args.range[1]) # img.save(args.output) else: if not args.range: print("min/max: ", np.amin(out), np.amax(out)) img = toimage(out, low = np.amin(out), high = np.amax(out),mode = "I") else: img = toimage(out, low = args.range[0], high = args.range[1], mode = "I") img.save(args.output)