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
Exemple #3
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()
Exemple #4
0
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
Exemple #9
0
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
Exemple #10
0
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
Exemple #11
0
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
Exemple #13
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()
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
Exemple #15
0
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
Exemple #18
0
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
Exemple #20
0
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
Exemple #21
0
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
Exemple #24
0
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,
Exemple #26
0
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)