def convertRGBArrayToFloatArray(rgbArray, scalarRange=[0.0, 1.0]): linearSize = rgbArray.GetNumberOfTuples() outputArray = vtkFloatArray() outputArray.SetNumberOfComponents(1) outputArray.SetNumberOfTuples(linearSize) for idx in range(linearSize): outputArray.SetTuple1( idx, getScalarFromRGB(rgbArray.GetTuple(idx), scalarRange)) return outputArray
def convertRGBArrayToFloatArray(rgbArray, scalarRange=[0.0, 1.0]): linearSize = rgbArray.GetNumberOfTuples() outputArray = vtkFloatArray() outputArray.SetNumberOfComponents(1) outputArray.SetNumberOfTuples(linearSize) for idx in range(linearSize): outputArray.SetTuple1( idx, getScalarFromRGB(rgbArray.GetTuple(idx), scalarRange) ) return outputArray
def transform_scalars(dataset, label_value=1): """Computes the principal axes of an object with the label value passed in as the parameter label_value. The principal axes are added to the field data of the dataset as an array of 3-component tuples named 'PrincipalAxes'. The principal axis tuples are stored in order of length from longest to shortest. The center of the object is also added to the field data as an array named 'Center' with a single 3-component tuple. This operator uses principal components analysis of the labeled point locations to determine the principal axes. """ from tomviz import utils from vtkmodules.vtkCommonCore import vtkFloatArray fd = dataset.GetFieldData() (axes, center) = utils.label_object_principal_axes(dataset, label_value) print(axes) print(center) axis_array = vtkFloatArray() axis_array.SetName('PrincipalAxes') axis_array.SetNumberOfComponents(3) axis_array.SetNumberOfTuples(3) axis_array.InsertTypedTuple(0, list(axes[:, 0])) axis_array.InsertTypedTuple(1, list(axes[:, 1])) axis_array.InsertTypedTuple(2, list(axes[:, 2])) fd.RemoveArray('PrincipalAxis') fd.AddArray(axis_array) center_array = vtkFloatArray() center_array.SetName('Center') center_array.SetNumberOfComponents(3) center_array.SetNumberOfTuples(1) center_array.InsertTypedTuple(0, list(center)) fd.RemoveArray('Center') fd.AddArray(center_array)
def convertImageToFloat(srcPngImage, destFile, scalarRange=[0.0, 1.0]): reader = vtkPNGReader() reader.SetFileName(srcPngImage) reader.Update() rgbArray = reader.GetOutput().GetPointData().GetArray(0) stackSize = rgbArray.GetNumberOfTuples() size = reader.GetOutput().GetDimensions() outputArray = vtkFloatArray() outputArray.SetNumberOfComponents(1) outputArray.SetNumberOfTuples(stackSize) for idx in range(stackSize): outputArray.SetTuple1( idx, getScalarFromRGB(rgbArray.GetTuple(idx), scalarRange)) # Write float file with open(destFile, "wb") as f: f.write(memoryview(outputArray)) return size
def convertImageToFloat(srcPngImage, destFile, scalarRange=[0.0, 1.0]): reader = vtkPNGReader() reader.SetFileName(srcPngImage) reader.Update() rgbArray = reader.GetOutput().GetPointData().GetArray(0) stackSize = rgbArray.GetNumberOfTuples() size = reader.GetOutput().GetDimensions() outputArray = vtkFloatArray() outputArray.SetNumberOfComponents(1) outputArray.SetNumberOfTuples(stackSize) for idx in range(stackSize): outputArray.SetTuple1( idx, getScalarFromRGB(rgbArray.GetTuple(idx), scalarRange) ) # Write float file with open(destFile, 'wb') as f: f.write(buffer(outputArray)) return size
def RequestData(self, request, inInfoVec, outInfoVec): from vtkmodules.vtkCommonCore import vtkFloatArray, vtkPoints from vtkmodules.vtkCommonDataModel import ( vtkCellArray, vtkCompositeDataSet, vtkPartitionedDataSet, vtkPartitionedDataSetCollection, vtkPolyData) output = vtkPartitionedDataSetCollection.GetData(outInfoVec) partitioned_datasets = [] partitioned_dataset_names = [] # Parse line file if not self._filename: print_error("SAVGReader requires a FileName") return 0 # Stores lines of text from the file associated with each group of # geometries encountered. geometries = {"lines": [], "points": [], "poly": []} # Read the file and build up data structure to hold the primitives with open(self._filename, "r") as file: current = None for line in file: parts = line.split("#") line = parts[0].strip().lower() if len(line) < 1: continue if not_supported(line): continue if line.startswith("lin"): geometries["lines"].append({"rgba": None, "values": []}) current = geometries["lines"][-1] line_parts = line.split(" ") if len(line_parts) == 5: current["rgba"] = [float(n) for n in line_parts[1:]] elif line.startswith("point"): geometries["points"].append({ "rgba": None, "values": [], }) current = geometries["points"][-1] line_parts = line.split(" ") if len(line_parts) == 5: current["rgba"] = [float(n) for n in line_parts[1:]] elif line.startswith("poly"): geometries["poly"].append({ "rgba": None, "npts": None, "values": [], }) current = geometries["poly"][-1] line_parts = line.split(" ") if len(line_parts) == 2: current["npts"] = int(line_parts[1]) elif len(line_parts) == 6: current["rgba"] = [float(n) for n in line_parts[1:5]] current["npts"] = int(line_parts[5]) elif line.startswith("end"): current = None else: if current is not None: if "npts" in current and current["npts"] is not None: # polygon, known num pts per poly if len(current["values"]) == current["npts"]: # Reached the number of points for the current one, # start a new one. geometries["poly"].append({ "npts": current["npts"], "rgba": current["rgba"], "values": [] }) current = geometries["poly"][-1] pt, pt_col, pt_n = get_coords_from_line(line) if pt: current["values"].append({ "pos": pt, }) color = pt_col or current["rgba"] if color: current["values"][-1]["col"] = color if pt_n: current["values"][-1]["norm"] = pt_n # Build lines polydata if there were any lines if geometries["lines"]: line_points = vtkPoints() line_cells = vtkCellArray() line_point_colors = vtkFloatArray() line_point_colors.SetNumberOfComponents(4) line_point_colors.SetName("rgba_colors") line_point_normals = vtkFloatArray() line_point_normals.SetNumberOfComponents(3) line_point_normals.SetName("vertex_normals") pt_count = 0 for batch in geometries["lines"]: num_in_batch = len(batch["values"]) first_in_batch = True for coord in batch["values"]: if "pos" in coord: line_points.InsertNextPoint(coord["pos"]) if "norm" in coord: line_point_normals.InsertNextTuple(coord["norm"]) if "col" in coord: line_point_colors.InsertNextTuple(coord["col"]) if first_in_batch: line_cells.InsertNextCell(num_in_batch) first_in_batch = False line_cells.InsertCellPoint(pt_count) pt_count += 1 output_lines = vtkPolyData() output_lines.SetPoints(line_points) output_lines.SetLines(line_cells) if line_point_colors.GetNumberOfTuples() > 0: output_lines.GetPointData().AddArray(line_point_colors) if line_point_normals.GetNumberOfTuples() > 0: output_lines.GetPointData().AddArray(line_point_normals) ds = vtkPartitionedDataSet() ds.SetNumberOfPartitions(1) ds.SetPartition(0, output_lines) partitioned_datasets.append(ds) partitioned_dataset_names.append("Lines") # Build the points polydata if we found points if geometries["points"]: p_points = vtkPoints() p_cells = vtkCellArray() p_point_colors = vtkFloatArray() p_point_colors.SetNumberOfComponents(4) p_point_colors.SetName("rgba_colors") p_point_normals = vtkFloatArray() p_point_normals.SetNumberOfComponents(3) p_point_normals.SetName("vertex_normals") p_count = 0 for batch in geometries["points"]: num_in_batch = len(batch["values"]) first_in_batch = True for coord in batch["values"]: if "pos" in coord: p_points.InsertNextPoint(coord["pos"]) if "norm" in coord: p_point_normals.InsertNextTuple(coord["norm"]) if "col" in coord: p_point_colors.InsertNextTuple(coord["col"]) if first_in_batch: p_cells.InsertNextCell(num_in_batch) first_in_batch = False p_cells.InsertCellPoint(p_count) p_count += 1 output_points = vtkPolyData() output_points.SetPoints(p_points) output_points.SetVerts(p_cells) if p_point_colors.GetNumberOfTuples() > 0: output_points.GetPointData().AddArray(p_point_colors) if p_point_normals.GetNumberOfTuples() > 0: output_points.GetPointData().AddArray(p_point_normals) ds = vtkPartitionedDataSet() ds.SetNumberOfPartitions(1) ds.SetPartition(0, output_points) partitioned_datasets.append(ds) partitioned_dataset_names.append("Points") # Build the polygons if there were any if geometries["poly"]: poly_points = vtkPoints() poly_cells = vtkCellArray() poly_point_colors = vtkFloatArray() poly_point_colors.SetNumberOfComponents(4) poly_point_colors.SetName("rgba_colors") poly_point_normals = vtkFloatArray() poly_point_normals.SetNumberOfComponents(3) poly_point_normals.SetName("vertex_normals") pt_count = 0 for batch in geometries["poly"]: num_in_batch = len(batch["values"]) if num_in_batch < 1: continue first_in_batch = True for coord in batch["values"]: if "pos" in coord: poly_points.InsertNextPoint(coord["pos"]) if "norm" in coord: poly_point_normals.InsertNextTuple(coord["norm"]) if "col" in coord: poly_point_colors.InsertNextTuple(coord["col"]) if first_in_batch: np_in_cell = num_in_batch poly_cells.InsertNextCell(np_in_cell) first_in_batch = False poly_cells.InsertCellPoint(pt_count) pt_count += 1 output_polys = vtkPolyData() output_polys.SetPoints(poly_points) output_polys.SetPolys(poly_cells) if poly_point_colors.GetNumberOfTuples() > 0: output_polys.GetPointData().AddArray(poly_point_colors) if poly_point_normals.GetNumberOfTuples() > 0: output_polys.GetPointData().AddArray(poly_point_normals) ds = vtkPartitionedDataSet() ds.SetNumberOfPartitions(1) ds.SetPartition(0, output_polys) partitioned_datasets.append(ds) partitioned_dataset_names.append("Polygons") # Add any partioned datasets we created output.SetNumberOfPartitionedDataSets(len(partitioned_datasets)) for idx, pds in enumerate(partitioned_datasets): output.SetPartitionedDataSet(idx, pds) output.GetMetaData(idx).Set(vtkCompositeDataSet.NAME(), partitioned_dataset_names[idx]) return 1
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 writeArray(self, path, source, name, component=0): rep = simple.Show(source, self.view) rep.Representation = 'Surface' rep.DiffuseColor = [1, 1, 1] dataRange = [0.0, 1.0] fieldToColorBy = ['POINTS', name] self.view.ArrayNameToDraw = name self.view.ArrayComponentToDraw = component pdi = source.GetPointDataInformation() cdi = source.GetCellDataInformation() if pdi.GetArray(name): self.view.DrawCells = 0 dataRange = pdi.GetArray(name).GetRange(component) fieldToColorBy[0] = 'POINTS' elif cdi.GetArray(name): self.view.DrawCells = 1 dataRange = cdi.GetArray(name).GetRange(component) fieldToColorBy[0] = 'CELLS' else: print("No array with that name", name) return realRange = dataRange if dataRange[0] == dataRange[1]: dataRange = [dataRange[0] - 0.1, dataRange[1] + 0.1] simple.ColorBy(rep, fieldToColorBy) # Grab data tmpFileName = path + '__.png' self.view.ScalarRange = dataRange self.view.LockBounds = 1 self.view.StartCaptureValues() simple.SaveScreenshot(tmpFileName, self.view) self.view.StopCaptureValues() 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 = vtkFloatArray() rawArray.SetNumberOfTuples(arraySize) minValue = 10000.0 maxValue = -100000.0 delta = (dataRange[1] - dataRange[0]) / 16777215.0 # 2^24 - 1 => 16,777,215 for idx in range(arraySize): rgb = rgbArray.GetTuple3(idx) if rgb[0] != 0 or rgb[1] != 0 or rgb[2] != 0: value = dataRange[0] + delta * float( rgb[0] * 65536 + rgb[1] * 256 + rgb[2] - 1) rawArray.SetTuple1(idx, value) minValue = min(value, minValue) maxValue = max(value, maxValue) else: rawArray.SetTuple1(idx, float('NaN')) # print ('Array bounds', minValue, maxValue, 'compare to', dataRange) with open(path, 'wb') as f: f.write(buffer(rawArray)) # Delete temporary file if self.cleanAfterMe: os.remove(tmpFileName) # Remove representation from view simple.Hide(source, self.view) return realRange
def _do_surface_creation(self, mask, mask_sFormMatrix=None): if mask_sFormMatrix is None: mask_sFormMatrix = vtkMatrix4x4() value = np.mean(mask.GetScalarRange()) # Use the mask to create isosurface mc = vtkContourFilter() mc.SetInputData(mask) mc.SetValue(0, value) mc.ComputeNormalsOn() mc.Update() # Mask isosurface refSurface = mc.GetOutput() # Create a uniformly meshed surface tmpPeel = downsample(refSurface) # Standard space coordinates # Apply coordinate transform to the meshed mask mask_ijk2xyz = vtkTransform() mask_ijk2xyz.SetMatrix(mask_sFormMatrix) mask_ijk2xyz_filter = vtkTransformPolyDataFilter() mask_ijk2xyz_filter.SetInputData(tmpPeel) mask_ijk2xyz_filter.SetTransform(mask_ijk2xyz) mask_ijk2xyz_filter.Update() # Smooth the mesh tmpPeel = smooth(mask_ijk2xyz_filter.GetOutput()) # Configure calculation of normals tmpPeel = fixMesh(tmpPeel) # Remove duplicate points etc # tmpPeel = cleanMesh(tmpPeel) # Generate triangles tmpPeel = upsample(tmpPeel) tmpPeel = smooth(tmpPeel) tmpPeel = fixMesh(tmpPeel) tmpPeel = cleanMesh(tmpPeel) refImageSpace2_xyz_transform = vtkTransform() refImageSpace2_xyz_transform.SetMatrix(vtk_utils.numpy_to_vtkMatrix4x4(np.linalg.inv(self.affine))) self.refImageSpace2_xyz = vtkTransformPolyDataFilter() self.refImageSpace2_xyz.SetTransform(refImageSpace2_xyz_transform) xyz2_refImageSpace_transform = vtkTransform() xyz2_refImageSpace_transform.SetMatrix(vtk_utils.numpy_to_vtkMatrix4x4(self.affine)) self.xyz2_refImageSpace = vtkTransformPolyDataFilter() self.xyz2_refImageSpace.SetTransform(xyz2_refImageSpace_transform) currentPeel = tmpPeel self.currentPeelNo = 0 currentPeel= self.MapImageOnCurrentPeel(currentPeel) newPeel = vtkPolyData() newPeel.DeepCopy(currentPeel) newPeel.DeepCopy(currentPeel) self.peel_normals = vtkFloatArray() self.peel_centers = vtkFloatArray() self.peel.append(newPeel) self.currentPeelActor = vtkActor() if not np.all(np.equal(self.affine, np.eye(4))): affine_vtk = self.CreateTransformedVTKAffine() self.currentPeelActor.SetUserMatrix(affine_vtk) self.GetCurrentPeelActor(currentPeel) self.peelActors.append(self.currentPeelActor) # locator will later find the triangle on the peel surface where the coil's normal intersect self.locator = vtkCellLocator() self.PeelDown(currentPeel)
def writeArray(self, path, source, name, component=0): rep = simple.Show(source, self.view) rep.Representation = 'Surface' rep.DiffuseColor = [1,1,1] dataRange = [0.0, 1.0] fieldToColorBy = ['POINTS', name] self.view.ArrayNameToDraw = name self.view.ArrayComponentToDraw = component pdi = source.GetPointDataInformation() cdi = source.GetCellDataInformation() if pdi.GetArray(name): self.view.DrawCells = 0 dataRange = pdi.GetArray(name).GetRange(component) fieldToColorBy[0] = 'POINTS' elif cdi.GetArray(name): self.view.DrawCells = 1 dataRange = cdi.GetArray(name).GetRange(component) fieldToColorBy[0] = 'CELLS' else: print ("No array with that name", name) return realRange = dataRange if dataRange[0] == dataRange[1]: dataRange = [dataRange[0] - 0.1, dataRange[1] + 0.1] simple.ColorBy(rep, fieldToColorBy) # Grab data tmpFileName = path + '__.png' self.view.ScalarRange = dataRange self.view.LockBounds = 1 self.view.StartCaptureValues() simple.SaveScreenshot(tmpFileName, self.view) self.view.StopCaptureValues() 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 = vtkFloatArray() rawArray.SetNumberOfTuples(arraySize) minValue = 10000.0 maxValue = -100000.0 delta = (dataRange[1] - dataRange[0]) / 16777215.0 # 2^24 - 1 => 16,777,215 for idx in range(arraySize): rgb = rgbArray.GetTuple3(idx) if rgb[0] != 0 or rgb[1] != 0 or rgb[2] != 0: value = dataRange[0] + delta * float(rgb[0]*65536 + rgb[1]*256 + rgb[2] - 1) rawArray.SetTuple1(idx, value) minValue = min(value, minValue) maxValue = max(value, maxValue) else: rawArray.SetTuple1(idx, float('NaN')) # print ('Array bounds', minValue, maxValue, 'compare to', dataRange) with open(path, 'wb') as f: f.write(buffer(rawArray)) # Delete temporary file if self.cleanAfterMe: os.remove(tmpFileName) # Remove representation from view simple.Hide(source, self.view) return realRange
def writeData(self, time=0): if not self.dataHandler.can_write: return currentScene = []; for data in self.config['scene']: currentData = { 'name': data['name'], 'fields': {} } currentScene.append(currentData) if self.surfaceExtract: self.merge.Input = data['source'] else: self.merge = simple.MergeBlocks(Input=data['source'], MergePoints=0) self.surfaceExtract = simple.ExtractSurface(Input=self.merge) # Extract surface self.surfaceExtract.UpdatePipeline(time) ds = self.surfaceExtract.SMProxy.GetClientSideObject().GetOutputDataObject(0) originalDS = data['source'].SMProxy.GetClientSideObject().GetOutputDataObject(0) originalPoints = ds.GetPoints() # Points points = vtkFloatArray() nbPoints = originalPoints.GetNumberOfPoints() points.SetNumberOfComponents(3) points.SetNumberOfTuples(nbPoints) for idx in range(nbPoints): coord = originalPoints.GetPoint(idx) points.SetTuple3(idx, coord[0], coord[1], coord[2]) pBuffer = buffer(points) pMd5 = hashlib.md5(pBuffer).hexdigest() pPath = os.path.join(self.dataHandler.getBasePath(), 'points',"%s.Float32Array" % pMd5) currentData['points'] = 'points/%s.Float32Array' % pMd5 with open(pPath, 'wb') as f: f.write(pBuffer) # Polys poly = ds.GetPolys() nbCells = poly.GetNumberOfCells() cellLocation = 0 idList = vtkIdList() topo = vtkTypeUInt32Array() topo.Allocate(poly.GetData().GetNumberOfTuples()) for cellIdx in range(nbCells): poly.GetCell(cellLocation, idList) cellSize = idList.GetNumberOfIds() cellLocation += cellSize + 1 if cellSize == 3: topo.InsertNextValue(idList.GetId(0)) topo.InsertNextValue(idList.GetId(1)) topo.InsertNextValue(idList.GetId(2)) elif cellSize == 4: topo.InsertNextValue(idList.GetId(0)) topo.InsertNextValue(idList.GetId(1)) topo.InsertNextValue(idList.GetId(3)) topo.InsertNextValue(idList.GetId(1)) topo.InsertNextValue(idList.GetId(2)) topo.InsertNextValue(idList.GetId(3)) else: print ("Cell size of", cellSize, "not supported") iBuffer = buffer(topo) iMd5 = hashlib.md5(iBuffer).hexdigest() iPath = os.path.join(self.dataHandler.getBasePath(), 'index',"%s.Uint32Array" % iMd5) currentData['index'] = 'index/%s.Uint32Array' % iMd5 with open(iPath, 'wb') as f: f.write(iBuffer) # Grow object side self.objSize[data['name']]['points'] = max(self.objSize[data['name']]['points'], nbPoints) self.objSize[data['name']]['index'] = max(self.objSize[data['name']]['index'], topo.GetNumberOfTuples()) # Colors / FIXME for fieldName, fieldInfo in iteritems(data['colors']): array = ds.GetPointData().GetArray(fieldName) tupleSize = array.GetNumberOfComponents() arraySize = array.GetNumberOfTuples() outputField = vtkFloatArray() outputField.SetNumberOfTuples(arraySize) if tupleSize == 1: for i in range(arraySize): outputField.SetValue(i, array.GetValue(i)) else: # compute magnitude tupleIdxs = range(tupleSize) for i in range(arraySize): magnitude = 0 for j in tupleIdxs: magnitude += math.pow(array.GetValue(i * tupleSize + j), 2) outputField.SetValue(i, math.sqrt(magnitude)) fBuffer = buffer(outputField) fMd5 = hashlib.md5(fBuffer).hexdigest() fPath = os.path.join(self.dataHandler.getBasePath(), 'fields',"%s_%s.Float32Array" % (fieldName, fMd5)) with open(fPath, 'wb') as f: f.write(fBuffer) currentData['fields'][fieldName] = 'fields/%s_%s.Float32Array' % (fieldName, fMd5) # Write scene with open(self.dataHandler.getDataAbsoluteFilePath('scene'), 'w') as f: f.write(json.dumps(currentScene, indent=2))
def writeData(self, time=0): if not self.dataHandler.can_write: return currentScene = []; for data in self.config['scene']: currentData = { 'name': data['name'], 'fields': {}, 'cells': {} } currentScene.append(currentData) if self.surfaceExtract: self.merge.Input = data['source'] else: self.merge = simple.MergeBlocks(Input=data['source'], MergePoints=0) self.surfaceExtract = simple.ExtractSurface(Input=self.merge) # Extract surface self.surfaceExtract.UpdatePipeline(time) ds = self.surfaceExtract.SMProxy.GetClientSideObject().GetOutputDataObject(0) originalDS = data['source'].SMProxy.GetClientSideObject().GetOutputDataObject(0) originalPoints = ds.GetPoints() # Points points = vtkFloatArray() nbPoints = originalPoints.GetNumberOfPoints() points.SetNumberOfComponents(3) points.SetNumberOfTuples(nbPoints) for idx in range(nbPoints): coord = originalPoints.GetPoint(idx) points.SetTuple3(idx, coord[0], coord[1], coord[2]) pBuffer = buffer(points) pMd5 = hashlib.md5(pBuffer).hexdigest() pPath = os.path.join(self.dataHandler.getBasePath(), 'data',"%s.Float32Array" % pMd5) currentData['points'] = 'data/%s.Float32Array' % pMd5 with open(pPath, 'wb') as f: f.write(pBuffer) # Handle cells writeCellArray(self.dataHandler, currentData['cells'], 'verts', ds.GetVerts().GetData()) writeCellArray(self.dataHandler, currentData['cells'], 'lines', ds.GetLines().GetData()) writeCellArray(self.dataHandler, currentData['cells'], 'polys', ds.GetPolys().GetData()) writeCellArray(self.dataHandler, currentData['cells'], 'strips', ds.GetStrips().GetData()) # Fields for fieldName, fieldInfo in iteritems(data['colors']): array = None if 'constant' in fieldInfo: currentData['fields'][fieldName] = fieldInfo continue elif 'POINT_DATA' in fieldInfo['location']: array = ds.GetPointData().GetArray(fieldName) elif 'CELL_DATA' in fieldInfo['location']: array = ds.GetCellData().GetArray(fieldName) jsType = jsMapping[arrayTypesMapping[array.GetDataType()]] arrayRange = array.GetRange(-1) tupleSize = array.GetNumberOfComponents() arraySize = array.GetNumberOfTuples() if tupleSize == 1: outputField = array else: # compute magnitude outputField = array.NewInstance() outputField.SetNumberOfTuples(arraySize) tupleIdxs = range(tupleSize) for i in range(arraySize): magnitude = 0 for j in tupleIdxs: magnitude += math.pow(array.GetValue(i * tupleSize + j), 2) outputField.SetValue(i, math.sqrt(magnitude)) fBuffer = buffer(outputField) fMd5 = hashlib.md5(fBuffer).hexdigest() fPath = os.path.join(self.dataHandler.getBasePath(), 'data',"%s_%s.%s" % (fieldName, fMd5, jsType)) with open(fPath, 'wb') as f: f.write(fBuffer) currentRange = self.ranges[fieldName] if currentRange[1] < currentRange[0]: currentRange[0] = arrayRange[0]; currentRange[1] = arrayRange[1]; else: currentRange[0] = arrayRange[0] if arrayRange[0] < currentRange[0] else currentRange[0]; currentRange[1] = arrayRange[1] if arrayRange[1] > currentRange[1] else currentRange[1]; currentData['fields'][fieldName] = { 'array' : 'data/%s_%s.%s' % (fieldName, fMd5, jsType), 'location': fieldInfo['location'], 'range': outputField.GetRange() } # Write scene with open(self.dataHandler.getDataAbsoluteFilePath('scene'), 'w') as f: f.write(json.dumps(currentScene, indent=4))
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