class OrthoColoredRenderer(OrthoBaseRenderer, ColoredRenderer): terms = 'f', 'background_image', 'overdraw', 'num_channels' dterms = 'vc', 'ortho', 'bgcolor' def compute_r(self): return self.color_image def compute_dr_wrt(self, wrt): raise NotImplementedError def on_changed(self, which): if 'ortho' in which: w = self.ortho.width h = self.ortho.height self.glf = OsContext(np.int(w), np.int(h), typ=GL_FLOAT) _setup_ortho(self.glf, self.ortho.left.r, self.ortho.right.r, self.ortho.bottom.r, self.ortho.top.r, self.ortho.near, self.ortho.far, self.ortho.view_mtx) self.glf.Viewport(0, 0, w, h) self.glb = OsContext(np.int(w), np.int(h), typ=GL_UNSIGNED_BYTE) self.glb.Viewport(0, 0, w, h) _setup_ortho(self.glb, self.ortho.left.r, self.ortho.right.r, self.ortho.bottom.r, self.ortho.top.r, self.ortho.near, self.ortho.far, self.ortho.view_mtx) if not hasattr(self, 'num_channels'): self.num_channels = 3 if not hasattr(self, 'bgcolor'): self.bgcolor = Ch(np.array([.5] * self.num_channels)) which.add('bgcolor') if not hasattr(self, 'overdraw'): self.overdraw = True if 'bgcolor' in which: self.glf.ClearColor(self.bgcolor.r[0], self.bgcolor.r[1 % self.num_channels], self.bgcolor.r[2 % self.num_channels], 1.) @depends_on('f', 'ortho', 'vc') def boundarycolor_image(self): return self.draw_boundarycolor_image(with_vertex_colors=True) @depends_on('f', 'ortho') def boundary_images(self): self._call_on_changed() return draw_boundary_images(self.glb, self.v.r, self.f, self.vpe, self.fpe, self.ortho) @depends_on(terms + dterms) def color_image(self): return super(OrthoColoredRenderer, self).color_image @property def shape(self): return (self.ortho.height, self.ortho.width, 3)
class BoundaryRenderer(BaseRenderer): terms = 'f', 'frustum', 'num_channels' dterms = 'camera', @property def shape(self): return (self.frustum['height'], self.frustum['width'], self.num_channels) def compute_r(self): tmp = self.camera.r return self.color_image def compute_dr_wrt(self, wrt): if wrt is not self.camera: return None visibility = self.boundaryid_image shape = visibility.shape visible = np.nonzero(visibility.ravel() != 4294967295)[0] num_visible = len(visible) barycentric = self.barycentric_image return common.dImage_wrt_2dVerts(self.color_image, visible, visibility, barycentric, self.frustum['width'], self.frustum['height'], self.v.r.size / 3, self.vpe) def on_changed(self, which): if 'frustum' in which: w = self.frustum['width'] h = self.frustum['height'] self.glf = OsContext(w, h, typ=GL_FLOAT) self.glf.Viewport(0, 0, w, h) self.glb = OsContext(w, h, typ=GL_UNSIGNED_BYTE) self.glb.Viewport(0, 0, w, h) if 'frustum' in which or 'camera' in which: setup_camera(self.glb, self.camera, self.frustum) setup_camera(self.glf, self.camera, self.frustum) if not hasattr(self, 'overdraw'): self.overdraw = True @depends_on(terms + dterms) def color_image(self): self._call_on_changed() result = self.boundarybool_image.astype(np.float64) return np.dstack([result for i in range(self.num_channels)])
class DepthRenderer(BaseRenderer): terms = 'f', 'frustum', 'background_image', 'overdraw' dterms = 'camera', 'v' @property def shape(self): return (self.frustum['height'], self.frustum['width']) def compute_r(self): tmp = self.camera.r return self.depth_image.reshape( (self.frustum['height'], self.frustum['width'])) def compute_dr_wrt(self, wrt): if wrt is not self.camera and wrt is not self.v: return None visibility = self.visibility_image visible = np.nonzero(visibility.ravel() != 4294967295)[0] barycentric = self.barycentric_image if wrt is self.camera: shape = visibility.shape depth = self.depth_image if self.overdraw: result1 = common.dImage_wrt_2dVerts_bnd( depth, visible, visibility, barycentric, self.frustum['width'], self.frustum['height'], self.v.r.size / 3, self.f, self.boundaryid_image != 4294967295) else: result1 = common.dImage_wrt_2dVerts(depth, visible, visibility, barycentric, self.frustum['width'], self.frustum['height'], self.v.r.size / 3, self.f) # result1 = common.dImage_wrt_2dVerts(depth, visible, visibility, barycentric, self.frustum['width'], self.frustum['height'], self.v.r.size/3, self.f) return result1 elif wrt is self.v: IS = np.tile(col(visible), (1, 9)).ravel() JS = col(self.f[visibility.ravel()[visible]].ravel()) JS = np.hstack((JS * 3, JS * 3 + 1, JS * 3 + 2)).ravel() # FIXME: there should be a faster way to get the camera axis. # But it should be carefully tested with distortion present! pts = np.array([[self.camera.c.r[0], self.camera.c.r[1], 2], [self.camera.c.r[0], self.camera.c.r[1], 1]]) pts = self.camera.unproject_points(pts) cam_axis = pts[0, :] - pts[1, :] if True: # use barycentric coordinates (correct way) w = visibility.shape[1] pxs = np.asarray(visible % w, np.int32) pys = np.asarray(np.floor(np.floor(visible) / w), np.int32) bc0 = col(barycentric[pys, pxs, 0]) bc1 = col(barycentric[pys, pxs, 1]) bc2 = col(barycentric[pys, pxs, 2]) bc = np.hstack( (bc0, bc0, bc0, bc1, bc1, bc1, bc2, bc2, bc2)).ravel() else: # each vert contributes equally (an approximation) bc = 1. / 3. data = np.tile(row(cam_axis), (IS.size / 3, 1)).ravel() * bc result2 = sp.csc_matrix( (data, (IS, JS)), shape=(self.frustum['height'] * self.frustum['width'], self.v.r.size)) return result2 def on_changed(self, which): if 'frustum' in which: w = self.frustum['width'] h = self.frustum['height'] self.glf = OsContext(w, h, typ=GL_FLOAT) self.glf.Viewport(0, 0, w, h) self.glb = OsContext(w, h, typ=GL_UNSIGNED_BYTE) self.glb.Viewport(0, 0, w, h) if 'frustum' in which or 'camera' in which: setup_camera(self.glb, self.camera, self.frustum) setup_camera(self.glf, self.camera, self.frustum) if not hasattr(self, 'overdraw'): self.overdraw = True assert (self.v is self.camera.v) @depends_on(dterms + terms) def depth_image(self): self._call_on_changed() gl = self.glb gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) gl.PolygonMode(GL_FRONT_AND_BACK, GL_FILL) draw_noncolored_verts(gl, self.camera.v.r, self.f) result = np.asarray(deepcopy(gl.getDepth()), np.float64) if self.overdraw: gl.PolygonMode(GL_FRONT_AND_BACK, GL_LINE) draw_noncolored_verts(gl, self.camera.v.r, self.f) overdraw = np.asarray(deepcopy(gl.getDepth()), np.float64) gl.PolygonMode(GL_FRONT_AND_BACK, GL_FILL) boundarybool_image = self.boundarybool_image result = overdraw * boundarybool_image + result * ( 1 - boundarybool_image) if hasattr(self, 'background_image'): if False: # has problems at boundaries, not sure why yet bg_px = self.visibility_image == 4294967295 fg_px = 1 - bg_px result = bg_px * self.background_image + fg_px * result else: tmp = np.concatenate( (np.atleast_3d(result), np.atleast_3d( self.background_image)), axis=2) result = np.min(tmp, axis=2) return result def getDepthMesh(self, depth_image=None): self._call_on_changed() # make everything is up-to-date v = self.glb.getDepthCloud(depth_image) w = self.frustum['width'] h = self.frustum['height'] idxs = np.arange(w * h).reshape((h, w)) # v0 is upperleft, v1 is upper right, v2 is lowerleft, v3 is lowerright v0 = col(idxs[:-1, :-1]) v1 = col(idxs[:-1, 1:]) v2 = col(idxs[1:, :-1]) v3 = col(idxs[1:, 1:]) f = np.hstack((v0, v1, v2, v1, v3, v2)).reshape((-1, 3)) return v, f
class ColoredRenderer(BaseRenderer): terms = 'f', 'frustum', 'background_image', 'overdraw', 'num_channels' dterms = 'vc', 'camera', 'bgcolor' @property def shape(self): if not hasattr(self, 'num_channels'): self.num_channels = 3 if self.num_channels > 1: return (self.frustum['height'], self.frustum['width'], self.num_channels) else: return (self.frustum['height'], self.frustum['width']) def compute_r(self): tmp = self.camera.r return self.color_image # .reshape((self.frustum['height'], self.frustum['width'], -1)).squeeze() def compute_dr_wrt(self, wrt): if wrt is not self.camera and wrt is not self.vc and wrt is not self.bgcolor: return None visibility = self.visibility_image shape = visibility.shape color = self.color_image visible = np.nonzero(visibility.ravel() != 4294967295)[0] num_visible = len(visible) barycentric = self.barycentric_image if wrt is self.camera: if self.overdraw: return common.dImage_wrt_2dVerts_bnd( color, visible, visibility, barycentric, self.frustum['width'], self.frustum['height'], self.v.r.size / 3, self.f, self.boundaryid_image != 4294967295) else: return common.dImage_wrt_2dVerts(color, visible, visibility, barycentric, self.frustum['width'], self.frustum['height'], self.v.r.size / 3, self.f) elif wrt is self.vc: return common.dr_wrt_vc(visible, visibility, self.f, barycentric, self.frustum, self.vc.size, num_channels=self.num_channels) elif wrt is self.bgcolor: return common.dr_wrt_bgcolor(visibility, self.frustum, num_channels=self.num_channels) def on_changed(self, which): if 'frustum' in which: w = self.frustum['width'] h = self.frustum['height'] self.glf = OsContext(w, h, typ=GL_FLOAT) self.glf.Viewport(0, 0, w, h) self.glb = OsContext(w, h, typ=GL_UNSIGNED_BYTE) self.glb.Viewport(0, 0, w, h) if 'frustum' in which or 'camera' in which: setup_camera(self.glb, self.camera, self.frustum) setup_camera(self.glf, self.camera, self.frustum) if not hasattr(self, 'num_channels'): self.num_channels = 3 if not hasattr(self, 'bgcolor'): self.bgcolor = Ch(np.array([.5] * self.num_channels)) which.add('bgcolor') if not hasattr(self, 'overdraw'): self.overdraw = True if 'bgcolor' in which or ('frustum' in which and hasattr(self, 'bgcolor')): self.glf.ClearColor(self.bgcolor.r[0], self.bgcolor.r[1 % self.num_channels], self.bgcolor.r[2 % self.num_channels], 1.) def flow_to(self, v_next, cam_next=None): return common.flow_to(self, v_next, cam_next) def filter_for_triangles(self, which_triangles): cim = self.color_image vim = self.visibility_image + 1 arr = np.zeros(len(self.f) + 1) arr[which_triangles + 1] = 1 relevant_pixels = arr[vim.ravel()] cim2 = cim.copy() * np.atleast_3d(relevant_pixels.reshape(vim.shape)) relevant_pixels = np.nonzero(arr[vim.ravel()])[0] xs = relevant_pixels % vim.shape[1] ys = relevant_pixels / vim.shape[1] return cim2[np.min(ys):np.max(ys), np.min(xs):np.max(xs), :] @depends_on('f', 'camera', 'vc') def boundarycolor_image(self): return self.draw_boundarycolor_image(with_vertex_colors=True) def draw_color_image(self, gl): self._call_on_changed() gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # use face colors if given # FIXME: this won't work for 2 channels draw_colored_verts(gl, self.v.r, self.f, self.vc.r) result = np.asarray( deepcopy(gl.getImage()[:, :, :self.num_channels].squeeze()), np.float64) if hasattr(self, 'background_image'): bg_px = np.tile( np.atleast_3d(self.visibility_image) == 4294967295, (1, 1, self.num_channels)).squeeze() fg_px = 1 - bg_px result = bg_px * self.background_image + fg_px * result return result @depends_on(dterms + terms) def color_image(self): gl = self.glf gl.PolygonMode(GL_FRONT_AND_BACK, GL_FILL) no_overdraw = self.draw_color_image(gl) if not self.overdraw: return no_overdraw gl.PolygonMode(GL_FRONT_AND_BACK, GL_LINE) overdraw = self.draw_color_image(gl) gl.PolygonMode(GL_FRONT_AND_BACK, GL_FILL) boundarybool_image = self.boundarybool_image if self.num_channels > 1: boundarybool_image = np.atleast_3d(boundarybool_image) return np.asarray((overdraw * boundarybool_image + no_overdraw * (1 - boundarybool_image)), order='C') @depends_on('f', 'frustum', 'camera') def boundary_images(self): self._call_on_changed() return draw_boundary_images(self.glb, self.v.r, self.f, self.vpe, self.fpe, self.camera) @depends_on(terms + dterms) def boundarycolor_image(self): self._call_on_changed() gl = self.glf colors = self.vc.r.reshape((-1, 3))[self.vpe.ravel()] gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) draw_colored_primitives(gl, self.v.r.reshape((-1, 3)), self.vpe, colors) return np.asarray(deepcopy(gl.getImage()), np.float64)