def update(): global drawmod, v1, LUT # diffusion cml.iterate() # calculate various statistics used for control and influencing musical parameters #stats.update(cml.matrix,cml.iter) if (cml.iter % drawmod==0): # if an image is big, don't do the scaling but rather use it direct. Could we somtoth #llshow=cml.matrix*128 if cml.iter>1: w.removeItem(v1) ## slice out three planes, convert to RGBA for OpenGL texture #levels = (-0.08, 0.08) llshow=zoom(((cml.matrix)+1)*128, 4, order=4) tex1 = pg.makeRGBA(llshow,lut=LUT)[0] # yz plane ## Create image items from textures, add to view v1 = gl.GLImageItem(tex1) v1.translate(-llshow.shape[0]/2, -llshow.shape[1]/2, 0) #v1.rotate(90, 0,0,1) #v1.rotate(-90, 0,1,0) w.addItem(v1) ax = gl.GLAxisItem() w.addItem(ax)
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 _image_plane(self, direction, index=None): """Create an image plane Item from the center plane in the given direction for the given SimpleITK Image.""" if index is None: shape = self.image_content.shape if direction == 'x': index = shape[0] / 2 elif direction == 'y': index = shape[1] / 2 elif direction == 'z': index = shape[2] / 2 if direction == 'x': plane = self.image_content[index, :, :] plane = plane.transpose() elif direction == 'y': plane = self.image_content[:, index, :] else: plane = self.image_content[:, :, index] texture = pg.makeRGBA(plane)[0] image_item = gl.GLImageItem(texture) spacing = self.input_image.GetSpacing() if direction == 'x': image_item.translate(0, 0, spacing[2] * index) elif direction == 'y': image_item.rotate(-90, 0, 1, 0) image_item.rotate(-90, 0, 0, 1) image_item.translate(0, spacing[1] * index, 0) else: image_item.rotate(-90, 0, 1, 0) image_item.translate(spacing[0] * index, 0, 0) return image_item
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)
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 updateV2(): global imv3, img3, img3RGBA, vLine2, vLine1 vLine1.setValue(vLine2.value()) img3 = data[vLine2.value(),:,:] img3RGBA = pg.makeRGBA(img3,levels=[np.amin(img3),np.amax(img3)])[0] if maskCol is not None: maskSlice = maskCol[vLine2.value(),:,:,:] img3RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img3RGBA[:,:,0:3] img3RGBA[:,:,3] = 255; imv3.setImage(img3RGBA.astype(int))
def updateV3(): global imv2, img2, img2RGBA, vLine3, hLine1 hLine1.setValue(vLine3.value()) img2 = data[:,vLine3.value(),:] img2RGBA = pg.makeRGBA(img2,levels=[np.amin(img2),np.amax(img2)])[0] if maskCol is not None: maskSlice = maskCol[:,vLine3.value(),:,:] img2RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img2RGBA[:,:,0:3] img2RGBA[:,:,3] = 255 imv2.setImage(img2RGBA.astype(int))
def updateH3(): global imv1, img1, img1RGBA, hLine3, hLine2 hLine2.setValue(hLine3.value()) img1 = data[:,:,hLine3.value()] img1RGBA = pg.makeRGBA(img1,levels=[np.amin(img1),np.amax(img1)])[0] if maskCol is not None: maskSlice = maskCol[:,:,hLine3.value(),:] img1RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img1RGBA[:,:,0:3] img1RGBA[:,:,3] imv1.setImage(img1RGBA.astype(int))
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 updateV1(): #updates image views that get affected by dragging in imv1 in vertical dimension global imv3, img3, img3RGBA, vLine1, vLine2 vLine2.setValue(vLine1.value()) img3 = data[vLine1.value(),:,:] img3RGBA = pg.makeRGBA(img3,levels=[np.amin(img3),np.amax(img3)])[0] if maskCol is not None: maskSlice = maskCol[vLine1.value(),:,:,:] img3RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img3RGBA[:,:,0:3] img3RGBA[:,:,3] = 255 imv3.setImage(img3RGBA.astype(int))
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 updateH1(): #updates image views that get affected by dragging in imv1 in horizontal #dimension global img2, img2RGBA, imv2, hLine1, vLine3 vLine3.setValue(hLine1.value()) img2 = data[:,hLine1.value(),:] img2RGBA = pg.makeRGBA(img2,levels=[np.amin(img2),np.amax(img2)])[0] if maskCol is not None: maskSlice = maskCol[:,hLine1.value(),:,:] img2RGBA[:,:,0:3] = maskSlice[:,:,0:3].astype(float)/255*img2RGBA[:,:,0:3] img2RGBA[:,:,3] = 255 imv2.setImage(img2RGBA.astype(int))
def gradientChanged(): global volume, volumeItem, gradientEditor, levels indices = np.nonzero(volume == 0) listTicks = gradientEditor.listTicks() listTicks[0][0].color.setAlpha(0) for tick in listTicks[1:]: tick[0].color.setAlpha(30) lut = gradientEditor.getLookupTable(255) volumeColors = np.asarray([ makeRGBA(data=slice, lut=lut, levels=levels)[0] for slice in volume ]) # volumeColors[indices, 3] = 0 volumeItem.setData(volumeColors)
def showData(self, slPos): "Loads the data into a displaying object." temp = slPos - (self.cWSize/2) if temp < 0: pos = 0 else: if (temp%self.cWStep <= (self.cWStep/2)): pos = temp / self.cWStep else: pos = (temp / self.cWStep) + 1 #Create the gray scale image. matRGB = pg.makeRGBA(self.matData[:,:,pos], levels=[np.amin(self.matData[:,:,pos]), np.amax(self.matData[:,:,pos])])[0] if self.ok: #Colours the gray scale image with 2 colours. matRGBCol = np.zeros(matRGB.shape, dtype=matRGB.dtype) if self.r3 is None: matRGBCol[:,:,0] = (matRGB[:,:,0]/255.0)*self.r1 + (1 - (matRGB[:,:,0]/255.0))*self.r2 matRGBCol[:,:,1] = (matRGB[:,:,1]/255.0)*self.g1 + (1 - (matRGB[:,:,1]/255.0))*self.g2 matRGBCol[:,:,2] = (matRGB[:,:,2]/255.0)*self.b1 + (1 - (matRGB[:,:,2]/255.0))*self.b2 matRGBCol[:,:,3] = 255 else: #Or with 3 colours. a = ((matRGB[:,:,0]/128)*(matRGB[:,:,0]/255.0))+(abs(matRGB[:,:,0].astype(int)/128 - 1)*(matRGB[:,:,0]/128.0)) b = ((matRGB[:,:,0]/128)*self.r3)+(abs(matRGB[:,:,0].astype(int)/128 - 1)*self.r2) c = 1 - (((matRGB[:,:,0]/128)*(matRGB[:,:,0]/255.0))+(abs(matRGB[:,:,0].astype(int)/128 - 1)*(matRGB[:,:,0]/128.0))) d = ((matRGB[:,:,0]/128)*self.r2)+(abs(matRGB[:,:,0].astype(int)/128 - 1)*self.r1) matRGBCol[:,:,0] = (a * b) + (c * d) a = ((matRGB[:,:,1]/128)*(matRGB[:,:,1]/255.0))+(abs(matRGB[:,:,1].astype(int)/128 - 1)*(matRGB[:,:,1]/128.0)) b = ((matRGB[:,:,1]/128)*self.g3)+(abs(matRGB[:,:,1].astype(int)/128 - 1)*self.g2) c = 1 - (((matRGB[:,:,1]/128)*(matRGB[:,:,1]/255.0))+(abs(matRGB[:,:,1].astype(int)/128 - 1)*(matRGB[:,:,1]/128.0))) d = ((matRGB[:,:,1]/128)*self.g2)+(abs(matRGB[:,:,1].astype(int)/128 - 1)*self.g1) matRGBCol[:,:,1] = (a * b) + (c * d) a = ((matRGB[:,:,2]/128)*(matRGB[:,:,2]/255.0))+(abs(matRGB[:,:,2].astype(int)/128 - 1)*(matRGB[:,:,2]/128.0)) b = ((matRGB[:,:,2]/128)*self.b3)+(abs(matRGB[:,:,2].astype(int)/128 - 1)*self.b2) c = 1 - (((matRGB[:,:,2]/128)*(matRGB[:,:,2]/255.0))+(abs(matRGB[:,:,2].astype(int)/128 - 1)*(matRGB[:,:,2]/128.0))) d = ((matRGB[:,:,2]/128)*self.b2)+(abs(matRGB[:,:,2].astype(int)/128 - 1)*self.b1) matRGBCol[:,:,2] = (a * b) + (c * d) matRGBCol[:,:,3] = 255 self.img.setImage(matRGBCol) else: self.img.setImage(matRGB)
def _image_plane(self, direction, index=None): """Create an image plane Item from the center plane in the given direction for the given SimpleITK Image.""" if index is None: shape = self.image_content.shape if direction == 0: index = shape[2] / 2 elif direction == 1: index = shape[1] / 2 elif direction == 2: index = shape[0] / 2 if direction == 0: plane = self.image_content[:, :, index] elif direction == 1: plane = self.image_content[:, index, :] else: plane = self.image_content[index, :, :] plane = plane.transpose() texture = pg.makeRGBA(plane)[0] image_item = gl.GLImageItem(texture) spacing = self.input_image.GetSpacing() origin = self.input_image.GetOrigin() if direction == 0: image_item.scale(spacing[2], spacing[1], 1) image_item.rotate(-90, 0, 1, 0) image_item.translate(origin[0] + spacing[2] * index, origin[1], origin[2]) elif direction == 1: image_item.scale(spacing[2], spacing[0], 1) image_item.rotate(-90, 0, 1, 0) image_item.rotate(-90, 0, 0, 1) image_item.translate(origin[0], origin[1] + spacing[1] * index, origin[2]) else: image_item.scale(spacing[0], spacing[1], 1) image_item.translate(origin[0], origin[1], origin[2] + spacing[0] * index) return image_item
def showData(self, slPos): "Loads the data into a displaying object." temp = slPos - (self.cWSize / 2) if temp < 0: pos = 0 else: if (temp % self.cWStep <= (self.cWStep / 2)): pos = temp / self.cWStep else: pos = (temp / self.cWStep) + 1 #Create the gray scale image. matRGB = pg.makeRGBA(self.matData[:, :, pos], levels=[ np.amin(self.matData[:, :, pos]), np.amax(self.matData[:, :, pos]) ])[0] if self.ok: #Colours the gray scale image with 2 colours. matRGBCol = np.zeros(matRGB.shape, dtype=matRGB.dtype) if self.r3 is None: matRGBCol[:, :, 0] = (matRGB[:, :, 0] / 255.0) * self.r1 + ( 1 - (matRGB[:, :, 0] / 255.0)) * self.r2 matRGBCol[:, :, 1] = (matRGB[:, :, 1] / 255.0) * self.g1 + ( 1 - (matRGB[:, :, 1] / 255.0)) * self.g2 matRGBCol[:, :, 2] = (matRGB[:, :, 2] / 255.0) * self.b1 + ( 1 - (matRGB[:, :, 2] / 255.0)) * self.b2 matRGBCol[:, :, 3] = 255 else: #Or with 3 colours. a = ((matRGB[:, :, 0] / 128) * (matRGB[:, :, 0] / 255.0)) + ( abs(matRGB[:, :, 0].astype(int) / 128 - 1) * (matRGB[:, :, 0] / 128.0)) b = ((matRGB[:, :, 0] / 128) * self.r3) + ( abs(matRGB[:, :, 0].astype(int) / 128 - 1) * self.r2) c = 1 - (((matRGB[:, :, 0] / 128) * (matRGB[:, :, 0] / 255.0)) + (abs(matRGB[:, :, 0].astype(int) / 128 - 1) * (matRGB[:, :, 0] / 128.0))) d = ((matRGB[:, :, 0] / 128) * self.r2) + ( abs(matRGB[:, :, 0].astype(int) / 128 - 1) * self.r1) matRGBCol[:, :, 0] = (a * b) + (c * d) a = ((matRGB[:, :, 1] / 128) * (matRGB[:, :, 1] / 255.0)) + ( abs(matRGB[:, :, 1].astype(int) / 128 - 1) * (matRGB[:, :, 1] / 128.0)) b = ((matRGB[:, :, 1] / 128) * self.g3) + ( abs(matRGB[:, :, 1].astype(int) / 128 - 1) * self.g2) c = 1 - (((matRGB[:, :, 1] / 128) * (matRGB[:, :, 1] / 255.0)) + (abs(matRGB[:, :, 1].astype(int) / 128 - 1) * (matRGB[:, :, 1] / 128.0))) d = ((matRGB[:, :, 1] / 128) * self.g2) + ( abs(matRGB[:, :, 1].astype(int) / 128 - 1) * self.g1) matRGBCol[:, :, 1] = (a * b) + (c * d) a = ((matRGB[:, :, 2] / 128) * (matRGB[:, :, 2] / 255.0)) + ( abs(matRGB[:, :, 2].astype(int) / 128 - 1) * (matRGB[:, :, 2] / 128.0)) b = ((matRGB[:, :, 2] / 128) * self.b3) + ( abs(matRGB[:, :, 2].astype(int) / 128 - 1) * self.b2) c = 1 - (((matRGB[:, :, 2] / 128) * (matRGB[:, :, 2] / 255.0)) + (abs(matRGB[:, :, 2].astype(int) / 128 - 1) * (matRGB[:, :, 2] / 128.0))) d = ((matRGB[:, :, 2] / 128) * self.b2) + ( abs(matRGB[:, :, 2].astype(int) / 128 - 1) * self.b1) matRGBCol[:, :, 2] = (a * b) + (c * d) matRGBCol[:, :, 3] = 255 self.img.setImage(matRGBCol) else: self.img.setImage(matRGB)
def plot_image(self): self.replot() tex3 = pg.makeRGBA(self.dst_img, levels=[0, 255])[0] # xy plane v3 = gl.GLImageItem(tex3) self.view_widget.addItem(v3)
import numpy as np app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['distance'] = 200 w.show() w.setWindowTitle('pyqtgraph example: GLImageItem') ## 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[int(shape[0] / 2)], levels=levels)[0] # yz plane tex2 = pg.makeRGBA(data[:, int(shape[1] / 2)], levels=levels)[0] # xz plane tex3 = pg.makeRGBA(data[:, :, int(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)
def showPowSpec(self): """Function that shows the plot and its time-frequency spectrum. The user is asked for the colours that should be used in the spectrum. If Cancel is clicked, the spectrum is displayed in gray scale.""" #Some more initialisation. self.setWindowTitle("vizEEG - Time-frequency Spectrum display") self.img = pg.ImageView() self.col1.addWidget(self.img) self.imgSlider = pg.InfiniteLine(pos=0, bounds=[0, self.PSData.shape[0]], movable=True, pen='y') self.img.addItem(self.imgSlider) self.plotSlider.sigDragged.connect(self.imgSliderFunc) self.imgSlider.sigDragged.connect(self.plotSliderFunc) self.r3 = None colours, self.ok = self.colourInput( "Choose a colouring for time-frequency spectum images or enter a different one in format RRR,GGG,BBB.\n Please, separate colours (2 or 3) with space.\n If Cancel is clicked spectrum will be displayed in gray scale." ) msgBox = QtGui.QMessageBox() msgBox.setWindowTitle("vizEEG: Colour Error") if self.ok: #If the input was without an error, parse the user input. parsed = re.findall("\d{0,3},\d{0,3},\d{0,3}", colours) if len(parsed) < 2 or len(parsed) > 3: self.ok = False msgBox.setText( "Colours input in an incorrect format.\nPlease, input 2 or 3 colours in format RRR,GGG,BBB separated by space, where RRR or GGG or BBB are numbers in range 0-255." ) msgBox.exec_() else: self.r1 = int(parsed[0].split(',')[0]) self.g1 = int(parsed[0].split(',')[1]) self.b1 = int(parsed[0].split(',')[2]) self.r2 = int(parsed[1].split(',')[0]) self.g2 = int(parsed[1].split(',')[1]) self.b2 = int(parsed[1].split(',')[2]) if len(parsed) == 3: self.r3 = int(parsed[2].split(',')[0]) self.g3 = int(parsed[2].split(',')[1]) self.b3 = int(parsed[2].split(',')[2]) #Check if the input colours are in a proper format. okRange = range(256) areColsOk = self.r1 in okRange and self.r2 in okRange and self.g1 in okRange and self.g2 in okRange and self.b1 in okRange and self.b2 in okRange if len(parsed) == 3: areColsOk = areColsOk and self.r3 in okRange and self.g3 in okRange and self.b3 in okRange if not areColsOk: self.ok = False msgBox.setText( "Colours are out of RGB range. \nPlease, input 2 or 3 colours in format RRR,GGG,BBB separated by space, where RRR or GGG or BBB are numbers in range 0-255." ) msgBox.exec_() #Create the gray scale image. #makeRGBA outputs a tuple (imgArray,isThereAlphaChannel?) TFRGBImg = pg.makeRGBA(self.PSData[:, :, self.data[2][0]], levels=[ np.amin(self.PSData[:, :, self.data[2][0]]), np.amax(self.PSData[:, :, self.data[2][0]]) ])[0] if self.ok: #Colour the image with 2 colours. TFRGBCol = np.zeros(TFRGBImg.shape, dtype=TFRGBImg.dtype) if self.r3 is None: TFRGBCol[:, :, 0] = (TFRGBImg[:, :, 0] / 255.0) * self.r1 + ( 1 - (TFRGBImg[:, :, 0].astype(int) / 255.0)) * self.r2 TFRGBCol[:, :, 1] = (TFRGBImg[:, :, 1] / 255.0) * self.g1 + ( 1 - (TFRGBImg[:, :, 1].astype(int) / 255.0)) * self.g2 TFRGBCol[:, :, 2] = (TFRGBImg[:, :, 2] / 255.0) * self.b1 + ( 1 - (TFRGBImg[:, :, 2].astype(int) / 255.0)) * self.b2 TFRGBCol[:, :, 3] = 255 else: #Colour the image with 3 colours. a = ((TFRGBImg[:, :, 0] / 128) * (TFRGBImg[:, :, 0] / 255.0)) + ( abs(TFRGBImg[:, :, 0].astype(int) / 128 - 1) * (TFRGBImg[:, :, 0] / 128.0)) b = ((TFRGBImg[:, :, 0] / 128) * self.r3) + ( abs(TFRGBImg[:, :, 0].astype(int) / 128 - 1) * self.r2) c = 1 - (((TFRGBImg[:, :, 0] / 128) * (TFRGBImg[:, :, 0] / 255.0)) + (abs(TFRGBImg[:, :, 0].astype(int) / 128 - 1) * (TFRGBImg[:, :, 0] / 128.0))) d = ((TFRGBImg[:, :, 0] / 128) * self.r2) + ( abs(TFRGBImg[:, :, 0].astype(int) / 128 - 1) * self.r1) TFRGBCol[:, :, 0] = (a * b) + (c * d) a = ((TFRGBImg[:, :, 1] / 128) * (TFRGBImg[:, :, 1] / 255.0)) + ( abs(TFRGBImg[:, :, 1].astype(int) / 128 - 1) * (TFRGBImg[:, :, 1] / 128.0)) b = ((TFRGBImg[:, :, 1] / 128) * self.g3) + ( abs(TFRGBImg[:, :, 1].astype(int) / 128 - 1) * self.g2) c = 1 - (((TFRGBImg[:, :, 1] / 128) * (TFRGBImg[:, :, 1] / 255.0)) + (abs(TFRGBImg[:, :, 1].astype(int) / 128 - 1) * (TFRGBImg[:, :, 1] / 128.0))) d = ((TFRGBImg[:, :, 1] / 128) * self.g2) + ( abs(TFRGBImg[:, :, 1].astype(int) / 128 - 1) * self.g1) TFRGBCol[:, :, 1] = (a * b) + (c * d) a = ((TFRGBImg[:, :, 2] / 128) * (TFRGBImg[:, :, 2] / 255.0)) + ( abs(TFRGBImg[:, :, 2].astype(int) / 128 - 1) * (TFRGBImg[:, :, 2] / 128.0)) b = ((TFRGBImg[:, :, 2] / 128) * self.b3) + ( abs(TFRGBImg[:, :, 2].astype(int) / 128 - 1) * self.b2) c = 1 - (((TFRGBImg[:, :, 2] / 128) * (TFRGBImg[:, :, 2] / 255.0)) + (abs(TFRGBImg[:, :, 2].astype(int) / 128 - 1) * (TFRGBImg[:, :, 2] / 128.0))) d = ((TFRGBImg[:, :, 2] / 128) * self.b2) + ( abs(TFRGBImg[:, :, 2].astype(int) / 128 - 1) * self.b1) TFRGBCol[:, :, 2] = (a * b) + (c * d) TFRGBCol[:, :, 3] = 255 self.img.setImage(TFRGBCol) else: self.img.setImage(TFRGBImg)
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, returnCoords=True) texture = pg.makeRGBA(cut, levels=levels, lut=lut)[0] # xy.setTexture(texture) 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 # bounds = cutline.roi.parentBounds() # print(bounds) # p0 = bounds.bottomLeft() # p1 = bounds.topRight() 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 # delta1 = original_roi_x1 - new_roi_coords[1][1].x() # Construct a unit vector pointing from P0 to P1 diff = p1 - p0 # e_pp = diff / np.sqrt(diff.x()**2 + diff.y()**2) 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 + e_pp*(distance_p0_m + delta0) # Somehow, the way the new plane is calculated, delta0 must not be added # M = p0 + e_pp*distance_p0_m M = p0 # tx, ty = M.x(), M.y() tx, ty = M[0], M[1] print('tx, ty: {}, {}'.format(tx, ty)) # tx, ty = [0.5*(p1.x() + p0.x()), 0.5*(p1.y() + p0.y())] tx *= xscale ty *= yscale print('tx, ty: {}, {}'.format(tx, ty)) # Rotate around origin try: # alpha = np.arctan((p1.y()-p0.y()) / (p1.x()-p0.x())) 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)) # Get the right scaling # beta = alpha%(np.pi/2) # print('beta (deg): ', 180/np.pi*beta) # critical_angle = np.arctan(ny/nx) # if beta < critical_angle : # scaling = nx * np.cos(beta) # else : # scaling = ny * np.sin(beta) # print('scaling: ', scaling) # Send to origin and apply rotation and translation # new_transform = QtGui.QMatrix4x4() # new_transform.translate(tx-1/2, ty-1/2, 0) # new_transform.rotate(alpha, 0, 0, 1) # new_transform *= transform0 # cutplane.setTransform(new_transform) # cutplane.setTransform(QtGui.QMatrix4x4()) # cutplane.scale(xscale, zscale, 1) # cutplane.scale(1/scaling, zscale, 1) # cutplane.rotate(90, 1, 0, 0) # cutplane.rotate(alpha_deg, 0, 0, 1) # cutplane.translate(tx-1/2, ty-1/2, -1/2) 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)
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_()
data.dtype, theta) #transform = data data = transform[:, 0, :, :] #tShape = tData.shape #data = data[:,0,:,:] shape = data.shape ## slice out three planes, convert to RGBA for OpenGL texture levels = (0, 1000) slice1 = int(shape[0] / 2) slice2 = int(shape[1] / 2) slice3 = int(shape[2] / 2) tex1 = pg.makeRGBA(data[slice1], levels=levels)[0] # yz plane tex2 = pg.makeRGBA(data[:, slice2], levels=levels)[0] # xz plane tex3 = pg.makeRGBA(data[:, :, slice3], levels=levels)[0] # xy plane ## Create three image items from textures, add to view v1 = gl.GLImageItem(tex1) v1.translate(-slice2, -slice3, 0) v1.rotate(90, 0, 0, 1) v1.rotate(-90, 0, 1, 0) w.addItem(v1) v2 = gl.GLImageItem(tex2) v2.translate(-slice1, -slice3, 0) v2.rotate(-90, 1, 0, 0) w.addItem(v2)
# Load data with open(datafile, 'rb') as f: 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)
def __init__(self): super(Mainwindow, self).__init__() self.exitAction = QtGui.QAction(QtGui.QIcon('close.png'), 'Exit', self) self.exitAction.setShortcut('Ctrl+Q') self.exitAction.setStatusTip('Exit application') self.exitAction.triggered.connect(self.close) self.statusBar() self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu('&File') self.exitMenu = self.menubar.addMenu('&Exit') #fileMenu.addAction(exitAction1) #toolbar = self.addToolBar('Exit') #toolbar.addAction(exitAction) self.setGeometry(100, 100, 1000, 500) self.setWindowTitle('BCI System Nanjing University Li Meng') self.setWindowIcon(QtGui.QIcon('Icon_system.png')) #---Left Docker dockWidgetleft =QtGui.QDockWidget("Direction",self) dockWidgetleft.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea) self.Leftdocker = LeftDockerWidget() dockWidgetleft.setWidget(self.Leftdocker) self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dockWidgetleft) #---Right Docker dockWidgetright =QtGui.QDockWidget("Status",self) dockWidgetright.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea) self.Rightdocker = RightDockerWidget() dockWidgetright.setWidget(self.Rightdocker) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dockWidgetright) #---Top Docker dockWidgettop =QtGui.QDockWidget("Tool",self) dockWidgettop.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea) self.Topdocker = TopDockerWidget() dockWidgettop.setWidget(self.Topdocker) self.addDockWidget(QtCore.Qt.TopDockWidgetArea, dockWidgettop) w = gl.GLViewWidget() #w.resize(6,800) w.opts['distance'] = 200 w.setWindowTitle('pyqtgraph example: GLImageItem') ## 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 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) self.setCentralWidget(w); self.resize(1200,500)
import numpy as np import scipy.ndimage as ndi app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['distance'] = 200 w.show() ## create volume data set to slice three images from shape = (100,100,70) data = ndi.gaussian_filter(np.random.normal(size=shape), (4,4,4)) data += ndi.gaussian_filter(np.random.normal(size=shape), (15,15,15))*15 ## slice out three planes, convert to ARGB 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 ## 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)
data = pickle.load(f) # D = pickle.load(f) #data = np.rollaxis(D.data, 2) #data = np.rollaxis(data, 2, 1) 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() 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) # 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)
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_()
def showPowSpec(self): """Function that shows the plot and its time-frequency spectrum. The user is asked for the colours that should be used in the spectrum. If Cancel is clicked, the spectrum is displayed in gray scale.""" #Some more initialisation. self.setWindowTitle("vizEEG - Time-frequency Spectrum display") self.img = pg.ImageView() self.col1.addWidget(self.img) self.imgSlider = pg.InfiniteLine(pos=0, bounds=[0,self.PSData.shape[0]], movable=True, pen='y') self.img.addItem(self.imgSlider) self.plotSlider.sigDragged.connect(self.imgSliderFunc) self.imgSlider.sigDragged.connect(self.plotSliderFunc) self.r3 = None colours, self.ok = self.colourInput("Choose a colouring for time-frequency spectum images or enter a different one in format RRR,GGG,BBB.\n Please, separate colours (2 or 3) with space.\n If Cancel is clicked spectrum will be displayed in gray scale.") msgBox = QtGui.QMessageBox() msgBox.setWindowTitle("vizEEG: Colour Error") if self.ok: #If the input was without an error, parse the user input. parsed = re.findall("\d{0,3},\d{0,3},\d{0,3}", colours) if len(parsed) < 2 or len(parsed) > 3: self.ok = False msgBox.setText("Colours input in an incorrect format.\nPlease, input 2 or 3 colours in format RRR,GGG,BBB separated by space, where RRR or GGG or BBB are numbers in range 0-255.") msgBox.exec_() else: self.r1 = int(parsed[0].split(',')[0]) self.g1 = int(parsed[0].split(',')[1]) self.b1 = int(parsed[0].split(',')[2]) self.r2 = int(parsed[1].split(',')[0]) self.g2 = int(parsed[1].split(',')[1]) self.b2 = int(parsed[1].split(',')[2]) if len(parsed) == 3: self.r3 = int(parsed[2].split(',')[0]) self.g3 = int(parsed[2].split(',')[1]) self.b3 = int(parsed[2].split(',')[2]) #Check if the input colours are in a proper format. okRange = range(256) areColsOk = self.r1 in okRange and self.r2 in okRange and self.g1 in okRange and self.g2 in okRange and self.b1 in okRange and self.b2 in okRange if len(parsed) == 3: areColsOk = areColsOk and self.r3 in okRange and self.g3 in okRange and self.b3 in okRange if not areColsOk: self.ok = False msgBox.setText("Colours are out of RGB range. \nPlease, input 2 or 3 colours in format RRR,GGG,BBB separated by space, where RRR or GGG or BBB are numbers in range 0-255.") msgBox.exec_() #Create the gray scale image. #makeRGBA outputs a tuple (imgArray,isThereAlphaChannel?) TFRGBImg = pg.makeRGBA(self.PSData[:,:,self.data[2][0]], levels=[np.amin(self.PSData[:,:,self.data[2][0]]), np.amax(self.PSData[:,:,self.data[2][0]])])[0] if self.ok: #Colour the image with 2 colours. TFRGBCol = np.zeros(TFRGBImg.shape, dtype=TFRGBImg.dtype) if self.r3 is None: TFRGBCol[:,:,0] = (TFRGBImg[:,:,0]/255.0)*self.r1 + (1 - (TFRGBImg[:,:,0].astype(int)/255.0))*self.r2 TFRGBCol[:,:,1] = (TFRGBImg[:,:,1]/255.0)*self.g1 + (1 - (TFRGBImg[:,:,1].astype(int)/255.0))*self.g2 TFRGBCol[:,:,2] = (TFRGBImg[:,:,2]/255.0)*self.b1 + (1 - (TFRGBImg[:,:,2].astype(int)/255.0))*self.b2 TFRGBCol[:,:,3] = 255 else: #Colour the image with 3 colours. a = ((TFRGBImg[:,:,0]/128)*(TFRGBImg[:,:,0]/255.0))+(abs(TFRGBImg[:,:,0].astype(int)/128 - 1)*(TFRGBImg[:,:,0]/128.0)) b = ((TFRGBImg[:,:,0]/128)*self.r3)+(abs(TFRGBImg[:,:,0].astype(int)/128 - 1)*self.r2) c = 1 - (((TFRGBImg[:,:,0]/128)*(TFRGBImg[:,:,0]/255.0))+(abs(TFRGBImg[:,:,0].astype(int)/128 - 1)*(TFRGBImg[:,:,0]/128.0))) d = ((TFRGBImg[:,:,0]/128)*self.r2)+(abs(TFRGBImg[:,:,0].astype(int)/128 - 1)*self.r1) TFRGBCol[:,:,0] = (a * b) + (c * d) a = ((TFRGBImg[:,:,1]/128)*(TFRGBImg[:,:,1]/255.0))+(abs(TFRGBImg[:,:,1].astype(int)/128 - 1)*(TFRGBImg[:,:,1]/128.0)) b = ((TFRGBImg[:,:,1]/128)*self.g3)+(abs(TFRGBImg[:,:,1].astype(int)/128 - 1)*self.g2) c = 1 - (((TFRGBImg[:,:,1]/128)*(TFRGBImg[:,:,1]/255.0))+(abs(TFRGBImg[:,:,1].astype(int)/128 - 1)*(TFRGBImg[:,:,1]/128.0))) d = ((TFRGBImg[:,:,1]/128)*self.g2)+(abs(TFRGBImg[:,:,1].astype(int)/128 - 1)*self.g1) TFRGBCol[:,:,1] = (a * b) + (c * d) a = ((TFRGBImg[:,:,2]/128)*(TFRGBImg[:,:,2]/255.0))+(abs(TFRGBImg[:,:,2].astype(int)/128 - 1)*(TFRGBImg[:,:,2]/128.0)) b = ((TFRGBImg[:,:,2]/128)*self.b3)+(abs(TFRGBImg[:,:,2].astype(int)/128 - 1)*self.b2) c = 1 - (((TFRGBImg[:,:,2]/128)*(TFRGBImg[:,:,2]/255.0))+(abs(TFRGBImg[:,:,2].astype(int)/128 - 1)*(TFRGBImg[:,:,2]/128.0))) d = ((TFRGBImg[:,:,2]/128)*self.b2)+(abs(TFRGBImg[:,:,2].astype(int)/128 - 1)*self.b1) TFRGBCol[:,:,2] = (a * b) + (c * d) TFRGBCol[:,:,3] = 255 self.img.setImage(TFRGBCol) else: self.img.setImage(TFRGBImg)
def make_texture(self, cut): """ Wrapper for :func:`makeRGBA <pyqtgraph.makeRGBA>`.""" return pg.makeRGBA(cut, levels=self.levels, lut=self.lut)[0]
time_length = 60 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):
import numpy as np app = pg.mkQApp("GLImageItem Example") w = gl.GLViewWidget() w.show() w.setWindowTitle('pyqtgraph example: GLImageItem') w.setCameraPosition(distance=200) ## 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)
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