def gazePointsToHeatmaps(self): self.XYHeatmap = [] self.XZHeatmap = [] for sx in range(self.gaze_points.shape[2]): XYG = [] XZG = [] for f in range(self.gaze_points.shape[0]): d = self.gaze_points[f, :, sx] xyg = self.gaussian(mu=d[0], max=self.frame_size[0]) xzg = self.gaussian(mu=d[1], max=self.frame_size[1]) XYG.append(xyg) XZG.append(xzg) self.XYHeatmap.append(np.array(XYG)) self.XZHeatmap.append(np.array(XZG)) self.XYHeatmap = np.sum(self.XYHeatmap, 0) self.XZHeatmap = np.sum(self.XZHeatmap, 0) self.XYHeatmap = gl.GLImageItem(self.getColors(self.XYHeatmap, cm.jet)) self.XZHeatmap = gl.GLImageItem(self.getColors(self.XZHeatmap, cm.jet)) self.XYHeatmap.scale(self.image_spacing, 1, 1) self.XZHeatmap.scale(self.image_spacing, 1, 1) self.XYHeatmap.rotate(90, -1, 0, 0) self.XYHeatmap.translate(0, -50 * self.scaling_factor, 0) self.XZHeatmap.translate( 0, 0, -self.frame_size[0] - 50 * self.scaling_factor)
def mkTexture(w, img, T): W = img.shape[1] if img.shape[2] == 3: obj = gl.GLImageItem(data=img2tex(img.transpose(1, 0, 2))) else: obj = gl.GLImageItem(data=img2texA(img.transpose(1, 0, 2))) w.addItem(obj) S = scale((1 / W, 1 / W, 1)) D = desp((0, 0, -DC)) def update(H): transform(D @ H @ T @ S, obj) return update
def loadFrameByNumber(self, number, rotation=[90, 0, 1, 0], x_shift=0, y_shift=0, option='translucent'): # list and sort all frames in folder frame_paths = sorted(listdir(self.image_path)) frame_paths = [path.join(self.image_path, p) for p in frame_paths] if number >= len(frame_paths): return None frame = misc.imread(frame_paths[number]) if not self.scaling_factor == 1.: frame = misc.imresize(frame, self.scaling_factor) if self.frame_size is None: self.frame_size = frame.shape[:2] self.z_shift = 0 #self.frame_size[0] # convert frame into RGBA image frame = pg.makeRGBA(frame, levels=[frame.min(), frame.max()])[0] frame = gl.GLImageItem(frame) frame.rotate(rotation[0], rotation[1], rotation[2], rotation[3]) frame.translate(number * self.image_spacing + x_shift, y_shift, self.z_shift) frame.setGLOptions(option) return frame
def _initialize_planes(self): """ Create the xy plane, the arbitrary cut plane and the view in the selector panel. """ # xy super()._initialize_planes() # selector xy = self.get_xy_slice(0) self.selector.set_image(xy, lut=self.lut) # cutline in selector if not hasattr(self, 'cutline'): self.cutline = Cutline(self.selector) self.cutline.initialize() # cut plane if hasattr(self, 'cutplane'): self.glview.removeItem(self.cutplane) cut, coords = self.get_cutline_cut() cut_texture = self.make_texture(cut) self.cutplane = gl.GLImageItem(cut_texture, glOptions=self.gloptions) # Scale and move to origin in upright position self.cutplane.scale(self.xscale, self.zscale, 1) self.cutplane.rotate(90, 1, 0, 0) self.cutplane.translate(T, 0, T) self.transform0 = self.cutplane.transform() self.glview.addItem(self.cutplane) self.cutline.sig_region_changed.connect(self.update_cut)
def prepare_RA(w, size, fov, dist=20): WIDTH, HEIGHT = size # Ponemos el punto de vista de la visualización gráfica en el origen del sistema # de referencia, con elevación y azimuth de modo que el eje x apunte hacia la # derecha, el eje y hacia abajo y el eje z mirando hacia delante. # Es la posición "inicial" de una cámara en el origen. # (ponemos distancia > 0 que luego se compensa porque cero da problemas) setCameraPosition(w, distance=DC, elevation=-90, azimuth=-90, fov=fov) # Preparamos el objeto textura que contendrá la imagen de cámara en vivo. La vamos # a situar centrada delante del punto de vista del visor gráfico, a la distancia # justa para que ocupe toda la ventana, teniendo en cuenta el FOV. Es el fondo # de la escena, delante pondremos los objetos virtuales. W2 = WIDTH / 2 d = dist s = (d + DC) / W2 * np.tan(np.radians(fov) / 2) camera_image = gl.GLImageItem(data=np.zeros([100, 100, 4])) transform( scale((s, s, 1)) @ desp((-WIDTH // 2, -HEIGHT // 2, d)), camera_image) w.addItem(camera_image) def update(frame): camera_image.setData(data=img2tex(frame.transpose(1, 0, 2))) return update
def updateXY(self): try: self.w.removeItem(self.v3) except: pass tex3 = pg.makeRGBA(self.data[:,:,self.slice3], levels=self.levels)[0] # xy plane self.v3 = gl.GLImageItem(tex3) self.v3.translate(-self.slice1, -self.slice2, 0) self.w.addItem(self.v3) return
def updateXZ(self): try: self.w.removeItem(self.v2) except: pass tex2 = pg.makeRGBA(self.data[:,self.slice2], levels=self.levels)[0] # xz plane self.v2 = gl.GLImageItem(tex2) self.v2.translate(-self.slice1, -self.slice3, 0) self.v2.rotate(-90, 1,0,0) self.w.addItem(self.v2) return
def updateYZ(self): try: self.w.removeItem(self.v1) except: pass tex1 = pg.makeRGBA(self.data[self.slice1], levels=self.levels)[0] # yz plane self.v1 = gl.GLImageItem(tex1) self.v1.translate(-self.slice2, -self.slice3, 0) self.v1.rotate(90, 0,0,1) self.v1.rotate(-90, 0,1,0) self.w.addItem(self.v1) return
def slice(self): if( len(self.mesh) == 0): self.message('Load mesh first!') return self.slices.clear() curdir = os.getcwd() if(path.isdir("images")): #remove all files in images filelist = [ f for f in os.listdir("./images") if f.endswith(".png") ] for f in filelist: os.remove(os.path.join(curdir+"/images", f)) else: os.mkdir("images") self.out_path = os.path.join(curdir, "images/slice-%d.png") self.message('Slicing mesh...') self.update_var() self.mesh_info.first_layer_thicknes = self.conf.get("first_layer_thickness") self.mesh_info.layer_thickness = self.conf.get("layer_thickness") nLayer = self.mesh_info.get_layers() z_list = self.mesh_info.get_z_list() str_layers = str(nLayer) x_pixel_size, y_pixel_size, x0, y0 = stl2pngfunc.stl2png(self.mesh_info.path, z_list, self.mesh_info.image_width, self.mesh_info.image_height, self.out_path, self.mesh_info.border_size, func = lambda i: self.message("slicing layer " + str(i+1) + "/" + str_layers, False) ) self.mesh_info.real_pixel_size, self.mesh_info.real_pixel_size, self.gcode_minx, self.gcode_miny = x_pixel_size, y_pixel_size, x0, y0 self.message('Slicing mesh into ' + self.out_path) self.message(self.mesh_info.get_info() ) im = cv2.imread(self.out_path % 0) tex1 = cv2.cvtColor(im, cv2.COLOR_BGR2RGBA) v1 = gl.GLImageItem(tex1) v1.translate(0, 0, 0) self.view_slice.addItem(v1) # activate slider self.sl.setMinimum(0) self.sl.setMaximum(self.mesh_info.get_layers() - 1) self.sl.setValue(0) self.sl.setTickPosition(QSlider.TicksBelow) self.sl.setTickInterval(1) self.sl.valueChanged.connect(self.show_slice) return
def show_slice(self): i = self.sl.value() self.message("Show slice {}.".format(i+1), False) curdir = os.getcwd() im = cv2.imread(self.out_path % i) #self.slices[i] = im tex1 = cv2.cvtColor(im, cv2.COLOR_BGR2RGBA) v1 = gl.GLImageItem(tex1) v1.translate(0, 0, i * self.mesh_info.layer_thickness) self.view_slice.items = [] self.view_slice.addItem(v1)
def updateXZ(self): try: self.w.removeItem(self.v2) except: pass tex2 = pg.makeRGBA(self.data[:,self.slice2], levels=self.levels)[0] # xz plane self.v2 = gl.GLImageItem(tex2) #self.v2.translate(-self.slice1, -self.slice3, int(self.shape[1]/2)-self.slice2) self.v2.translate(-self.slice1, -self.slice3, -int(self.shape[1]/2)+self.slice2) self.v2.rotate(-90, 1,0,0) #self.v2.scale(-1, 1, 1, local=False) #fliplr self.w.addItem(self.v2) return
def loadKeyFrames(self, key_frame_list, rotation=[90, 0, 1, 0], scale=.5): self.keyFrames = [] for kf in key_frame_list: if kf >= len(self.frames) or kf < 0: print('key frame value not in list: {0}'.format(kf)) continue data = self.frames[kf].data.copy() keyFrame = gl.GLImageItem(data) keyFrame.rotate(*rotation) keyFrame.scale(scale, scale, 1) keyFrame.translate(self.image_spacing * kf, self.frame_size[1] * 1.15, 0) #-self.frame_size[0]*1.15) self.keyFrames.append(keyFrame)
def img2glimage(img_path, gloptions): imgarr, sizex, sizey, xcols, yrows, midpt = image2array(img_path) v1 = gl.GLImageItem(imgarr) sx = sizex / xcols sy = sizey / yrows v1.scale(sx, sy, 0) dx = sizex / 2 #sizex/2 dy = sizey / 2 #sizey/2 v1.translate(-1 * dx, -1 * dy, 0) v1.rotate(180, 0, 1, 0) v1.rotate(180, 0, 0, 1) v1.translate(midpt[0], midpt[1], 0) v1.setGLOptions(gloptions) return v1
def fill(self): try: i = self.sl.value() self.message("Show slice {}.".format(i + 1), False) curdir = os.getcwd() filepath = self.out_path % i offset = self.conf.get("infill_offset") line_width = 1 # int(abs(offset)/2) pe = pathengine.pathEngine() pe.generate_contours_from_img(filepath, True) pe.im = cv2.cvtColor(pe.im, cv2.COLOR_GRAY2BGR) contour_tree = pe.convert_hiearchy_to_PyPolyTree() group_contour = pe.get_contours_from_each_connected_region( contour_tree, '0') # draw boundaries ################################# # Generate N color list ################################# def generate_RGB_list(N): import colorsys HSV_tuples = [(x * 1.0 / N, 0.8, 0.9) for x in range(N)] RGB_tuples = map(lambda x: colorsys.hsv_to_rgb(*x), HSV_tuples) rgb_list = tuple(RGB_tuples) return np.array(rgb_list) * 255 N = 50 colors = generate_RGB_list(N) bg_img = pe.im.copy() bg_img = np.full(bg_img.shape, 255, dtype=np.uint8) for boundary in group_contour.values(): spiral = mkspiral.spiral(pe, boundary, offset) pathengine.suPath2D.draw_line( spiral, bg_img, colors[0], line_width) # for show cv2.imwrite(filepath, bg_img) tex1 = cv2.cvtColor(bg_img, cv2.COLOR_BGR2RGBA) v1 = gl.GLImageItem(tex1) v1.translate(0, 0, i * self.mesh_info.layer_thickness) self.view_slice.items = [] self.view_slice.addItem(v1) except Exception as e: self.message(str(e)) return
def initialize_xy(self): """ Create the xy plane. """ # Get out if no data is present if self.data.get_value() is None: return # Remove any old planes if hasattr(self, 'xy'): self.glview.removeItem(self.xy) # Get the data and texture to create the GLImageItem object cut = self.get_xy_slice(self.slider_xy.pos.get_value()) texture = self.make_texture(cut) self.xy = gl.GLImageItem(texture, glOptions=self.gloptions) # Scale and translate to origin and add to glview self.xy.scale(self.xscale, self.yscale, 1) self.xy.translate(T, T, T) # Put to position in accordance with slider self.old_z = 0 #self.slider_xy.pos.get_value() self.update_xy() # Add to GLView self.glview.addItem(self.xy)
def initialize_zx(self): """ Create the zx plane. """ # Get out if no data is present if self.data.get_value() is None: return # Remove any old planes if hasattr(self, 'zx'): self.glview.removeItem(self.zx) # Get the data and texture to create the GLImageItem object cut = self.get_zx_slice(0) texture = self.make_texture(cut) self.zx = gl.GLImageItem(texture, glOptions=self.gloptions) # Scale and translate to origin and add to glview (this plane has # shape (x, z)) self.zx.scale(self.xscale, self.zscale, 1) self.zx.translate(T, T, 0) self.zx.rotate(90, 1, 0, 0) self.zx.translate(0, T, 0) # Put to position in accordance with slider self.update_zx() # Add to GLView self.glview.addItem(self.zx)
def gazePointsToGaussians(self, sigma=20, rotation=[90, 0, 1, 0], x_shift=0, y_shift=0, option='additive'): ''' Transforms the csv data into a list of GLImageItems. Each item contains the viewpoints (AOIs) of every subject represented as Gaussians ''' self.gaussians = [] self.XYHeatmap = [] self.XZHeatmap = [] for frame_idx in range(self.gaze_points.shape[0]): print('computing gaussian overlay #{0}'.format(frame_idx)) frame_data = self.gaze_points[frame_idx, :2, :] gaussians = [] for subject in range(self.gaze_points.shape[2]): # mus are simply pixel indices of eye tracking subject_data = frame_data[:, subject] # gaussian = self.gaussian2d([subject_data[0], subject_data[1]], self.sigma) gaussians.append(gaussian) # add all gaussians gaussians = np.sum(gaussians, 0) # divide by number of subjects to renormalize gaussians (0,1) gaussians /= (subject + 1) # transform to RGBA gaussians = self.getColors(gaussians, cm.jet) # transform into GLImageItem gaussians = gl.GLImageItem(gaussians) # rotate, translate, scale, set option gaussians.rotate(rotation[0], rotation[1], rotation[2], rotation[3]) gaussians.translate(frame_idx * self.image_spacing + x_shift + 1, y_shift, 0) gaussians.setGLOptions(option) self.gaussians.append(gaussians)
def __init__(self, w, path, sensor_no): super().__init__() a = self._anchor = gl.GLGraphicsItem.GLGraphicsItem() self._gizmo = gl.GLAxisItem(size=self.SIZE) self._gizmo.setParentItem(a) name = "{} {}".format(path[1:], sensor_no) sd_font = ImageFont.truetype(str(SQUARE_DEAL), 20) temp_image = Image.new('RGBA', (2, 2), (0, 0, 0, 0)) width, height = ImageDraw.Draw(temp_image).textsize(name, sd_font) txt_image = Image.new('RGBA', (width + 2, height + 2), (0, 0, 0, 0)) draw = ImageDraw.Draw(txt_image) draw.text((1, 1), name, font=sd_font, fill=(255, 255, 255, 128)) tex1 = np.asarray(txt_image) v1 = gl.GLImageItem(tex1) v1.setParentItem(a) v1.scale(0.05, 0.05, 0.05) w.addItem(a) w.addItem(v1) w.addItem(self._gizmo) self._sensor_no = sensor_no self.update(QtGui.QQuaternion())
## create volume data set to slice three images from shape = (100, 100, 70) data = pg.gaussianFilter(np.random.normal(size=shape), (4, 4, 4)) data += pg.gaussianFilter(np.random.normal(size=shape), (15, 15, 15)) * 15 ## slice out three planes, convert to RGBA for OpenGL texture levels = (-0.08, 0.08) tex1 = pg.makeRGBA(data[shape[0] // 2], levels=levels)[0] # yz plane tex2 = pg.makeRGBA(data[:, shape[1] // 2], levels=levels)[0] # xz plane tex3 = pg.makeRGBA(data[:, :, shape[2] // 2], levels=levels)[0] # xy plane #tex1[:,:,3] = 128 #tex2[:,:,3] = 128 #tex3[:,:,3] = 128 ## Create three image items from textures, add to view v1 = gl.GLImageItem(tex1) v1.translate(-shape[1] / 2, -shape[2] / 2, 0) v1.rotate(90, 0, 0, 1) v1.rotate(-90, 0, 1, 0) w.addItem(v1) v2 = gl.GLImageItem(tex2) v2.translate(-shape[0] / 2, -shape[2] / 2, 0) v2.rotate(-90, 1, 0, 0) w.addItem(v2) v3 = gl.GLImageItem(tex3) v3.translate(-shape[0] / 2, -shape[1] / 2, 0) w.addItem(v3) ax = gl.GLAxisItem() w.addItem(ax)
if show_time: w.addItem(make_grid_item((-radius, 0, time_length/2), (90, 0, 1, 0), (time_length/20, radius/10, radius/10))) w.addItem(make_grid_item((-radius, 0, time_length*3/2), (90, 0, 1, 0), (time_length/20, radius/10, radius/10))) w.addItem(make_grid_item((0, -radius, time_length/2), (90, 1, 0, 0), (radius/10, time_length/20, radius/10))) w.addItem(make_grid_item((0, -radius, time_length*3/2), (90, 1, 0, 0), (radius/10, time_length/20, radius/10))) w.addItem(make_grid_item((0, 0, 0), (0, 0, 0, 0), (radius/10, radius/10, radius/10))) # Make Image Base # Determine the background image according to meta phase bg_path = 'maze.png' img = imread(os.path.join(local_directory, bg_path)) image_scale = (radius * 2.0) / float(img.shape[0]) tex1 = pg.makeRGBA(img)[0] base_image = gl.GLImageItem(tex1) base_image.translate(-radius, -radius, 0) base_image.rotate(270, 0, 0, 1) base_image.scale(image_scale, image_scale, image_scale) w.addItem(base_image) # Generate Path Line color = (255, 255, 255, 255) line_color = np.empty((len(iterations), 4)) line_color_state = np.empty((len(iterations), 4)) x = [] y = [] z = [] for idx, i in enumerate(iterations): x.append(float(i['x']))
ax = gl.GLAxisItem(glOptions='opaque') ax.setSize(2, 2, 2) win.addItem(ax) ax.setTransform( QtGui.QMatrix4x4(*(rotation((1, 0, 0), 0.0001, homog=True).flatten()))) ax.translate(0, 0, -0.02) axc = gl.GLAxisItem(glOptions='opaque') axc.setSize(1, 1, 1) #axc.translate(0,0,0.02) win.addItem(axc) # imagen view = gl.GLImageItem(data=np.zeros([100, 100, 4])) win.addItem(view) # marker gmark = gl.GLLinePlotItem(pos=np.vstack([marker, marker[0]]), color=(255, 0, 0, 1), antialias=True, width=3) gmark.setGLOptions('opaque') gmark.translate(0, 0, 0.01) win.addItem(gmark) # camera cam = gl.GLLinePlotItem(pos=np.array([[0, 0, 0]]), color=(255, 255, 255, 1), antialias=True,
def fill(self): try: i = self.sl.value() self.message("Show slice {}.".format(i + 1), False) curdir = os.getcwd() filepath = self.out_path % i offset = -6 line_width = 1 #int(abs(offset)/2) pe = pathengine.pathEngine() pe.generate_contours_from_img(filepath, True) pe.im = cv2.cvtColor(pe.im, cv2.COLOR_GRAY2BGR) contour_tree = pe.convert_hiearchy_to_PyPolyTree() group_contour = pe.get_contours_from_each_connected_region( contour_tree, '0') #draw boundaries ################################# # Generate N color list ################################# def generate_RGB_list(N): import colorsys HSV_tuples = [(x * 1.0 / N, 0.8, 0.9) for x in range(N)] RGB_tuples = map(lambda x: colorsys.hsv_to_rgb(*x), HSV_tuples) rgb_list = tuple(RGB_tuples) return np.array(rgb_list) * 255 N = 50 colors = generate_RGB_list(N) for boundary in group_contour.values(): iso_contours = pe.fill_closed_region_with_iso_contours( boundary, offset) idx = 0 for cs in iso_contours: for c in cs: pathengine.suPath2D.draw_line(np.vstack([c, c[0]]), pe.im, colors[idx], line_width) idx += 1 cv2.imwrite(filepath, pe.im) tex1 = cv2.cvtColor(pe.im, cv2.COLOR_BGR2RGBA) v1 = gl.GLImageItem(tex1) v1.translate(0, 0, i * self.mesh_info.layer_thickness) self.view_slice.items = [] self.view_slice.addItem(v1) except Exception as e: self.message(str(e)) # gen fermat's curve # gen 3d point n*3 matrix #n = 51 #y = np.linspace(-10,10,n) #x = np.linspace(-10,10,100) #for i in range(n): #yi = np.array([y[i]]*100) #d = (x**2 + yi**2)**0.5 #z = 10 * np.cos(d) / (d+1) #pts = np.vstack([x,yi,z]).transpose() #plt = gl.GLLinePlotItem(pos=pts, color=pg.glColor((i,n*1.3)), width=(i+1)/10., antialias=True) #self.view_slice.addItem(plt) return
def init_ui(self): self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setMinimumSize(250, 250) layout = QGridLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) positions = np.vstack([self.x_points, self.y_points, self.z_points]).transpose() self.view = GLViewWidgetFix.GLViewWidgetFix() self.view.setBackgroundColor(119, 181, 254) self.view.setCameraPosition(distance=1950, elevation=90, azimuth=0) self.plot = opengl.GLLinePlotItem(pos=positions, color=[1, 0, 0, 1], width=3) self.plot.setGLOptions("opaque") self.view.addItem(self.plot) # self.grid = opengl.GLGridItem(color="white") # self.grid.setSize(x=(self.lon_max-self.lon_min)*self.meters_per_lon, # y=(self.lat_max-self.lat_min)*self.meters_per_lat) # self.grid.setSpacing(x=100, y=100) # self.view.addItem(self.grid) self.image_file = Image.open(self.image_name) self.image = opengl.GLImageItem(np.asarray(self.image_file)) self.view.addItem(self.image) self.image.scale((self.lat_max - self.lat_min) * self.meters_per_lat / self.image_file.size[1], (self.lon_max - self.lon_min) * self.meters_per_lon / self.image_file.size[0], 1) self.image.translate( -(self.lat_max - self.lat_min) * self.meters_per_lat / 2, -(self.lon_max - self.lon_min) * self.meters_per_lon / 2, 0) flat_earth = opengl.GLMeshItem(meshdata=opengl.MeshData.cylinder( 1, 64, [6371000, 0], 0), color=[84 / 255, 89 / 255, 72 / 255, 1], smooth=True) flat_earth.translate(0, 0, -10000) flat_earth.setGLOptions("opaque") self.view.addItem(flat_earth) crosshair_mesh = mesh.Mesh.from_file("DisplayModels/Crosshairs.stl") crosshair_mesh_data = opengl.MeshData(vertexes=crosshair_mesh.vectors) self.crosshair = opengl.GLMeshItem(meshdata=crosshair_mesh_data, color=[1, 0, 0, 1]) self.set_crosshair_pos(0, 0, 0) self.view.addItem(self.crosshair) self.view_btn = QPushButton("2D") self.view_btn.clicked.connect(self.switch_3d) self.view_btn.setMaximumWidth(30) self.coords_label = QLineEdit("0,0") self.coords_label.setAlignment(Qt.AlignCenter) self.coords_label.setReadOnly(True) self.clear_btn = QPushButton("CLR") self.clear_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.clear_btn.setToolTip("Clear Data") self.clear_btn.setFixedWidth(35) self.clear_btn.setParent(self.view) self.clear_btn.clicked.connect(self.clear_plot) self.sats_label = QLineEdit("0") self.sats_label.setAlignment(Qt.AlignCenter) self.sats_label.setReadOnly(True) self.sats_label.setToolTip("Number of Satellites") self.sats_label.setMaximumWidth(50) layout.addWidget(self.view, 0, 0, 1, 4) layout.addWidget(self.clear_btn, 1, 3) layout.addWidget(self.view_btn, 1, 0) layout.addWidget(self.coords_label, 1, 1) layout.addWidget(self.sats_label, 1, 2)
data = pickle.load(f) nx, ny, nz = data.shape print(nx, ny, nz) x0, y0, z0 = 0, 0, 0 x0, y0, z0 = [int(2 * n / 5) for n in [nx, ny, nz]] # Create Textures levels = [data.min(), data.max()] cmap = cmaps[cmap] lut = cmap.getLookupTable() textures = [ pg.makeRGBA(d, levels=levels, lut=lut)[0] for d in [data[x0], data[:, y0], data[:, :, z0]] ] planes = [gl.GLImageItem(texture, glOptions=gloption) for texture in textures] ## Apply transformations to get lanes where they need to go xscale, yscale, zscale = 1 / nx, 1 / ny, 1 / nz # xy plane xy = planes[2] xy.scale(xscale, yscale, 1) xy.translate(-1 / 2, -1 / 2, -1 / 2 + z0 * zscale) main.addItem(xy) # yz plane (appears in the coordinate system along xy) yz = planes[0] yz.scale(yscale, zscale, 1) yz.rotate(90, 0, 0, 1) yz.rotate(90, 0, 1, 0) yz.translate(-1 / 2 + x0 * xscale, -1 / 2, -1 / 2)
def __init__(self): super(MyView, self).__init__() self.opts['distance'] = 10 self.opts['center'].setX(floor_sz[0] * 0.5) self.opts['center'].setY(floor_sz[1] * 0.5) self.opts['center'].setZ(wall_height * 0.5) self.opts['elevation'] = 0 self.show() self.setWindowTitle('Hack4Sweden') # Floor floor_tex = scipy.ndimage.imread('textures/wood.jpeg', mode='RGBA') floor_tex = tile(floor_tex, floor_sz) floor = gl.GLImageItem(floor_tex) self.addItem(floor) # Walls wall1_tex = scipy.ndimage.imread('textures/wall_tex.jpg', mode='RGBA') wall1_tex = tile(wall1_tex, [floor_sz[0], wall_height]) wall1 = gl.GLImageItem(wall1_tex) wall1.rotate(90, 1, 0, 0) self.addItem(wall1) wall2 = gl.GLImageItem(wall1_tex) wall2.rotate(90, 1, 0, 0) wall2.translate(0, floor_sz[1], 0) self.addItem(wall2) # Lighting globAmb = [0.3, 0.3, 0.3, 1.0] lightAmb = [0.75, 0.75, 0.75, 1.0] lightDifAndSpec = [0.7, 0.7, 0.7, 1.0] # glEnable(GL_LIGHTING) # glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb) # glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDifAndSpec) # glLightfv(GL_LIGHT0, GL_SPECULAR, lightDifAndSpec) # # glLightfv(GL_LIGHT0, GL_POSITION, [500, 250, 100, 0]) # glEnable(GL_LIGHT0) # glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globAmb) # glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) # glEnable(GL_DEPTH_TEST) # Load paintings db = TinyDB('paintings/db.json') # db.insert({'name': 'Captain Planet', 'img': 'test.jpg'}) added = 0 for item in db.all(): painting_tex = scipy.ndimage.imread('paintings/' + item['img'], mode='RGBA') painting = gl.GLImageItem(painting_tex, smooth=True) scale = painting_width * 1.0 / painting_tex.shape[1] painting.rotate(90, 0, 1, 0) painting.rotate(90, 0, 0, 1) painting.scale(scale, scale, scale) added += painting_spacing + painting_width painting.translate(added, 5, painting_tex.shape[0] * scale / 2 + wall_height / 2) self.addItem(painting)
def visualize(path=None): """ This function visualizes data for the virtual morris water maze task. :param path: a path to a log file from the virtual morris water maze task :return: Nothing """ # noinspection PyGlobalUndefined global path_line, idx, timer, iterations, num_points_to_update, line_color_state, line_color #################################################################################################################### # Setup #################################################################################################################### show_time = False if path is None: path = easygui.fileopenbox() if path is '': logging.info('No file selected. Closing.') exit() if not os.path.exists(path): logging.error('File not found. Closing.') exit() meta = None # noinspection PyBroadException try: meta = get_filename_meta_data(os.path.basename(path)) # The meta filename information for convenience except: logging.error('There was an error reading the filename meta-information. Please confirm this is a valid log ' 'file.') exit() logging.info("Parsing file (" + str(path) + ")...") # First we populate a list of each iteration's data # This section of code contains some custom binary parser data which won't be explained here iterations = read_binary_file(path) # Output the iterations count for debugging purposes logging.info("Plotting " + str(len(iterations)) + " iterations.") # Generate UI Window and Set Camera Settings app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['center'] = pg.Qt.QtGui.QVector3D(0, 0, 0) w.opts['elevation'] = 90 w.opts['azimuth'] = 0 w.opts['distance'] = 200 w.setWindowTitle('MSL Virtual Morris Water Maze Visualizer' + ' - Subject {0}, Trial {1}, iteration {2}'.format( meta['subid'], meta['trial'], trial_num_to_str(meta['iteration']))) #################################################################################################################### # Generate static graphical items #################################################################################################################### # Make Grid grid_items = [] def make_grid_item(loc, rot, scale): g = gl.GLGridItem() g.scale(scale[0], scale[1], scale[2]) g.rotate(rot[0], rot[1], rot[2], rot[3]) g.translate(loc[0], loc[1], loc[2]) return g radius = 60 time_length = 60 if show_time: g0 = make_grid_item((-radius, 0, time_length/2), (90, 0, 1, 0), (time_length/20, radius/10, radius/10)) g1 = make_grid_item((-radius, 0, time_length*3/2), (90, 0, 1, 0), (time_length/20, radius/10, radius/10)) g2 = make_grid_item((0, -radius, time_length/2), (90, 1, 0, 0), (radius/10, time_length/20, radius/10)) g3 = make_grid_item((0, -radius, time_length*3/2), (90, 1, 0, 0), (radius/10, time_length/20, radius/10)) grid_items.append(g0) grid_items.append(g1) grid_items.append(g2) grid_items.append(g3) w.addItem(g0) w.addItem(g1) w.addItem(g2) w.addItem(g3) gn = make_grid_item((0, 0, 0), (0, 0, 0, 0), (radius/10, radius/10, radius/10)) grid_items.append(gn) w.addItem(gn) # Make Image Base # Determine the background image according to meta phase bg_path = 'maze.png' img = imread(os.path.join('./media/virtual_morris_water_maze', bg_path)) image_scale = (radius * 2.0) / float(img.shape[0]) tex1 = pg.makeRGBA(img)[0] base_image = gl.GLImageItem(tex1) base_image.translate(-radius, -radius, 0) base_image.rotate(270, 0, 0, 1) base_image.scale(image_scale, image_scale, image_scale) w.addItem(base_image) # Generate Path Line color = (255, 255, 255, 255) line_color = np.empty((len(iterations), 4)) line_color_state = np.empty((len(iterations), 4)) x = [] y = [] z = [] for idx, i in enumerate(iterations): x.append(float(i['x'])) y.append(float(i['z'])) if show_time: z.append(float(i['time'])) else: z.append(0.0) line_color[idx] = pg.glColor(color) line_color_state[idx] = pg.glColor((0, 0, 0, 0)) pts = np.vstack([x, y, z]).transpose() path_line = gl.GLLinePlotItem(pos=pts, color=line_color_state, mode='line_strip', antialias=True) w.addItem(path_line) #################################################################################################################### # Show UI #################################################################################################################### w.show() logging.info("Showing plot. Close plot to exit program.") #################################################################################################################### # Custom Keyboard Controls #################################################################################################################### # These variables are modified by the keyboard controls idx = 0 num_points_to_update = 5 saved_points_to_update = 0 paused = False # GUI Callbacks def speed_up(): global num_points_to_update, paused if not paused: num_points_to_update += 5 logging.info("Setting speed to " + str(num_points_to_update) + " points per tick.") def speed_down(): global num_points_to_update, paused if not paused: num_points_to_update -= 5 logging.info("Setting speed to " + str(num_points_to_update) + " points per tick.") def pause(): global num_points_to_update, saved_points_to_update, paused if not paused: logging.info("Paused.") saved_points_to_update = num_points_to_update num_points_to_update = 0 paused = True else: logging.info("Unpaused.") num_points_to_update = saved_points_to_update saved_points_to_update = -0.5 paused = False def reset(): global idx, line_color_state logging.info("Resetting to time zero.") idx = 0 for index in range(0, len(line_color_state) - 1): line_color_state[index] = (0, 0, 0, 0) def go_to_end(): global idx, line_color_state, line_color logging.info("Going to end.") idx = len(line_color_state) - 1 for index in range(0, len(line_color_state) - 1): line_color_state[index] = line_color[index] def close_all(): global timer, app logging.info("User Shutdown Via Button Press") timer.stop() app.closeAllWindows() # Visibility Variables grid_visible = True base_visible = True path_line_visible = True def toggle_grid_visible(): global grid_visible if grid_visible: for g in grid_items: g.hide() grid_visible = False else: for g in grid_items: g.show() grid_visible = True def toggle_base_visible(): global base_visible if base_visible: base_image.hide() base_visible = False else: base_image.show() base_visible = True def toggle_path_line_visible(): global path_line_visible if path_line_visible: path_line.hide() path_line_visible = False else: path_line.show() path_line_visible = True # GUI Initialization sh = QtGui.QShortcut(QtGui.QKeySequence("+"), w, speed_up) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("-"), w, speed_down) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence(" "), w, pause) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("R"), w, reset) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("E"), w, go_to_end) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("Escape"), w, close_all) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("1"), w, toggle_grid_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("2"), w, toggle_base_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("5"), w, toggle_path_line_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) #################################################################################################################### # Animation Loop #################################################################################################################### timer = QtCore.QTimer() # noinspection PyUnresolvedReferences timer.timeout.connect(update) timer.start(1) #################################################################################################################### # PyQtGraph Initialization #################################################################################################################### if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): # noinspection PyArgumentList QtGui.QApplication.instance().exec_()
plt_yaxis = gl.GLLinePlotItem(pos=pts_yaxis, width=linewidth, antialias=True) w.addItem(plt_yaxis) ## make x-axis xaxis = np.linspace(-x_length, x_length, 10) y_xaxis = np.zeros(10) z_xaxis = np.zeros(10) pts_xaxis = np.vstack([y_xaxis, z_xaxis, xaxis]).transpose() plt_xaxis = gl.GLLinePlotItem(pos=pts_xaxis, width=linewidth, antialias=True) w.addItem(plt_xaxis) ## make images image_shape = (8, 8) uniform_values = np.ones(image_shape) * 255 uniform_image_transparent = pg.makeARGB(uniform_values)[0] uniform_image_transparent[:, :, 3] = 65 v1 = gl.GLImageItem(uniform_image_transparent) v1.translate(-image_shape[0] / 2, -image_shape[1] / 2, 0) v1.rotate(90, 1, 0, 0) #w.addItem(v1) v = [] for i in range(0, 20): vtemp = gl.GLImageItem(uniform_image_transparent) vtemp.translate(-image_shape[0] / 2, -image_shape[1] / 2, 0) vtemp.rotate(90, 1, 0, 0) dz = float(i - 10) vtemp.translate(0, dz, 0) v.append(vtemp) w.addItem(v[i]) # Set up some animation parameters frametime = 50 # frame refresh time in ms
def make_color_bar(rgb, p, r, s): v = gl.GLImageItem(np.array([[rgb + (255,)]])) v.translate(p[0], p[1], p[2]) v.scale(s[0], s[1], s[2]) v.rotate(r[0], r[1], r[2], r[3]) return v
def visualize_time_travel_data(path=None, automatically_rotate=True): """ This function visualizes data from the Time Travel Task in 3D. :param path: the path to a data file to visualize :param automatically_rotate: If True, the figure will automatically rotate in an Abs(Sin(x)) function shape, otherwise the user can interact with the figure. :return: Nothing """ # noinspection PyGlobalUndefined global path_line, idx, timer, iterations, click_scatter, click_pos, click_color, click_size, window, meta, \ reconstruction_items, num_points_to_update, line_color, line_color_state, auto_rotate auto_rotate = automatically_rotate #################################################################################################################### # Setup #################################################################################################################### # Get Log File Path and Load File local_directory = os.path.dirname(os.path.realpath(__file__)) # The directory of this script # filename = '001_1_1_1_2016-08-29_10-26-03.dat' # The relative path to the data file (CHANGE ME) # path = os.path.join(local_directory, filename) if path is None: path = easygui.fileopenbox() if path is '': logging.info('No file selected. Closing.') exit() if not os.path.exists(path): logging.error('File not found. Closing.') exit() meta = None # noinspection PyBroadException try: meta = get_filename_meta_data(os.path.basename(path)) # The meta filename information for convenience except: logging.error('There was an error reading the filename meta-information. Please confirm this is a valid log ' 'file.') exit() logging.info("Parsing file (" + str(path) + ")...") # First we populate a list of each iteration's data # This section of code contains some custom binary parser data which won't be explained here iterations = read_binary_file(path) # Output the iterations count for debugging purposes logging.info("Plotting " + str(len(iterations)) + " iterations.") # Generate UI Window and Set Camera Settings app = QtGui.QApplication([]) window = gl.GLViewWidget() window.opts['center'] = pg.Qt.QtGui.QVector3D(0, 0, 30) window.opts['distance'] = 200 window.setWindowTitle('Timeline Visualizer' + ' - Subject {0}, Trial {1}, Phase {2}'.format(meta['subID'], meta['trial'], phase_num_to_str(int(meta['phase'])))) #################################################################################################################### # Generate static graphical items #################################################################################################################### # Make Grid grid_items = [] def make_grid_item(loc, rot, scale): g = gl.GLGridItem() g.scale(scale[0], scale[1], scale[2]) g.rotate(rot[0], rot[1], rot[2], rot[3]) g.translate(loc[0], loc[1], loc[2]) return g if meta['phase'] == '0' or meta['phase'] == '3' or meta['phase'] == '6': g0 = make_grid_item((-19, 0, 15), (90, 0, 1, 0), (1.5, 1.9, 1.9)) g1 = make_grid_item((0, -19, 15), (90, 1, 0, 0), (1.9, 1.5, 1.9)) grid_items.append(g0) grid_items.append(g1) window.addItem(g0) window.addItem(g1) else: g0 = make_grid_item((-19, 0, 15), (90, 0, 1, 0), (1.5, 1.9, 1.9)) g1 = make_grid_item((-19, 0, 45), (90, 0, 1, 0), (1.5, 1.9, 1.9)) g2 = make_grid_item((0, -19, 15), (90, 1, 0, 0), (1.9, 1.5, 1.9)) g3 = make_grid_item((0, -19, 45), (90, 1, 0, 0), (1.9, 1.5, 1.9)) grid_items.append(g0) grid_items.append(g1) grid_items.append(g2) grid_items.append(g3) window.addItem(g0) window.addItem(g1) window.addItem(g2) window.addItem(g3) gn = make_grid_item((0, 0, 0), (0, 0, 0, 0), (1.9, 1.9, 1.9)) grid_items.append(gn) window.addItem(gn) # Make Image Base # Determine the background image according to meta phase img_location = './media/time_travel_task/' bg_path = 'studyBG.png' if meta['phase'] == '0' or meta['phase'] == '3': bg_path = 'practiceBG.png' elif meta['phase'] == '6': bg_path = 'practiceBG.png' elif meta['phase'] == '7' or meta['phase'] == '8': bg_path = 'studyBG.png' img = imread(os.path.abspath(os.path.join(img_location, bg_path))) image_scale = (19.0 * 2.0) / float(img.shape[0]) tex1 = pg.makeRGBA(img)[0] base_image = gl.GLImageItem(tex1) base_image.translate(-19, -19, 0) base_image.rotate(270, 0, 0, 1) base_image.scale(image_scale, image_scale, image_scale) window.addItem(base_image) # Make Timeline Colored Bars color_bars = [] def make_color_bar(rgb, p, r, s): v = gl.GLImageItem(np.array([[rgb + (255,)]])) v.translate(p[0], p[1], p[2]) v.scale(s[0], s[1], s[2]) v.rotate(r[0], r[1], r[2], r[3]) return v color_bar_length = 15 if meta['phase'] == '0' or meta['phase'] == '3' or meta['phase'] == '6': times = [0, 7.5, 15, 22.5] color_bar_length = 7.5 else: times = [0, 15, 30, 45] if meta['inverse'] == '1': times.reverse() v0 = make_color_bar((255, 255, 0), (19, times[0], 19), (90, 1, 0, 0), (5, color_bar_length, 0)) v1 = make_color_bar((255, 0, 0), (19, times[1], 19), (90, 1, 0, 0), (5, color_bar_length, 0)) v2 = make_color_bar((0, 255, 0), (19, times[2], 19), (90, 1, 0, 0), (5, color_bar_length, 0)) v3 = make_color_bar((0, 0, 255), (19, times[3], 19), (90, 1, 0, 0), (5, color_bar_length, 0)) color_bars.append(v0) color_bars.append(v1) color_bars.append(v2) color_bars.append(v3) window.addItem(v0) window.addItem(v1) window.addItem(v2) window.addItem(v3) # Generate Path Line forwardColor = (255, 255, 255, 255) backwardColor = (255, 0, 255, 255) line_color = np.empty((len(iterations), 4)) line_color_state = np.empty((len(iterations), 4)) x = [] y = [] z = [] for idx, i in enumerate(iterations): x.append(float(i['x'])) y.append(float(i['z'])) z.append(float(i['time_val'])) c = forwardColor if i['timescale'] <= 0: c = backwardColor line_color[idx] = pg.glColor(c) line_color_state[idx] = pg.glColor((0, 0, 0, 0)) pts = np.vstack([x, y, z]).transpose() path_line = gl.GLLinePlotItem(pos=pts, color=line_color_state, mode='line_strip', antialias=True) window.addItem(path_line) # Generate Item Lines (ground truth) # noinspection PyUnusedLocal items, times, directions = get_items_solutions(meta) if meta['phase'] == '0' or meta['phase'] == '3' or meta['phase'] == '6': times = [2, 12, 18, 25] directions = [2, 1, 2, 1] # Fall = 2, Fly = 1, Stay = 0 if meta['inverse'] == '1': times.reverse() directions.reverse() items = [{'direction': directions[0], 'pos': (2, -12, times[0]), 'color': (255, 255, 0)}, {'direction': directions[1], 'pos': (2, 13, times[1]), 'color': (255, 0, 0)}, {'direction': directions[2], 'pos': (-13, 2, times[2]), 'color': (0, 255, 0)}, {'direction': directions[3], 'pos': (-12, -17, times[3]), 'color': (0, 0, 255)}, {'direction': 0, 'pos': (13, 5, 0), 'color': (128, 0, 128)}] # elif meta['phase'] == '7' or meta['phase'] == '8': # times = [2, 8, 17, 23] # directions = [2, 1, 1, 2] # Fall = 2, Fly = 1, Stay = 0 # if meta['inverse'] == '1': # times.reverse() # directions.reverse() # items = [{'direction': directions[0], 'pos': (16, -14, times[0]), 'color': (255, 255, 0)}, # {'direction': directions[1], 'pos': (-10, -2, times[1]), 'color': (255, 0, 0)}, # {'direction': directions[2], 'pos': (15, -8, times[2]), 'color': (0, 255, 0)}, # {'direction': directions[3], 'pos': (-15, -15, times[3]), 'color': (0, 0, 255)}, # {'direction': 0, 'pos': (-2, 10, 0), 'color': (128, 0, 128)}] else: times = [4, 10, 16, 25, 34, 40, 46, 51] directions = [2, 1, 1, 2, 2, 1, 2, 1] # Fall = 2, Fly = 1, Stay = 0 if meta['inverse'] == '1': times.reverse() directions.reverse() items = [{'direction': directions[0], 'pos': (18, -13, times[0]), 'color': (255, 255, 0)}, {'direction': directions[1], 'pos': (-13, 9, times[1]), 'color': (255, 255, 0)}, {'direction': directions[2], 'pos': (-10, -2, times[2]), 'color': (255, 0, 0)}, {'direction': directions[3], 'pos': (6, -2, times[3]), 'color': (255, 0, 0)}, {'direction': directions[4], 'pos': (17, -8, times[4]), 'color': (0, 255, 0)}, {'direction': directions[5], 'pos': (-2, -7, times[5]), 'color': (0, 255, 0)}, {'direction': directions[6], 'pos': (-15, -15, times[6]), 'color': (0, 0, 255)}, {'direction': directions[7], 'pos': (6, 18, times[7]), 'color': (0, 0, 255)}, {'direction': 0, 'pos': (14, 6, 0), 'color': (128, 0, 128)}, {'direction': 0, 'pos': (-2, 10, 0), 'color': (128, 0, 128)}] item_lines = [] pos = np.empty((len(items), 3)) size = np.empty((len(items))) color = np.empty((len(items), 4)) end_time = 60 if meta['phase'] == '0' or meta['phase'] == '3' or meta['phase'] == '6': end_time = 30 for idx, i in enumerate(items): pos[idx] = i['pos'] size[idx] = 2 if i['direction'] == 0: size[idx] = 0 color[idx] = (i['color'][0] / 255, i['color'][1] / 255, i['color'][2] / 255, 1) idx += 1 end = i['pos'] if i['direction'] == 1: end = (end[0], end[1], 0) elif i['direction'] == 2 or i['direction'] == 0: end = (end[0], end[1], end_time) line = gl.GLLinePlotItem(pos=np.vstack([[i['pos'][0], end[0]], [i['pos'][1], end[1]], [i['pos'][2], end[2]]]).transpose(), color=pg.glColor(i['color']), width=3, antialias=True) item_lines.append(line) window.addItem(line) item_scatter_plot = gl.GLScatterPlotItem(pos=pos, size=size, color=color, pxMode=False) window.addItem(item_scatter_plot) #################################################################################################################### # Generate data graphical items #################################################################################################################### # If Study/Practice, label click events '''click_pos = np.empty((len(items), 3)) click_size = np.zeros((len(iterations), len(items))) click_color = np.empty((len(items), 4)) if meta['phase'] == '0' or meta['phase'] == '1' or meta['phase'] == '3' or meta['phase'] == '4' \ or meta['phase'] == '6' or meta['phase'] == '7': for idx, i in enumerate(iterations): if idx + 1 < len(iterations): for idxx, (i1, i2) in enumerate(zip(i['itemsclicked'], iterations[idx + 1]['itemsclicked'])): if i['itemsclicked'][idxx]: click_size[idx][idxx] = 0.5 if not i1 == i2: click_pos[idxx] = (i['x'], i['z'], i['time_val']) click_color[idxx] = (128, 128, 128, 255) else: for idxx, i1 in enumerate(i['itemsclicked']): if i['itemsclicked'][idxx]: click_size[idx][idxx] = 0.5 ''' click_pos, _, click_size, click_color = get_click_locations_and_indicies(iterations, items, meta) click_scatter = gl.GLScatterPlotItem(pos=click_pos, size=click_size[0], color=click_color, pxMode=False) window.addItem(click_scatter) # If Test, Generate Reconstruction Items event_state_labels, item_number_label, item_label_filename, cols = get_item_details() # if meta['phase'] == '7' or meta['phase'] == '8': # item_number_label = ['bottle', 'clover', 'boot', 'bandana', 'guitar'] # item_label_filename = ['bottle.jpg', 'clover.jpg', 'boot.jpg', 'bandana.jpg', 'guitar.jpg'] # cols = [(255, 255, pastel_factor), (255, pastel_factor, pastel_factor), (pastel_factor, 255, pastel_factor), # (pastel_factor, pastel_factor, 255), (128, pastel_factor / 2, 128)] reconstruction_item_scatter_plot = None reconstruction_item_lines = [] if meta['phase'] == '2' or meta['phase'] == '5' or meta['phase'] == '8': reconstruction_items, order = parse_test_items(iterations, cols, item_number_label, event_state_labels) pos = np.empty((len(reconstruction_items), 3)) size = np.empty((len(reconstruction_items))) color = np.empty((len(reconstruction_items), 4)) # Iterate through the reconstruction items and visualize them for idx, i in enumerate(reconstruction_items): pos[idx] = i['pos'] size[idx] = 2 if i['direction'] == 0: size[idx] = 0 color[idx] = (i['color'][0] / 255, i['color'][1] / 255, i['color'][2] / 255, 1) end = pos[idx] if i['direction'] == 1: end = (end[0], end[1], 0) elif i['direction'] == 2 or i['direction'] == 0: end = (end[0], end[1], end_time) line = gl.GLLinePlotItem(pos=np.vstack([[pos[idx][0], end[0]], [pos[idx][1], end[1]], [pos[idx][2], end[2]]]).transpose(), color=pg.glColor(i['color']), width=3, antialias=True) reconstruction_item_lines.append(line) window.addItem(line) img_path = item_label_filename[idx] img = imread(os.path.join(local_directory, img_path)) expected_size = 2.0 image_scale = expected_size / float(img.shape[0]) offset_param = 0.0 - image_scale / 2 - expected_size / 2 tex = pg.makeRGBA(img)[0] label_image = gl.GLImageItem(tex) t = pos[idx][2] if i['direction'] == 0: t = end_time label_image.translate(pos[idx][0] + offset_param, pos[idx][1] + offset_param, t) label_image.scale(image_scale, image_scale, image_scale) window.addItem(label_image) billboard_item_labels.append(label_image) reconstruction_item_scatter_plot = gl.GLScatterPlotItem(pos=pos, size=size, color=color, pxMode=False) window.addItem(reconstruction_item_scatter_plot) #################################################################################################################### # Show UI #################################################################################################################### window.show() logging.info("Showing plot. Close plot to exit program.") #################################################################################################################### # Custom Keyboard Controls #################################################################################################################### # These variables are modified by the keyboard controls idx = 0 num_points_to_update = 5 saved_points_to_update = 0 paused = False # GUI Callbacks def speed_up(): global num_points_to_update, paused if not paused: num_points_to_update += 5 logging.info("Setting speed to " + str(num_points_to_update) + " points per tick.") def speed_down(): global num_points_to_update, paused if not paused: num_points_to_update -= 5 logging.info("Setting speed to " + str(num_points_to_update) + " points per tick.") def pause(): global num_points_to_update, saved_points_to_update, paused if not paused: logging.info("Paused.") saved_points_to_update = num_points_to_update num_points_to_update = 0 paused = True else: logging.info("Unpaused.") num_points_to_update = saved_points_to_update saved_points_to_update = -0.5 paused = False def reset(): global idx, line_color_state logging.info("Resetting to time zero.") idx = 0 for index in range(0, len(line_color_state) - 1): line_color_state[index] = (0, 0, 0, 0) def go_to_end(): global idx, line_color_state, line_color logging.info("Going to end.") idx = len(line_color_state) - 1 for index in range(0, len(line_color_state) - 1): line_color_state[index] = line_color[index] def close_all(): global timer, app logging.info("User Shutdown Via Button Press") timer.stop() app.closeAllWindows() # Visibility Variables grid_visible = True base_visible = True color_bars_visible = True items_visible = True path_line_visible = True reconstruction_item_lines_visible = True billboard_item_labels_visible = True def toggle_grid_visible(): global grid_visible if grid_visible: for g in grid_items: g.hide() grid_visible = False else: for g in grid_items: g.show() grid_visible = True def toggle_base_visible(): global base_visible if base_visible: base_image.hide() base_visible = False else: base_image.show() base_visible = True def toggle_color_bars_visible(): global color_bars_visible if color_bars_visible: for bar in color_bars: bar.hide() color_bars_visible = False else: for bar in color_bars: bar.show() color_bars_visible = True def toggle_items_visible(): global items_visible if items_visible: item_scatter_plot.hide() for il in item_lines: il.hide() items_visible = False else: item_scatter_plot.show() for il in item_lines: il.show() items_visible = True def toggle_path_line_visible(): global path_line_visible if path_line_visible: path_line.hide() click_scatter.hide() path_line_visible = False else: path_line.show() click_scatter.show() path_line_visible = True def toggle_reconstruction_item_lines_visible(): global reconstruction_item_lines_visible if reconstruction_item_lines_visible: if reconstruction_item_scatter_plot is not None: reconstruction_item_scatter_plot.hide() for ril in reconstruction_item_lines: ril.hide() reconstruction_item_lines_visible = False else: if reconstruction_item_scatter_plot is not None: reconstruction_item_scatter_plot.show() for ril in reconstruction_item_lines: ril.show() reconstruction_item_lines_visible = True def toggle_billboard_item_labels_visible(): global billboard_item_labels_visible if billboard_item_labels_visible: for il in billboard_item_labels: il.hide() billboard_item_labels_visible = False else: for il in billboard_item_labels: il.show() billboard_item_labels_visible = True # GUI Initialization sh = QtGui.QShortcut(QtGui.QKeySequence("+"), window, speed_up) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("-"), window, speed_down) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence(" "), window, pause) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("R"), window, reset) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("E"), window, go_to_end) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("Escape"), window, close_all) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("1"), window, toggle_grid_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("2"), window, toggle_base_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("3"), window, toggle_color_bars_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("4"), window, toggle_items_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("5"), window, toggle_path_line_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("6"), window, toggle_reconstruction_item_lines_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) sh = QtGui.QShortcut(QtGui.QKeySequence("7"), window, toggle_billboard_item_labels_visible) sh.setContext(QtCore.Qt.ApplicationShortcut) #################################################################################################################### # Animation Loop #################################################################################################################### timer = QtCore.QTimer() # noinspection PyUnresolvedReferences timer.timeout.connect(update) timer.start(1) #################################################################################################################### # PyQtGraph Initialization #################################################################################################################### if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): # noinspection PyArgumentList QtGui.QApplication.instance().exec_()
def make_freeslice(): #_Parameters________________________________________________________________ DATA_PATH = pkg_resources.resource_filename('data_slicer', 'data/') datafile = DATA_PATH + 'pit.p' ## Visual gloption = 'translucent' cmap = 'ocean' #_GUI_setup_________________________________________________________________ # Set up the main window and set a central widget window = QtGui.QMainWindow() window.resize(800, 800) central_widget = QtGui.QWidget() window.setCentralWidget(central_widget) # Create a layout layout = QtGui.QGridLayout() central_widget.setLayout(layout) # Add the selector view selector = ImagePlot() #selector = gl.GLViewWidget() layout.addWidget(selector, 1, 0, 1, 1) # Set up the main 3D view widget main = gl.GLViewWidget() layout.addWidget(main, 0, 0, 1, 1) # Somehow this is needed for both widets to be visible layout.setRowStretch(0, 1) layout.setRowStretch(1, 1) #_Data_loading_and_presenting_______________________________________________ # Load data with open(datafile, 'rb') as f: data = pickle.load(f) nx, ny, nz = data.shape x0, y0, z0 = 0, 0, 0 x0, y0, z0 = [int(2 * n / 5) for n in [nx, ny, nz]] # Create Textures levels = [data.min(), data.max()] cmap = load_cmap(cmap) lut = cmap.getLookupTable() cuts = [data[x0], data[:, y0], data[:, :, z0]] textures = [pg.makeRGBA(d, levels=levels, lut=lut)[0] for d in cuts] planes = [ gl.GLImageItem(texture, glOptions=gloption) for texture in textures ] ## Apply transformations to get lanes where they need to go xscale, yscale, zscale = 1 / nx, 1 / ny, 1 / nz # xy plane xy = planes[2] xy.scale(xscale, yscale, 1) xy.translate(-1 / 2, -1 / 2, -1 / 2 + z0 * zscale) main.addItem(xy) #_Selector__________________________________________________________________ # Set an image in the selector plot selector.set_image(cuts[2], lut=lut) cutline = Cutline(selector) cutline.initialize() # A plane representing the cutline cut, coords = cutline.get_array_region(data, selector.image_item, returnMappedCoords=True) cut_texture = pg.makeRGBA(cut, levels=levels, lut=lut)[0] cutplane = gl.GLImageItem(cut_texture, glOptions=gloption) # Scale and move it to origin in upright position # Upon initialization, this is like an xz plane cutplane.scale(xscale, zscale, 1) cutplane.rotate(90, 1, 0, 0) cutplane.translate(-1 / 2, 0, -1 / 2) transform0 = cutplane.transform() main.addItem(cutplane) # Conversion from ROI coordinates to Scene coordinates roi_coords = cutline.roi.getLocalHandlePositions() # also usefule for later original_roi_x0 = roi_coords[0][1].x() original_roi_x1 = roi_coords[1][1].x() # length in ROI coordinates length_in_roi = np.abs(original_roi_x1 - original_roi_x0) # length in data coordinates length_in_data = np.abs(coords[0, 0] - coords[0, -1]) # conversion in units of "roi/data" roi_data_conversion = length_in_roi / length_in_data # distance from left handle to M in data coords distance_p0_m = length_in_data / 2 print('Distance: ', distance_p0_m) def update_texture(): print('==') print('LocalHandles: ', cutline.roi.getLocalHandlePositions()) print('Scene: ', cutline.roi.getSceneHandlePositions()) print('++') transform = cutline.roi.getArraySlice(data, selector.image_item)[1] cut, coords = cutline.get_array_region(data, selector.image_item, returnMappedCoords=True) texture = pg.makeRGBA(cut, levels=levels, lut=lut)[0] cutplane.setData(texture) ## Find the original center of mass (if no length changes would have been applied) # The current handle positions in data coordinates are in p0 and p1 p0 = coords[[0, 1], [0, 0]] p1 = coords[[0, 1], [-1, -1]] # Find how much they have been stretched or compressed with respect to # the original handles new_roi_coords = cutline.roi.getLocalHandlePositions() delta0 = (original_roi_x0 - new_roi_coords[0][1].x()) / roi_data_conversion # Construct a unit vector pointing from P0 to P1 diff = p1 - p0 e_pp = diff / np.sqrt(diff.dot(diff)) print('p0: ', p0) print('p1: ', p1) print('diff', diff) print('e_pp: ', e_pp) # Now the original midpoint is at p0 + e_pp*(distance_p0_m+delta0) print('delta0: ', delta0) M = p0 tx, ty = M[0], M[1] print('tx, ty: {}, {}'.format(tx, ty)) tx *= xscale ty *= yscale print('tx, ty: {}, {}'.format(tx, ty)) # Rotate around origin try: alpha = np.arctan((p1[1] - p0[1]) / (p1[0] - p0[0])) except ZeroDivisionError: alpha = np.sign(p1[1] - p0[1]) * np.pi / 2 # Correct for special cases if p1[0] < p0[0]: alpha -= np.sign(p1[1] - p0[1]) * np.pi alpha_deg = alpha * 180 / np.pi print('alpha_deg: {}'.format(alpha_deg)) nt = QtGui.QMatrix4x4() nt.translate(tx - 1 / 2, ty - 1 / 2, -1 / 2) nt.scale(xscale, yscale, 1) nt.rotate(alpha_deg, 0, 0, 1) nt.rotate(90, 1, 0, 0) nt.scale(1, zscale, 1) cutplane.setTransform(nt) cutline.sig_region_changed.connect(update_texture) # Draw a coordinate system axis = gl.GLAxisItem() main.addItem(axis) return window