def test_buffer(self): # Some data that we need data = np.zeros(100, np.uint16) im2 = np.zeros((50, 50), np.uint16) im3 = np.zeros((20, 20, 20), np.uint16) shaders = gloo.VertexShader("x"), gloo.FragmentShader("x") items = [ # Buffers (gloo.buffer.Buffer(target=gl.GL_ARRAY_BUFFER), 'set_data', data), (gloo.buffer.VertexBuffer(np.uint16), 'set_data', data), (gloo.buffer.ElementBuffer(np.uint16), 'set_data', data), # Textures (gloo.Texture2D(), 'set_data', im2), (gloo.Texture3D(), 'set_data', im3), # FBO stuff (gloo.RenderBuffer(), 'set_shape', (1, 1)), (gloo.FrameBuffer(), 'attach_color', gloo.RenderBuffer((1, 1))), # Shader stuff (gloo.VertexShader(), 'set_code', "x"), (gloo.FragmentShader(), 'set_code', "x"), (gloo.Program(), 'attach', shaders), ] for ob, funcname, value in items: self._fix_ob(ob) #print('Testing GLObject compliance for %s' % ob.__class__.__name__) # Initially a clear state self.assertEqual(ob._need_update, False) # Set value, now we should have a "dirty" state x = ob for part in funcname.split('.'): x = getattr(x, part) x(value) self.assertEqual(ob._need_update, True) # Activate the object ob.activate() # Now we should be activated self.assertEqual(len(ob._actions), 3) self.assertEqual(ob._actions[0], 'create') self.assertEqual(ob._actions.count('update'), 1) self.assertEqual(ob._actions.count('activate'), 1) # Deactivate ob.deactivate() # Now we should be deactivated self.assertEqual(len(ob._actions), 4) self.assertEqual(ob._actions[-1], 'deactivate') # Activate some more for i in range(10): ob.activate() # Create and update should not have been called self.assertEqual(ob._actions.count('create'), 1) self.assertEqual(ob._actions.count('update'), 1)
def __init__(self): app.Canvas.__init__(self, keys='interactive') self.size = W * 5, H * 5 self.program = gloo.Program(VERT_SHADER, FRAG_SHADER) self.texture = gloo.Texture3D(I, interpolation='nearest', wrapping='clamp_to_edge') self.program['u_texture'] = self.texture self.program['i'] = 0.0 self.program.bind(gloo.VertexBuffer(data)) self.view = np.eye(4, dtype=np.float32) self.model = np.eye(4, dtype=np.float32) self.projection = np.eye(4, dtype=np.float32) self.program['u_model'] = self.model self.program['u_view'] = self.view self.projection = ortho(0, W, 0, H, -1, 1) self.program['u_projection'] = self.projection self.i = 0 gloo.set_clear_color('white') self._timer = app.Timer('auto', connect=self.on_timer, start=True)
def get_texture3d(self, outtexture=None): """Pack N-channel image data into R, RG, RGB, RGBA Texture3D using self.channels projection. outtexture: None: allocate new Texture3D not None: use existing Texture3D sets data in outtexture and returns the texture. """ I0 = self.data # choose size for texture data D, H, W = self.data.shape[0:3] C = len(self.channels) if outtexture is None: format, internalformat = self._get_texture3d_format() print('allocating texture3D', (D, H, W, C), internalformat) outtexture = gloo.Texture3D(shape=(D, H, W, C), format=format, internalformat=internalformat) elif self.last_channels == self.channels: print('reusing texture') return outtexture else: print('regenerating texture') print((D, H, W, C), '<-', I0.shape, list(self.channels), I0.dtype) # normalize for OpenGL [0,1.0] or [0,2**N-1] and zero black-level maxval = float(I0.max()) minval = float(I0.min()) if maxval > minval: scale = 1.0 / (maxval - minval) else: scale = 1.0 if I0.dtype == np.uint8 or I0.dtype == np.int8: tmpout = np.zeros((D, H, W, C), dtype=np.uint8) scale *= float(2**8 - 1) else: assert I0.dtype == np.float16 or I0.dtype == np.float32 or I0.dtype == np.uint16 or I0.dtype == np.int16 tmpout = np.zeros((D, H, W, C), dtype=np.uint16) scale *= (2.0**16 - 1) # pack selected channels into texture for i in range(C): tmpout[:, :, :, i] = (I0[:, :, :, self.channels[i]].astype(np.float32) - minval) * scale self.last_channels = self.channels outtexture.set_data(tmpout) return outtexture
def _reform_image(self, I, meta, view_reduction): splits = [(datetime.datetime.now(), None)] self.raw_image = I analyzer, view_image, centroids, centroid_measures = batch_analyze( I, self.synapse_diam_microns, self.vicinity_diam_microns, self.redblur_microns, view_reduction ) splits.append((datetime.datetime.now(), 'volume process')) centroid_status = np.zeros((256**3,), dtype=np.uint8) # get labeled voxels assert np.isnan(centroid_measures).sum() == 0 print("measures range", centroid_measures.min(axis=0), centroid_measures.max(axis=0)) print("centroids:", centroids.min(axis=0), centroids.max(axis=0)) print("view_image shape:", view_image.shape) print("view_image range", view_image.min(), view_image.max()) # align 3D textures for opengl? assert view_image.shape[3] < 4 result_shape = tuple(list(map( lambda s, m: s + s%m, view_image.shape[0:3], [1, 1, 4] )) + [view_image.shape[3] >= 2 and 3 or 1]) print("results shape:", result_shape) segment_map = self.splat_centroids(view_reduction, result_shape[0:3], centroids, centroid_measures) if centroid_measures.shape[0] <= (2**8-1): nb = 1 elif centroid_measures.shape[0] <= (2**16-1): nb = 2 else: assert centroid_measures.shape[0] <= (2**24-1), "too many segment IDs to RGB-pack" nb = 3 if nb == 1: fmt = 'red' else: fmt = 'rgb'[0:nb] print("voxel_class_texture %d segments, %d bytes, %s format" % (centroid_measures.shape[0], nb, fmt)) # pack least significant byte as R, then G, etc. segment_map_uint8 = np.zeros(segment_map.shape + (nb,), dtype=np.uint8) for i in range(nb): segment_map_uint8[:,:,:,i] = (segment_map[:,:,:] // (2**(i*8))) % 2**8 del segment_map self.voxel_class_texture = gloo.Texture3D(segment_map_uint8.shape, format=fmt) self.voxel_class_texture.set_data(segment_map_uint8) self.voxel_class_texture.interpolation = 'nearest' self.voxel_class_texture.wrapping = 'clamp_to_edge' del segment_map_uint8 splits.append((datetime.datetime.now(), 'segment texture')) self.data_max = max( view_image[:,:,:,0].max(), centroid_measures[:,0:2].max() ) self.data_min = min( view_image[:,:,:,0].min(), centroid_measures[:,0:2].min() ) if view_image.shape[3] > 1: self.data_max = max( self.data_max, view_image[:,:,:,1].max(), centroid_measures[:,4].max() ) self.data_min = min( self.data_min, view_image[:,:,:,1].min(), centroid_measures[:,4].min() ) # pack segment measures into a 3D grid max_classid = centroid_measures.shape[0] + 1 W = 256 seg_meas = np.zeros((W, W, W, 3), dtype=np.float32) seg_meas_flat = seg_meas.reshape((W**3, 3)) seg_meas_flat[1:max_classid,0:2] = centroid_measures[:,0:2] if centroid_measures.shape[1] > 4: seg_meas_flat[1:max_classid,2] = centroid_measures[:,4] seg_meas = (seg_meas - self.data_min) / (self.data_max - self.data_min) self.measures_texture = gloo.Texture3D(seg_meas.shape, format='rgb', internalformat='rgb16f') self.measures_texture.set_data(seg_meas) self.measures_texture.interpolation = 'nearest' self.measures_texture.wrapping = 'clamp_to_edge' self.status_texture = gloo.Texture3D((W,W,W,1), format='red', internalformat='red') self.status_texture.set_data(centroid_status.reshape((W,W,W,1))) self.status_texture.interpolation = 'nearest' self.status_texture.wrapping = 'clamp_to_edge' splits.append((datetime.datetime.now(), 'segment measures and status textures')) result = np.zeros(result_shape, dtype=np.float32) result[0,0,0,0] = self.data_min result[0,0,1,0] = self.data_max result_box = result[ 0:view_image.shape[0], 0:view_image.shape[1], 0:view_image.shape[2], : ] result_box[:,:,:,0] = view_image[:,:,:,0] splits.append((datetime.datetime.now(), 'scalar volume')) perf_vector = list(map(lambda t0, t1: ((t1[0]-t0[0]).total_seconds(), t1[1]), splits[0:-1], splits[1:])) for elapsed, desc in perf_vector: print("%8.2fs %s task time" % (elapsed, desc)) print("measure counts:", centroid_measures.shape) print("packed data range: ", self.data_min, self.data_max) self.analyzer = analyzer self.syn_values = centroid_measures[:,0] self.vcn_values = centroid_measures[:,1] if centroid_measures.shape[1] > 4: self.red_values = centroid_measures[:,2] else: self.red_values = np.zeros((centroid_measures.shape[0],), dtype=np.float32) self.centroids = centroids self.centroid_measures = centroid_measures self.centroid_status = centroid_status #self.widths = widths return result
def get_textures(self, Z): """Returns ((image_texture, map_texture, measures_texture), map_ndarray, status3d_flat)""" I0 = self.data # choose size for texture data D, H, W = self.data.shape[0:3] C = len(self.channels) if self.textures is None: format, internalformat = self._get_texture_format( len(self.channels), 2) #print 'allocating textures...' self.textures = [ gloo.Texture2D(shape=(H, W, C), format=format, internalformat=internalformat), gloo.Texture2D(shape=(H, W, 3), format='rgb', internalformat='rgb'), gloo.Texture3D(shape=(256, 256, 256, 3), format='rgb', internalformat='rgb16f'), gloo.Texture3D(shape=(256, 256, 256), format='luminance', internalformat='red'), ] self.map_ndarray = np.zeros((H, W, 4), dtype=np.uint8) self.measures3d = np.zeros((256, 256, 256, 3), dtype=np.float32) self.status3d = np.zeros((256, 256, 256), dtype=np.uint8) for texture in self.textures: texture.interpolation = 'nearest' texture.wrapping = 'clamp_to_edge' if self.statuses is not None: # if NPZ included initial status, load it here! status3d_flat = self.status3d.reshape((256**3, )) status3d_flat[1:self.statuses.shape[0] + 1] = self.statuses[:] elif self.last_channels == self.channels and self.last_Z == Z: #print 'reusing textures' return self.textures else: #print 'regenerating texture' pass # normalize image data for OpenGL [0,1.0] or [0,2**N-1] and zero black-level scale = 1.0 / self.value_norm if I0.dtype == np.uint8 or I0.dtype == np.int8: tmpout = np.zeros((H, W, C), dtype=np.uint8) scale *= float(2**8 - 1) else: assert I0.dtype == np.float16 or I0.dtype == np.float32 or I0.dtype == np.uint16 or I0.dtype == np.int16 tmpout = np.zeros((H, W, C), dtype=np.uint16) scale *= (2.0**16 - 1) # pack selected channels into texture for i in range(C): tmpout[:, :, i] = (I0[Z, :, :, self.channels[i]].astype(np.float32) - self.minval) * scale self.last_channels = self.channels self.last_Z = Z self.textures[0].set_data(tmpout) # splat intersecting segment IDs into map texture tmpout = np.zeros((H, W, 4), dtype=np.uint8) self.map_ndarray[:, :, :] = 0 indices = ((self.centroids[:, 0] >= Z - self.z_radius) * (self.centroids[:, 0] <= Z + self.z_radius)).nonzero()[0] if indices.shape[0] > len(self.kernel_slices): # optimized for a bunch of points spread around a little for i in range(indices.shape[0]): idx = indices[i] y, x = self.centroids[idx, 1:3] idx += 1 # offset indices 0..N-1 as 1..N tmpout[y, x, 0] = idx % 2**8 tmpout[y, x, 1] = (idx // 2**8) % 2**8 tmpout[y, x, 2] = (idx // 2**16) % 2**8 for dyslc, dxslc, syslc, sxslc in self.kernel_slices: dst = self.map_ndarray[dyslc, dxslc, :] dst_not_filled = ((dst[:, :, 0] == 0) * (dst[:, :, 1] == 0) * (dst[:, :, 2] == 0))[:, :, None] dst += tmpout[syslc, sxslc, :] * dst_not_filled # end loop (synspy#33 was indentation regression on previous line!) else: # optimized for fewer points spread around a lot for i in range(indices.shape[0]): idx = indices[i] y, x = self.centroids[idx, 1:3] idx += 1 # offset 0..N-1 as 1..N r = idx % 2**8 g = (idx // 2**8) % 2**8 b = (idx // 2**16) % 2**8 if self.kernel_radius < y < (self.map_ndarray.shape[0] - self.kernel_radius) \ and self.kernel_radius < x < (self.map_ndarray.shape[1] - self.kernel_radius): dslc = ( slice(y - self.kernel_radius, y + self.kernel_radius + 1), slice(x - self.kernel_radius, x + self.kernel_radius + 1), ) dst_not_filled = ((self.map_ndarray[dslc + (0, )] == 0) * (self.map_ndarray[dslc + (1, )] == 0) * (self.map_ndarray[dslc + (2, )] == 0)) self.map_ndarray[dslc + ( 0, )] = r * dst_not_filled * self.kernel_splat + self.map_ndarray[ dslc + (0, )] self.map_ndarray[dslc + ( 1, )] = g * dst_not_filled * self.kernel_splat + self.map_ndarray[ dslc + (1, )] self.map_ndarray[dslc + ( 2, )] = b * dst_not_filled * self.kernel_splat + self.map_ndarray[ dslc + (2, )] # pack measures into 3D grid meas3d_flat = self.measures3d.reshape((256**3, 3)) meas3d_flat[1:self.measures.shape[0] + 1, 0:2] = self.measures[:, 0:2] if self.measures.shape[1] > 4: meas3d_flat[1:self.measures.shape[0] + 1, 2] = self.measures[:, 4] # renormalize to [0,1] self.measures3d[:, :] = self.measures3d[:, :] * (1.0 / self.value_norm) # pack statuses into 3D grid status3d_flat = self.status3d.reshape((256**3, )) self.textures[1].set_data(self.map_ndarray) self.textures[2].set_data(self.measures3d) self.textures[3].set_data(self.status3d) return self.textures, self.map_ndarray, status3d_flat