def getSortedOrderArray(self): sortedOrder = vtkUnsignedCharArray() sortedOrder.SetName("layerIdx") sortedOrder.SetNumberOfTuples(self.stackSize) # Reset content for idx in range(self.stackSize): sortedOrder.SetValue(idx, 255) idx = 0 for pixel in self.pixels: x = idx % self.width y = idx / self.width flipYIdx = self.width * (self.height - y - 1) + x if "@" in pixel: idx += int(pixel[1:]) else: # Need to decode the order layerIdx = 0 for layer in pixel: sortedOrder.SetValue(flipYIdx + self.imageSize * layerIdx, self.encoding.index(layer)) layerIdx += 1 # Move to next pixel idx += 1 return sortedOrder
def getLookupTableForArrayName(self, name, numSamples=255): lutProxy = simple.GetColorTransferFunction(name) lut = lutProxy.GetClientSideObject() dataRange = lut.GetRange() delta = (dataRange[1] - dataRange[0]) / float(numSamples) colorArray = vtkUnsignedCharArray() colorArray.SetNumberOfComponents(3) colorArray.SetNumberOfTuples(numSamples) rgb = [0, 0, 0] for i in range(numSamples): lut.GetColor(dataRange[0] + float(i) * delta, rgb) r = int(round(rgb[0] * 255)) g = int(round(rgb[1] * 255)) b = int(round(rgb[2] * 255)) colorArray.SetTuple3(i, r, g, b) # Add the color array to an image data imgData = vtkImageData() imgData.SetDimensions(numSamples, 1, 1) aIdx = imgData.GetPointData().SetScalars(colorArray) # Use the vtk data encoder to base-64 encode the image as png, using no compression encoder = vtkDataEncoder() # two calls in a row crash on Windows - bald timing hack to avoid the crash. time.sleep(0.01) b64Str = encoder.EncodeAsBase64Jpg(imgData, 100) return { "image": "data:image/jpg;base64," + b64Str, "range": dataRange, "name": name, }
def writeLightArray(self, path, source): rep = simple.Show(source, self.view) rep.Representation = 'Surface' rep.DiffuseColor = [1, 1, 1] simple.ColorBy(rep, ('POINTS', None)) # Grab data tmpFileName = path + '__.png' self.view.LockBounds = 1 simple.SaveScreenshot(tmpFileName, self.view) self.view.LockBounds = 0 if self.canWrite: # Convert data self.reader.SetFileName(tmpFileName) self.reader.Update() rgbArray = self.reader.GetOutput().GetPointData().GetArray(0) arraySize = rgbArray.GetNumberOfTuples() rawArray = vtkUnsignedCharArray() rawArray.SetNumberOfTuples(arraySize) for idx in range(arraySize): light = rgbArray.GetTuple3(idx)[0] rawArray.SetTuple1(idx, light) with open(path, 'wb') as f: f.write(buffer(rawArray)) # Delete temporary file if self.cleanAfterMe: os.remove(tmpFileName) simple.Hide(source, self.view)
def getSortedOrderArray(self): sortedOrder = vtkUnsignedCharArray() sortedOrder.SetName('layerIdx'); sortedOrder.SetNumberOfTuples(self.stackSize) # Reset content for idx in range(self.stackSize): sortedOrder.SetValue(idx, 255) idx = 0 for pixel in self.pixels: x = (idx % self.width) y = (idx / self.width) flipYIdx = self.width * (self.height - y - 1) + x if '@' in pixel: idx += int(pixel[1:]) else: # Need to decode the order layerIdx = 0 for layer in pixel: sortedOrder.SetValue(flipYIdx + self.imageSize * layerIdx, self.encoding.index(layer)) layerIdx += 1 # Move to next pixel idx += 1 return sortedOrder
def writeLightArray(self, path, source): rep = simple.Show(source, self.view) rep.Representation = 'Surface' rep.DiffuseColor = [1,1,1] simple.ColorBy(rep, ('POINTS', None)) # Grab data tmpFileName = path + '__.png' self.view.LockBounds = 1 simple.SaveScreenshot(tmpFileName, self.view) self.view.LockBounds = 0 if self.canWrite: # Convert data self.reader.SetFileName(tmpFileName) self.reader.Update() rgbArray = self.reader.GetOutput().GetPointData().GetArray(0) arraySize = rgbArray.GetNumberOfTuples() rawArray = vtkUnsignedCharArray() rawArray.SetNumberOfTuples(arraySize) for idx in range(arraySize): light = rgbArray.GetTuple3(idx)[0] rawArray.SetTuple1(idx, light) with open(path, 'wb') as f: f.write(buffer(rawArray)) # Delete temporary file if self.cleanAfterMe: os.remove(tmpFileName) simple.Hide(source, self.view)
def pushSaturation(self, saturationFile): if os.path.exists(saturationFile): self.pfbReader.FileNames = [saturationFile] self.pfbReader.UpdatePipeline() imageData = self.pfbReader.GetClientSideObject().GetOutput( ).GetBlock(0) array = imageData.GetCellData().GetArray(0) size = array.GetNumberOfTuples() # Data convertion saturationArray = vtkUnsignedCharArray() saturationArray.SetNumberOfTuples(size) for i in range(size): value = array.GetValue(i) if value >= 1.0: saturationArray.SetValue(i, 255) elif value < 0.0: saturationArray.SetValue(i, 0) else: saturationArray.SetValue(i, int(value * 255)) print('push saturation: %s' % saturationFile) self.publish( 'parflow.sandtank.saturation', { 'time': self.lastProcessedTimestep, 'array': self.addAttachment( buffer(saturationArray).tobytes()) })
def pushIndicator(self): filePath = os.path.join(self.workdir, 'SandTank_Indicator.pfb') if not os.path.exists(filePath): print('no file for indicator') return None if self.pfbReader: self.pfbReader.FileNames = [filePath] else: self.pfbReader = simple.PFBreader(FileNames=[filePath], IsCLMFile='No') self.pfbReader.UpdatePipeline() imageData = self.pfbReader.GetClientSideObject().GetOutput().GetBlock( 0) imageSize = [v - 1 for v in imageData.GetDimensions()] array = imageData.GetCellData().GetArray(0) size = array.GetNumberOfTuples() indicatorDimensions = imageSize indicatorArray = vtkUnsignedCharArray() indicatorArray.SetNumberOfTuples(size) for i in range(size): indicatorArray.SetValue(i, int(array.GetValue(i))) self.publish( 'parflow.sandtank.indicator', { 'dimensions': indicatorDimensions, 'array': self.addAttachment(buffer(indicatorArray).tobytes()), }) # Schedule file processing... self.processNextFile()
def compute_tubes(trk, direction): """Compute and assign colors to a vtkTube for visualization of a single tract :param trk: nx3 array of doubles (x, y, z) point coordinates composing the tract :type trk: numpy.ndarray :param direction: nx3 array of int (x, y, z) RGB colors in the range 0 - 255 :type direction: numpy.ndarray :return: a vtkTubeFilter instance :rtype: vtkTubeFilter """ numb_points = trk.shape[0] points = vtkPoints() lines = vtkCellArray() colors = vtkUnsignedCharArray() colors.SetNumberOfComponents(4) k = 0 lines.InsertNextCell(numb_points) for j in range(numb_points): points.InsertNextPoint(trk[j, :]) colors.InsertNextTuple(direction[j, :]) lines.InsertCellPoint(k) k += 1 trk_data = vtkPolyData() trk_data.SetPoints(points) trk_data.SetLines(lines) trk_data.GetPointData().SetScalars(colors) # make it a tube trk_tube = vtkTubeFilter() trk_tube.SetRadius(0.5) trk_tube.SetNumberOfSides(4) trk_tube.SetInputData(trk_data) trk_tube.Update() return trk_tube
def convert(self, directory): imagePaths = {} depthPaths = {} layerNames = [] for fileName in os.listdir(directory): if "_rgb" in fileName or "_depth" in fileName: fileId = fileName.split("_")[0][0] if "_rgb" in fileName: imagePaths[fileId] = os.path.join(directory, fileName) else: layerNames.append(fileId) depthPaths[fileId] = os.path.join(directory, fileName) layerNames.sort() if len(layerNames) == 0: return # Load data in Memory depthArrays = [] imageReader = vtkPNGReader() numberOfValues = self.width * self.height * len(layerNames) imageSize = self.width * self.height self.layers = len(layerNames) # Write all images as single memoryview opacity = vtkUnsignedCharArray() opacity.SetNumberOfComponents(1) opacity.SetNumberOfTuples(numberOfValues) intensity = vtkUnsignedCharArray() intensity.SetNumberOfComponents(1) intensity.SetNumberOfTuples(numberOfValues) for layer in range(self.layers): imageReader.SetFileName(imagePaths[layerNames[layer]]) imageReader.Update() rgbaArray = imageReader.GetOutput().GetPointData().GetArray(0) for idx in range(imageSize): intensity.SetValue((layer * imageSize) + idx, rgbaArray.GetValue(idx * 4)) opacity.SetValue((layer * imageSize) + idx, rgbaArray.GetValue(idx * 4 + 3)) with open(depthPaths[layerNames[layer]], "rb") as depthFile: depthArrays.append(depthFile.read()) # Apply pixel sorting destOrder = vtkUnsignedCharArray() destOrder.SetNumberOfComponents(1) destOrder.SetNumberOfTuples(numberOfValues) opacityOrder = vtkUnsignedCharArray() opacityOrder.SetNumberOfComponents(1) opacityOrder.SetNumberOfTuples(numberOfValues) intensityOrder = vtkUnsignedCharArray() intensityOrder.SetNumberOfComponents(1) intensityOrder.SetNumberOfTuples(numberOfValues) for pixelIdx in range(imageSize): depthStack = [] for depthArray in depthArrays: depthStack.append((depthArray[pixelIdx], len(depthStack))) depthStack.sort(key=lambda tup: tup[0]) for destLayerIdx in range(len(depthStack)): sourceLayerIdx = depthStack[destLayerIdx][1] # Copy Idx destOrder.SetValue((imageSize * destLayerIdx) + pixelIdx, sourceLayerIdx) opacityOrder.SetValue( (imageSize * destLayerIdx) + pixelIdx, opacity.GetValue((imageSize * sourceLayerIdx) + pixelIdx), ) intensityOrder.SetValue( (imageSize * destLayerIdx) + pixelIdx, intensity.GetValue((imageSize * sourceLayerIdx) + pixelIdx), ) with open(os.path.join(directory, "alpha.uint8"), "wb") as f: f.write(memoryview(opacityOrder)) with open(os.path.join(directory, "intensity.uint8"), "wb") as f: f.write(memoryview(intensityOrder)) with open(os.path.join(directory, "order.uint8"), "wb") as f: f.write(memoryview(destOrder))
def testHypterTreeGridMask(self): "Test a simple hyper tree grid with masking" htg = vtkHyperTreeGrid() scalarArray = vtkUnsignedCharArray() scalarArray.SetName('scalar') scalarArray.SetNumberOfValues(0) mask = vtkBitArray() mask.SetName('mask') mask.SetNumberOfValues(22) mask.FillComponent(0, 0) htg.SetMaterialMask(mask) htg.GetPointData().SetScalars(scalarArray) htg.Initialize() htg.SetGridSize([3, 2, 1]) htg.SetDimension(2) htg.SetBranchFactor(2) # specify normal index to ignore htg.SetOrientation(2) # htg.SetTransposedRootIndexing(False) # rectilinear grid coordinates xValues = vtkDoubleArray() xValues.SetNumberOfValues(4) xValues.SetValue(0, -1) xValues.SetValue(1, 0) xValues.SetValue(2, 1) xValues.SetValue(3, 2) htg.SetXCoordinates(xValues) yValues = vtkDoubleArray() yValues.SetNumberOfValues(3) yValues.SetValue(0, -1) yValues.SetValue(1, 0) yValues.SetValue(2, 1) htg.SetYCoordinates(yValues) zValues = vtkDoubleArray() zValues.SetNumberOfValues(1) zValues.SetValue(0, 0) htg.SetZCoordinates(zValues) # Let's split the various trees cursor = vtkHyperTreeGridNonOrientedCursor() offsetIndex = 0 # ROOT CELL 0 htg.InitializeNonOrientedCursor(cursor, 0, True) cursor.SetGlobalIndexStart(offsetIndex) # coarse value idx = cursor.GetGlobalNodeIndex() # GLOBAL... # cursor.SetGlobalIndexFromLocal(idx) scalarArray.InsertTuple1(idx, 0) # ROOT CELL 0/[0-3] cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 24) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 27) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 18) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 21) cursor.ToParent() offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 1 htg.InitializeNonOrientedCursor(cursor, 1, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 15) # Mask mask.SetValue(idx, 1) offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 2 htg.InitializeNonOrientedCursor(cursor, 2, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 2) # Mask mask.SetValue(idx, 1) # ROOT CELL 2/[0-3] cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 36) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 39) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 30) # Mask mask.SetValue(idx, 1) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 33) cursor.ToParent() offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 3 htg.InitializeNonOrientedCursor(cursor, 3, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 0) offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 4 htg.InitializeNonOrientedCursor(cursor, 4, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 4) # ROOT CELL 4/[0-3] cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 9) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 12) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 3) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 51) cursor.ToParent() # ROOT CELL 4/3/[0-3] cursor.ToChild(3) cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 45) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 51) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 6) # Mask mask.SetValue(idx, 1) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 45) cursor.ToParent() offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 5 htg.InitializeNonOrientedCursor(cursor, 5, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 42) # --------------------------------------------------------------------- # Convert HTG to PolyData # --------------------------------------------------------------------- geometryFilter = vtkHyperTreeGridGeometry() geometryFilter.SetInputData(htg) # --------------------------------------------------------------------- # Rendering # --------------------------------------------------------------------- ren1 = vtk.vtkRenderer() renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren1) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) lut = vtk.vtkLookupTable() lut.SetHueRange(0.66, 0) lut.SetSaturationRange(1.0, 0.25) lut.SetTableRange(0, 51) lut.Build() mapper = vtk.vtkDataSetMapper() mapper.SetLookupTable(lut) mapper.SetColorModeToMapScalars() mapper.SetScalarModeToUseCellFieldData() mapper.SelectColorArray('scalar') mapper.SetInputConnection(geometryFilter.GetOutputPort()) mapper.UseLookupTableScalarRangeOn() mapper.SetScalarRange(0, 51) actor = vtk.vtkActor() actor.SetMapper(mapper) ren1.AddActor(actor) renWin.SetSize(350, 350) ren1.SetBackground(0.5, 0.5, 0.5) ren1.ResetCamera() renWin.Render() img_file = "TestHyperTreeGridMask.png" vtk.test.Testing.compareImage( renWin, vtk.test.Testing.getAbsImagePath(img_file), threshold=25) vtk.test.Testing.interact()
def processDirectory(self, directory): # Load depth depthStack = [] imageSize = self.config["size"] linearSize = imageSize[0] * imageSize[1] nbLayers = len(self.layers) stackSize = nbLayers * linearSize layerList = range(nbLayers) for layerIdx in layerList: with open(os.path.join(directory, "depth_%d.float32" % layerIdx), "rb") as f: a = array.array("f") a.fromfile(f, linearSize) depthStack.append(a) orderArray = vtkUnsignedCharArray() orderArray.SetName("layerIdx") orderArray.SetNumberOfComponents(1) orderArray.SetNumberOfTuples(stackSize) pixelSorter = [(i, i) for i in layerList] for pixelId in range(linearSize): # Fill pixelSorter for layerIdx in layerList: if depthStack[layerIdx][pixelId] < 1.0: pixelSorter[layerIdx] = (layerIdx, depthStack[layerIdx][pixelId]) else: pixelSorter[layerIdx] = (255, 1.0) # Sort pixel layers pixelSorter.sort(key=lambda tup: tup[1]) # Fill sortedOrder array for layerIdx in layerList: orderArray.SetValue(layerIdx * linearSize + pixelId, pixelSorter[layerIdx][0]) # Write order (sorted order way) with open(os.path.join(directory, "order.uint8"), "wb") as f: f.write(memoryview(orderArray)) self.data.append({ "name": "order", "type": "array", "fileName": "/order.uint8" }) # Remove depth files for layerIdx in layerList: os.remove(os.path.join(directory, "depth_%d.float32" % layerIdx)) # Encode Normals (sorted order way) if "normal" in self.config["light"]: sortedNormal = vtkUnsignedCharArray() sortedNormal.SetNumberOfComponents(3) # x,y,z sortedNormal.SetNumberOfTuples(stackSize) # Get Camera orientation and rotation information camDir = [0, 0, 0] worldUp = [0, 0, 0] with open(os.path.join(directory, "camera.json"), "r") as f: camera = json.load(f) camDir = normalize([ camera["position"][i] - camera["focalPoint"][i] for i in range(3) ]) worldUp = normalize(camera["viewUp"]) # [ camRight, camUp, camDir ] will be our new orthonormal basis for normals camRight = vectProduct(camDir, worldUp) camUp = vectProduct(camRight, camDir) # Tmp structure to capture (x,y,z) normal normalByLayer = vtkFloatArray() normalByLayer.SetNumberOfComponents(3) normalByLayer.SetNumberOfTuples(stackSize) # Capture all layer normals zPosCount = 0 zNegCount = 0 for layerIdx in layerList: # Load normal(x,y,z) from current layer normalLayer = [] for comp in [0, 1, 2]: with open( os.path.join( directory, "normal_%d_%d.float32" % (layerIdx, comp)), "rb", ) as f: a = array.array("f") a.fromfile(f, linearSize) normalLayer.append(a) # Store normal inside vtkArray offset = layerIdx * linearSize for idx in range(linearSize): normalByLayer.SetTuple3( idx + offset, normalLayer[0][idx], normalLayer[1][idx], normalLayer[2][idx], ) # Re-orient normal to be view based vect = normalByLayer.GetTuple3(layerIdx * linearSize + idx) if not math.isnan(vect[0]): # Express normal in new basis we computed above rVect = normalize([ -dotProduct(vect, camRight), dotProduct(vect, camUp), dotProduct(vect, camDir), ]) # Need to reverse vector ? if rVect[2] < 0: normalByLayer.SetTuple3( layerIdx * linearSize + idx, -rVect[0], -rVect[1], -rVect[2], ) else: normalByLayer.SetTuple3( layerIdx * linearSize + idx, rVect[0], rVect[1], rVect[2], ) # Sort normals and encode them as 3 bytes ( -1 < xy < 1 | 0 < z < 1) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: # No normal => same as view direction sortedNormal.SetTuple3(idx, 128, 128, 255) else: offset = layerIdx * linearSize imageIdx = idx % linearSize vect = normalByLayer.GetTuple3(imageIdx + offset) if (not math.isnan(vect[0]) and not math.isnan(vect[1]) and not math.isnan(vect[2])): sortedNormal.SetTuple3( idx, int(127.5 * (vect[0] + 1)), int(127.5 * (vect[1] + 1)), int(255 * vect[2]), ) else: print( "WARNING: encountered NaN in normal of layer ", layerIdx, ": [", vect[0], ",", vect[1], ",", vect[2], "]", ) sortedNormal.SetTuple3(idx, 128, 128, 255) # Write the sorted data with open(os.path.join(directory, "normal.uint8"), "wb") as f: f.write(memoryview(sortedNormal)) self.data.append({ "name": "normal", "type": "array", "fileName": "/normal.uint8", "categories": ["normal"], }) # Remove depth files for layerIdx in layerList: os.remove( os.path.join(directory, "normal_%d_%d.float32" % (layerIdx, 0))) os.remove( os.path.join(directory, "normal_%d_%d.float32" % (layerIdx, 1))) os.remove( os.path.join(directory, "normal_%d_%d.float32" % (layerIdx, 2))) # Encode Intensity (sorted order way) if "intensity" in self.config["light"]: sortedIntensity = vtkUnsignedCharArray() sortedIntensity.SetNumberOfTuples(stackSize) intensityLayers = [] for layerIdx in layerList: with open( os.path.join(directory, "intensity_%d.uint8" % layerIdx), "rb") as f: a = array.array("B") a.fromfile(f, linearSize) intensityLayers.append(a) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: sortedIntensity.SetValue(idx, 255) else: imageIdx = idx % linearSize sortedIntensity.SetValue( idx, intensityLayers[layerIdx][imageIdx]) with open(os.path.join(directory, "intensity.uint8"), "wb") as f: f.write(memoryview(sortedIntensity)) self.data.append({ "name": "intensity", "type": "array", "fileName": "/intensity.uint8", "categories": ["intensity"], }) # Remove depth files for layerIdx in layerList: os.remove( os.path.join(directory, "intensity_%d.uint8" % layerIdx))
def processDirectory(self, directory): self.imageReader.SetFileName(os.path.join(directory, "rgb.png")) self.imageReader.Update() rgbArray = self.imageReader.GetOutput().GetPointData().GetArray(0) self.composite.load(os.path.join(directory, "composite.json")) orderArray = self.composite.getSortedOrderArray() imageSize = self.composite.getImageSize() stackSize = self.composite.getStackSize() # Write order (sorted order way) with open(os.path.join(directory, "order.uint8"), "wb") as f: f.write(memoryview(orderArray)) self.data.append({ "name": "order", "type": "array", "fileName": "/order.uint8" }) # Encode Normals (sorted order way) if "normal" in self.layers[0]: sortedNormal = vtkUnsignedCharArray() sortedNormal.SetNumberOfComponents(3) # x,y,z sortedNormal.SetNumberOfTuples(stackSize) # Get Camera orientation and rotation information camDir = [0, 0, 0] worldUp = [0, 0, 0] with open(os.path.join(directory, "camera.json"), "r") as f: camera = json.load(f) camDir = normalize([ camera["position"][i] - camera["focalPoint"][i] for i in range(3) ]) worldUp = normalize(camera["viewUp"]) # [ camRight, camUp, camDir ] will be our new orthonormal basis for normals camRight = vectProduct(camDir, worldUp) camUp = vectProduct(camRight, camDir) # Tmp structure to capture (x,y,z) normal normalByLayer = vtkFloatArray() normalByLayer.SetNumberOfComponents(3) normalByLayer.SetNumberOfTuples(stackSize) # Capture all layer normals layerIdx = 0 zPosCount = 0 zNegCount = 0 for layer in self.layers: normalOffset = layer["normal"] for idx in range(imageSize): normalByLayer.SetTuple3( layerIdx * imageSize + idx, getScalarFromRGB( rgbArray.GetTuple(idx + normalOffset[0] * imageSize)), getScalarFromRGB( rgbArray.GetTuple(idx + normalOffset[1] * imageSize)), getScalarFromRGB( rgbArray.GetTuple(idx + normalOffset[2] * imageSize)), ) # Re-orient normal to be view based vect = normalByLayer.GetTuple3(layerIdx * imageSize + idx) if not math.isnan(vect[0]): # Express normal in new basis we computed above rVect = normalize([ -dotProduct(vect, camRight), dotProduct(vect, camUp), dotProduct(vect, camDir), ]) # Need to reverse vector ? if rVect[2] < 0: normalByLayer.SetTuple3( layerIdx * imageSize + idx, -rVect[0], -rVect[1], -rVect[2], ) else: normalByLayer.SetTuple3(layerIdx * imageSize + idx, rVect[0], rVect[1], rVect[2]) layerIdx += 1 # Sort normals and encode them as 3 bytes ( -1 < xy < 1 | 0 < z < 1) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: # No normal => same as view direction sortedNormal.SetTuple3(idx, 128, 128, 255) else: offset = layerIdx * imageSize imageIdx = idx % imageSize vect = normalByLayer.GetTuple3(imageIdx + offset) if (not math.isnan(vect[0]) and not math.isnan(vect[1]) and not math.isnan(vect[2])): sortedNormal.SetTuple3( idx, int(127.5 * (vect[0] + 1)), int(127.5 * (vect[1] + 1)), int(255 * vect[2]), ) else: print( "WARNING: encountered NaN in normal of layer ", layerIdx, ": [", vect[0], ",", vect[1], ",", vect[2], "]", ) sortedNormal.SetTuple3(idx, 128, 128, 255) # Write the sorted data with open(os.path.join(directory, "normal.uint8"), "wb") as f: f.write(memoryview(sortedNormal)) self.data.append({ "name": "normal", "type": "array", "fileName": "/normal.uint8", "categories": ["normal"], }) # Encode Intensity (sorted order way) if "intensity" in self.layers[0]: intensityOffsets = [] sortedIntensity = vtkUnsignedCharArray() sortedIntensity.SetNumberOfTuples(stackSize) for layer in self.layers: intensityOffsets.append(layer["intensity"]) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: sortedIntensity.SetValue(idx, 255) else: offset = 3 * intensityOffsets[layerIdx] * imageSize imageIdx = idx % imageSize sortedIntensity.SetValue( idx, rgbArray.GetValue(imageIdx * 3 + offset)) with open(os.path.join(directory, "intensity.uint8"), "wb") as f: f.write(memoryview(sortedIntensity)) self.data.append({ "name": "intensity", "type": "array", "fileName": "/intensity.uint8", "categories": ["intensity"], }) # Encode Each layer Scalar layerIdx = 0 for layer in self.layers: for scalar in layer: if scalar not in ["intensity", "normal"]: offset = imageSize * layer[scalar] scalarRange = self.config["scene"][layerIdx]["colors"][ scalar]["range"] delta = (scalarRange[1] - scalarRange[0] ) / 16777215.0 # 2^24 - 1 => 16,777,215 scalarArray = vtkFloatArray() scalarArray.SetNumberOfTuples(imageSize) for idx in range(imageSize): rgb = rgbArray.GetTuple(idx + offset) if rgb[0] != 0 or rgb[1] != 0 or rgb[2] != 0: # Decode encoded value value = scalarRange[0] + delta * float( rgb[0] * 65536 + rgb[1] * 256 + rgb[2] - 1) scalarArray.SetValue(idx, value) else: # No value scalarArray.SetValue(idx, float("NaN")) with open( os.path.join(directory, "%d_%s.float32" % (layerIdx, scalar)), "wb", ) as f: f.write(memoryview(scalarArray)) self.data.append({ "name": "%d_%s" % (layerIdx, scalar), "type": "array", "fileName": "/%d_%s.float32" % (layerIdx, scalar), "categories": ["%d_%s" % (layerIdx, scalar)], }) layerIdx += 1
def testHypterTreeGridMask(self): "Test a simple hyper tree grid with masking" htg = vtkHyperTreeGrid() scalarArray = vtkUnsignedCharArray() scalarArray.SetName('scalar') scalarArray.SetNumberOfValues(0) mask = vtkBitArray() mask.SetName('mask') mask.SetNumberOfValues(22) mask.FillComponent(0, 0) htg.SetMaterialMask(mask) htg.GetPointData().SetScalars(scalarArray) htg.Initialize() htg.SetGridSize([3, 2, 1]) htg.SetDimension(2) htg.SetBranchFactor(2) # specify normal index to ignore htg.SetOrientation(2) # htg.SetTransposedRootIndexing(False) # rectilinear grid coordinates xValues = vtkDoubleArray() xValues.SetNumberOfValues(4) xValues.SetValue(0, -1) xValues.SetValue(1, 0) xValues.SetValue(2, 1) xValues.SetValue(3, 2) htg.SetXCoordinates(xValues); yValues = vtkDoubleArray() yValues.SetNumberOfValues(3) yValues.SetValue(0, -1) yValues.SetValue(1, 0) yValues.SetValue(2, 1) htg.SetYCoordinates(yValues); zValues = vtkDoubleArray() zValues.SetNumberOfValues(1) zValues.SetValue(0, 0) htg.SetZCoordinates(zValues); # Let's split the various trees cursor = vtkHyperTreeGridNonOrientedCursor() offsetIndex = 0 # ROOT CELL 0 htg.InitializeNonOrientedCursor(cursor, 0, True) cursor.SetGlobalIndexStart(offsetIndex) # coarse value idx = cursor.GetGlobalNodeIndex() # GLOBAL... # cursor.SetGlobalIndexFromLocal(idx) scalarArray.InsertTuple1(idx, 0) # ROOT CELL 0/[0-3] cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 24) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 27) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 18) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 21) cursor.ToParent() offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 1 htg.InitializeNonOrientedCursor(cursor, 1, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 15) # Mask mask.SetValue(idx, 1) offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 2 htg.InitializeNonOrientedCursor(cursor, 2, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 2) # Mask mask.SetValue(idx, 1) # ROOT CELL 2/[0-3] cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 36) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 39) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 30) # Mask mask.SetValue(idx, 1) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 33) cursor.ToParent() offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 3 htg.InitializeNonOrientedCursor(cursor, 3, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 0) offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 4 htg.InitializeNonOrientedCursor(cursor, 4, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 4) # ROOT CELL 4/[0-3] cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 9) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 12) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 3) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 51) cursor.ToParent() # ROOT CELL 4/3/[0-3] cursor.ToChild(3) cursor.SubdivideLeaf() cursor.ToChild(0) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 45) cursor.ToParent() cursor.ToChild(1) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 51) cursor.ToParent() cursor.ToChild(2) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 6) # Mask mask.SetValue(idx, 1) cursor.ToParent() cursor.ToChild(3) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 45) cursor.ToParent() offsetIndex += cursor.GetTree().GetNumberOfVertices() # ROOT CELL 5 htg.InitializeNonOrientedCursor(cursor, 5, True) cursor.SetGlobalIndexStart(offsetIndex) idx = cursor.GetGlobalNodeIndex() scalarArray.InsertTuple1(idx, 42) # --------------------------------------------------------------------- # Convert HTG to PolyData # --------------------------------------------------------------------- geometryFilter = vtkHyperTreeGridGeometry() geometryFilter.SetInputData(htg) # --------------------------------------------------------------------- # Rendering # --------------------------------------------------------------------- ren1 = vtk.vtkRenderer() renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren1) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) lut = vtk.vtkLookupTable() lut.SetHueRange(0.66, 0) lut.SetSaturationRange(1.0, 0.25); lut.SetTableRange(0, 51) lut.Build() mapper = vtk.vtkDataSetMapper() mapper.SetLookupTable(lut) mapper.SetColorModeToMapScalars() mapper.SetScalarModeToUseCellFieldData() mapper.SelectColorArray('scalar') mapper.SetInputConnection(geometryFilter.GetOutputPort()) mapper.UseLookupTableScalarRangeOn() mapper.SetScalarRange(0, 51); actor = vtk.vtkActor() actor.SetMapper(mapper) ren1.AddActor(actor) renWin.SetSize(350,350) ren1.SetBackground(0.5,0.5,0.5) ren1.ResetCamera() renWin.Render() img_file = "TestHyperTreeGridMask.png" vtk.test.Testing.compareImage(renWin, vtk.test.Testing.getAbsImagePath(img_file), threshold=25) vtk.test.Testing.interact()
def writeData(self): composite_size = len(self.representations) self.view.UpdatePropertyInformation() self.view.Background = [0,0,0] imageSize = self.view.ViewSize[0] * self.view.ViewSize[1] # Generate the heavy data for camPos in self.getCamera(): self.view.CameraFocalPoint = camPos['focalPoint'] self.view.CameraPosition = camPos['position'] self.view.CameraViewUp = camPos['viewUp'] # Show all representations for compositeIdx in range(composite_size): rep = self.representations[compositeIdx] rep.Visibility = 1 # Fix camera bounds self.view.LockBounds = 0 simple.Render(self.view) self.view.LockBounds = 1 # Update destination directory dest_path = os.path.dirname(self.dataHandler.getDataAbsoluteFilePath('directory')) # Write camera information if self.dataHandler.can_write: with open(os.path.join(dest_path, "camera.json"), 'w') as f: f.write(json.dumps(camPos)) # Hide all representations for compositeIdx in range(composite_size): rep = self.representations[compositeIdx] rep.Visibility = 0 # Show only active Representation # Extract images for each fields for compositeIdx in range(composite_size): rep = self.representations[compositeIdx] if compositeIdx > 0: self.representations[compositeIdx - 1].Visibility = 0 rep.Visibility = 1 # capture Z simple.Render() zBuffer = self.view.CaptureDepthBuffer() with open(os.path.join(dest_path, 'depth_%d.float32' % compositeIdx), 'wb') as f: f.write(buffer(zBuffer)) # Prevent color interference rep.DiffuseColor = [1,1,1] # Handle light for lightType in self.config['light']: if lightType == 'intensity': rep.AmbientColor = [1,1,1] rep.SpecularColor = [1,1,1] self.view.StartCaptureLuminance() image = self.view.CaptureWindow(1) imagescalars = image.GetPointData().GetScalars() self.view.StopCaptureLuminance() # Extract specular information specularOffset = 1 # [diffuse, specular, ?] imageSize = imagescalars.GetNumberOfTuples() specularComponent = vtkUnsignedCharArray() specularComponent.SetNumberOfComponents(1) specularComponent.SetNumberOfTuples(imageSize) for idx in range(imageSize): specularComponent.SetValue(idx, imagescalars.GetValue(idx * 3 + specularOffset)) with open(os.path.join(dest_path, 'intensity_%d.uint8' % compositeIdx), 'wb') as f: f.write(buffer(specularComponent)) # Free memory image.UnRegister(None) if lightType == 'normal': if rep.Representation in ['Point Gaussian', 'Points', 'Outline', 'Wireframe']: uniqNormal = [(camPos['position'][i] - camPos['focalPoint'][i]) for i in range(3)] tmpNormalArray = vtkFloatArray() tmpNormalArray.SetNumberOfComponents(1) tmpNormalArray.SetNumberOfTuples(imageSize) for comp in range(3): tmpNormalArray.FillComponent(0, uniqNormal[comp]) with open(os.path.join(dest_path, 'normal_%d_%d.float32' % (compositeIdx, comp)), 'wb') as f: f.write(buffer(tmpNormalArray)) else: for comp in range(3): # Configure view to handle POINT_DATA / CELL_DATA self.view.DrawCells = 0 self.view.ArrayNameToDraw = 'Normals' self.view.ArrayComponentToDraw = comp self.view.ScalarRange = [-1.0, 1.0] self.view.StartCaptureValues() image = self.view.CaptureWindow(1) imagescalars = image.GetPointData().GetScalars() self.view.StopCaptureValues() # Convert RGB => Float => Write floatArray = data_converter.convertRGBArrayToFloatArray(imagescalars, [-1.0, 1.0]) with open(os.path.join(dest_path, 'normal_%d_%d.float32' % (compositeIdx, comp)), 'wb') as f: f.write(buffer(floatArray)) # Free memory image.UnRegister(None) # Handle color by for fieldName, fieldConfig in iteritems(self.config['scene'][compositeIdx]['colors']): if 'constant' in fieldConfig: # Skip nothing to render continue # Configure view to handle POINT_DATA / CELL_DATA if fieldConfig['location'] == 'POINT_DATA': self.view.DrawCells = 0 else: self.view.DrawCells = 1 self.view.ArrayNameToDraw = fieldName self.view.ArrayComponentToDraw = 0 self.view.ScalarRange = fieldConfig['range'] self.view.StartCaptureValues() image = self.view.CaptureWindow(1) imagescalars = image.GetPointData().GetScalars() self.view.StopCaptureValues() floatArray = data_converter.convertRGBArrayToFloatArray(imagescalars, fieldConfig['range']) with open(os.path.join(dest_path, '%d_%s.float32' % (compositeIdx, fieldName)), 'wb') as f: f.write(buffer(floatArray)) self.dataHandler.registerData(name='%d_%s' % (compositeIdx, fieldName), fileName='/%d_%s.float32' % (compositeIdx, fieldName), type='array', categories=['%d_%s' % (compositeIdx, fieldName)]) # Free memory image.UnRegister(None)
def processDirectory(self, directory): # Load depth depthStack = [] imageSize = self.config['size'] linearSize = imageSize[0] * imageSize[1] nbLayers = len(self.layers) stackSize = nbLayers * linearSize layerList = range(nbLayers) for layerIdx in layerList: with open(os.path.join(directory, 'depth_%d.float32' % layerIdx), "rb") as f: a = array.array('f') a.fromfile(f, linearSize) depthStack.append(a) orderArray = vtkUnsignedCharArray() orderArray.SetName('layerIdx'); orderArray.SetNumberOfComponents(1) orderArray.SetNumberOfTuples(stackSize) pixelSorter = [(i, i) for i in layerList] for pixelId in range(linearSize): # Fill pixelSorter for layerIdx in layerList: if depthStack[layerIdx][pixelId] < 1.0: pixelSorter[layerIdx] = (layerIdx, depthStack[layerIdx][pixelId]) else: pixelSorter[layerIdx] = (255, 1.0) # Sort pixel layers pixelSorter.sort(key=lambda tup: tup[1]) # Fill sortedOrder array for layerIdx in layerList: orderArray.SetValue(layerIdx * linearSize + pixelId, pixelSorter[layerIdx][0]) # Write order (sorted order way) with open(os.path.join(directory, 'order.uint8'), 'wb') as f: f.write(buffer(orderArray)) self.data.append({'name': 'order', 'type': 'array', 'fileName': '/order.uint8'}) # Remove depth files for layerIdx in layerList: os.remove(os.path.join(directory, 'depth_%d.float32' % layerIdx)) # Encode Normals (sorted order way) if 'normal' in self.config['light']: sortedNormal = vtkUnsignedCharArray() sortedNormal.SetNumberOfComponents(3) # x,y,z sortedNormal.SetNumberOfTuples(stackSize) # Get Camera orientation and rotation information camDir = [0,0,0] worldUp = [0,0,0] with open(os.path.join(directory, "camera.json"), "r") as f: camera = json.load(f) camDir = normalize([ camera['position'][i] - camera['focalPoint'][i] for i in range(3) ]) worldUp = normalize(camera['viewUp']) # [ camRight, camUp, camDir ] will be our new orthonormal basis for normals camRight = vectProduct(camDir, worldUp) camUp = vectProduct(camRight, camDir) # Tmp structure to capture (x,y,z) normal normalByLayer = vtkFloatArray() normalByLayer.SetNumberOfComponents(3) normalByLayer.SetNumberOfTuples(stackSize) # Capture all layer normals zPosCount = 0 zNegCount = 0 for layerIdx in layerList: # Load normal(x,y,z) from current layer normalLayer = [] for comp in [0, 1, 2]: with open(os.path.join(directory, 'normal_%d_%d.float32' % (layerIdx, comp)), "rb") as f: a = array.array('f') a.fromfile(f, linearSize) normalLayer.append(a) # Store normal inside vtkArray offset = layerIdx * linearSize for idx in range(linearSize): normalByLayer.SetTuple3( idx + offset, normalLayer[0][idx], normalLayer[1][idx], normalLayer[2][idx] ) # Re-orient normal to be view based vect = normalByLayer.GetTuple3(layerIdx * linearSize + idx) if not math.isnan(vect[0]): # Express normal in new basis we computed above rVect = normalize([ -dotProduct(vect, camRight), dotProduct(vect, camUp), dotProduct(vect, camDir) ]) # Need to reverse vector ? if rVect[2] < 0: normalByLayer.SetTuple3(layerIdx * linearSize + idx, -rVect[0], -rVect[1], -rVect[2]) else: normalByLayer.SetTuple3(layerIdx * linearSize + idx, rVect[0], rVect[1], rVect[2]) # Sort normals and encode them as 3 bytes ( -1 < xy < 1 | 0 < z < 1) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: # No normal => same as view direction sortedNormal.SetTuple3(idx, 128, 128, 255) else: offset = layerIdx * linearSize imageIdx = idx % linearSize vect = normalByLayer.GetTuple3(imageIdx + offset) if not math.isnan(vect[0]) and not math.isnan(vect[1]) and not math.isnan(vect[2]): sortedNormal.SetTuple3(idx, int(127.5 * (vect[0] + 1)), int(127.5 * (vect[1] + 1)), int(255 * vect[2])) else: print ('WARNING: encountered NaN in normal of layer ',layerIdx,': [',vect[0],',',vect[1],',',vect[2],']') sortedNormal.SetTuple3(idx, 128, 128, 255) # Write the sorted data with open(os.path.join(directory, 'normal.uint8'), 'wb') as f: f.write(buffer(sortedNormal)) self.data.append({'name': 'normal', 'type': 'array', 'fileName': '/normal.uint8', 'categories': ['normal']}) # Remove depth files for layerIdx in layerList: os.remove(os.path.join(directory, 'normal_%d_%d.float32' % (layerIdx, 0))) os.remove(os.path.join(directory, 'normal_%d_%d.float32' % (layerIdx, 1))) os.remove(os.path.join(directory, 'normal_%d_%d.float32' % (layerIdx, 2))) # Encode Intensity (sorted order way) if 'intensity' in self.config['light']: sortedIntensity = vtkUnsignedCharArray() sortedIntensity.SetNumberOfTuples(stackSize) intensityLayers = [] for layerIdx in layerList: with open(os.path.join(directory, 'intensity_%d.uint8' % layerIdx), "rb") as f: a = array.array('B') a.fromfile(f, linearSize) intensityLayers.append(a) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: sortedIntensity.SetValue(idx, 255) else: imageIdx = idx % linearSize sortedIntensity.SetValue(idx, intensityLayers[layerIdx][imageIdx]) with open(os.path.join(directory, 'intensity.uint8'), 'wb') as f: f.write(buffer(sortedIntensity)) self.data.append({'name': 'intensity', 'type': 'array', 'fileName': '/intensity.uint8', 'categories': ['intensity']}) # Remove depth files for layerIdx in layerList: os.remove(os.path.join(directory, 'intensity_%d.uint8' % layerIdx))
def processDirectory(self, directory): self.imageReader.SetFileName(os.path.join(directory, 'rgb.png')) self.imageReader.Update() rgbArray = self.imageReader.GetOutput().GetPointData().GetArray(0) self.composite.load(os.path.join(directory, 'composite.json')) orderArray = self.composite.getSortedOrderArray() imageSize = self.composite.getImageSize() stackSize = self.composite.getStackSize() # Write order (sorted order way) with open(os.path.join(directory, 'order.uint8'), 'wb') as f: f.write(buffer(orderArray)) self.data.append({'name': 'order', 'type': 'array', 'fileName': '/order.uint8'}) # Encode Normals (sorted order way) if 'normal' in self.layers[0]: sortedNormal = vtkUnsignedCharArray() sortedNormal.SetNumberOfComponents(3) # x,y,z sortedNormal.SetNumberOfTuples(stackSize) # Get Camera orientation and rotation information camDir = [0,0,0] worldUp = [0,0,0] with open(os.path.join(directory, "camera.json"), "r") as f: camera = json.load(f) camDir = normalize([ camera['position'][i] - camera['focalPoint'][i] for i in range(3) ]) worldUp = normalize(camera['viewUp']) # [ camRight, camUp, camDir ] will be our new orthonormal basis for normals camRight = vectProduct(camDir, worldUp) camUp = vectProduct(camRight, camDir) # Tmp structure to capture (x,y,z) normal normalByLayer = vtkFloatArray() normalByLayer.SetNumberOfComponents(3) normalByLayer.SetNumberOfTuples(stackSize) # Capture all layer normals layerIdx = 0 zPosCount = 0 zNegCount = 0 for layer in self.layers: normalOffset = layer['normal'] for idx in range(imageSize): normalByLayer.SetTuple3( layerIdx * imageSize + idx, getScalarFromRGB(rgbArray.GetTuple(idx + normalOffset[0] * imageSize)), getScalarFromRGB(rgbArray.GetTuple(idx + normalOffset[1] * imageSize)), getScalarFromRGB(rgbArray.GetTuple(idx + normalOffset[2] * imageSize)) ) # Re-orient normal to be view based vect = normalByLayer.GetTuple3(layerIdx * imageSize + idx) if not math.isnan(vect[0]): # Express normal in new basis we computed above rVect = normalize([ -dotProduct(vect, camRight), dotProduct(vect, camUp), dotProduct(vect, camDir) ]) # Need to reverse vector ? if rVect[2] < 0: normalByLayer.SetTuple3(layerIdx * imageSize + idx, -rVect[0], -rVect[1], -rVect[2]) else: normalByLayer.SetTuple3(layerIdx * imageSize + idx, rVect[0], rVect[1], rVect[2]) layerIdx += 1 # Sort normals and encode them as 3 bytes ( -1 < xy < 1 | 0 < z < 1) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: # No normal => same as view direction sortedNormal.SetTuple3(idx, 128, 128, 255) else: offset = layerIdx * imageSize imageIdx = idx % imageSize vect = normalByLayer.GetTuple3(imageIdx + offset) if not math.isnan(vect[0]) and not math.isnan(vect[1]) and not math.isnan(vect[2]): sortedNormal.SetTuple3(idx, int(127.5 * (vect[0] + 1)), int(127.5 * (vect[1] + 1)), int(255 * vect[2])) else: print ('WARNING: encountered NaN in normal of layer ',layerIdx,': [',vect[0],',',vect[1],',',vect[2],']') sortedNormal.SetTuple3(idx, 128, 128, 255) # Write the sorted data with open(os.path.join(directory, 'normal.uint8'), 'wb') as f: f.write(buffer(sortedNormal)) self.data.append({'name': 'normal', 'type': 'array', 'fileName': '/normal.uint8', 'categories': ['normal']}) # Encode Intensity (sorted order way) if 'intensity' in self.layers[0]: intensityOffsets = [] sortedIntensity = vtkUnsignedCharArray() sortedIntensity.SetNumberOfTuples(stackSize) for layer in self.layers: intensityOffsets.append(layer['intensity']) for idx in range(stackSize): layerIdx = int(orderArray.GetValue(idx)) if layerIdx == 255: sortedIntensity.SetValue(idx, 255) else: offset = 3 * intensityOffsets[layerIdx] * imageSize imageIdx = idx % imageSize sortedIntensity.SetValue(idx, rgbArray.GetValue(imageIdx * 3 + offset)) with open(os.path.join(directory, 'intensity.uint8'), 'wb') as f: f.write(buffer(sortedIntensity)) self.data.append({'name': 'intensity', 'type': 'array', 'fileName': '/intensity.uint8', 'categories': ['intensity']}) # Encode Each layer Scalar layerIdx = 0 for layer in self.layers: for scalar in layer: if scalar not in ['intensity', 'normal']: offset = imageSize * layer[scalar] scalarRange = self.config['scene'][layerIdx]['colors'][scalar]['range'] delta = (scalarRange[1] - scalarRange[0]) / 16777215.0 # 2^24 - 1 => 16,777,215 scalarArray = vtkFloatArray() scalarArray.SetNumberOfTuples(imageSize) for idx in range(imageSize): rgb = rgbArray.GetTuple(idx + offset) if rgb[0] != 0 or rgb[1] != 0 or rgb[2] != 0: # Decode encoded value value = scalarRange[0] + delta * float(rgb[0]*65536 + rgb[1]*256 + rgb[2] - 1) scalarArray.SetValue(idx, value) else: # No value scalarArray.SetValue(idx, float('NaN')) with open(os.path.join(directory, '%d_%s.float32' % (layerIdx, scalar)), 'wb') as f: f.write(buffer(scalarArray)) self.data.append({'name': '%d_%s' % (layerIdx, scalar), 'type': 'array', 'fileName': '/%d_%s.float32' % (layerIdx, scalar), 'categories': ['%d_%s' % (layerIdx, scalar)]}) layerIdx += 1