/// <summary> /// Creates a histogram texture for 2D transfer functions. /// X-axis = data sample (density) value /// Y-axis = gradient magnitude /// colour = white (if there is a data sample with the specified value and gradient magnitude) or black (if not) /// </summary> /// <param name="dataset"></param> /// <returns></returns> public static Texture2D Generate2DHistogramTexture(VolumeDataset dataset) { float minValue = dataset.GetMinDataValue(); float maxValue = dataset.GetMaxDataValue(); // Value range of the density values. float densityValRange = maxValue - minValue + 1.0f; float densityRangeRecip = 1.0f / (maxValue - minValue); // reciprocal // Clamp density value samples. int numDensitySamples = System.Math.Min((int)densityValRange, 512); int numGradientSamples = 256; Color[] cols = new Color[numDensitySamples * numGradientSamples]; Texture2D texture = new Texture2D(numDensitySamples, numGradientSamples, TextureFormat.RGBAFloat, false); // Zero-initialise colours. for (int iCol = 0; iCol < cols.Length; iCol++) { cols[iCol] = new Color(0.0f, 0.0f, 0.0f, 0.0f); } float maxRange = dataset.GetMaxDataValue() - dataset.GetMinDataValue(); const float maxNormalisedMagnitude = 1.75f; // sqrt(1^2 + 1^2 + 1^2) = swrt(3) = a bit less than 1.75 for (int x = 1; x < dataset.dimX - 1; x++) { for (int y = 1; y < dataset.dimY - 1; y++) { for (int z = 1; z < dataset.dimZ - 1; z++) { int iData = x + y * dataset.dimX + z * (dataset.dimX * dataset.dimY); int density = Mathf.RoundToInt(dataset.data[iData]); // FIXME float x1 = dataset.data[(x + 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; float x2 = dataset.data[(x - 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; float y1 = dataset.data[x + (y + 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; float y2 = dataset.data[x + (y - 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; float z1 = dataset.data[x + y * dataset.dimX + (z + 1) * (dataset.dimX * dataset.dimY)]; float z2 = dataset.data[x + y * dataset.dimX + (z - 1) * (dataset.dimX * dataset.dimY)]; // Calculate gradient Vector3 grad = new Vector3((x2 - x1) / (float)maxRange, (y2 - y1) / (float)maxRange, (z2 - z1) / (float)maxRange); // Calculate density and gradient value indices (in flattened 2D array) float tDensity = (density - minValue) * densityRangeRecip; int iDensity = Mathf.RoundToInt((numDensitySamples - 1) * tDensity); int iGrad = (int)(grad.magnitude * numGradientSamples / maxNormalisedMagnitude); // Assign a white colour to all samples (in a histogram where x = density and y = gradient magnitude). cols[iDensity + iGrad * numDensitySamples] = Color.white; } } } texture.SetPixels(cols); texture.Apply(); return(texture); }
public static Texture2D GenerateHistogramTexture(VolumeDataset dataset) { int minValue = dataset.GetMinDataValue(); int maxValue = dataset.GetMaxDataValue(); int numSamples = maxValue - minValue + 1; int[] values = new int[numSamples]; Color[] cols = new Color[numSamples]; Texture2D texture = new Texture2D(numSamples, 1, TextureFormat.RGBAFloat, false); int maxFreq = 0; for (int iData = 0; iData < dataset.data.Length; iData++) { int dataValue = dataset.data[iData] - minValue; values[dataValue] += 1; maxFreq = System.Math.Max(values[dataValue], maxFreq); } for (int iSample = 0; iSample < numSamples; iSample++) { cols[iSample] = new Color(Mathf.Log10((float)values[iSample]) / Mathf.Log10((float)maxFreq), 0.0f, 0.0f, 1.0f); } texture.SetPixels(cols); texture.Apply(); return(texture); }
/// <summary> /// Generates a histogram where: /// X-axis = the data sample (density) value /// Y-axis = the sample count (number of data samples with the specified density) /// </summary> /// <param name="dataset"></param> /// <returns></returns> public static Texture2D GenerateHistogramTexture(VolumeDataset dataset) { int minValue = dataset.GetMinDataValue(); int maxValue = dataset.GetMaxDataValue(); int numValues = maxValue - minValue + 1; float valRangeRecip = 1.0f / (maxValue - minValue); int numSamples = System.Math.Min(numValues, 1024); int[] values = new int[numSamples]; Color[] cols = new Color[numSamples]; Texture2D texture = new Texture2D(numSamples, 1, TextureFormat.RGBAFloat, false); int maxFreq = 0; for (int iData = 0; iData < dataset.data.Length; iData++) { int dataValue = dataset.data[iData]; float tValue = (dataValue - minValue) * valRangeRecip; int valueIndex = Mathf.RoundToInt((numSamples - 1) * tValue); values[valueIndex] += 1; maxFreq = System.Math.Max(values[valueIndex], maxFreq); } for (int iSample = 0; iSample < numSamples; iSample++) { cols[iSample] = new Color(Mathf.Log10((float)values[iSample]) / Mathf.Log10((float)maxFreq), 0.0f, 0.0f, 1.0f); } texture.SetPixels(cols); texture.Apply(); return(texture); }
/// <summary> /// Generates a histogram (but computaion is done on GPU) where: /// X-axis = the data sample (density) value /// Y-axis = the sample count (number of data samples with the specified density) /// </summary> /// <param name="dataset"></param> /// <returns></returns> public static Texture2D GenerateHistogramTextureOnGPU(VolumeDataset dataset) { double actualBound = dataset.GetMaxDataValue() - dataset.GetMinDataValue() + 1; int numValues = System.Convert.ToInt32(dataset.GetMaxDataValue() - dataset.GetMinDataValue() + 1); // removed +1 int sampleCount = System.Math.Min(numValues, 256); ComputeShader computeHistogram = Resources.Load("ComputeHistogram") as ComputeShader; int handleInitialize = computeHistogram.FindKernel("HistogramInitialize"); int handleMain = computeHistogram.FindKernel("HistogramMain"); ComputeBuffer histogramBuffer = new ComputeBuffer(sampleCount, sizeof(uint) * 1); uint[] histogramData = new uint[sampleCount]; Color32[] histogramCols = new Color32[sampleCount]; Texture3D dataTexture = dataset.GetDataTexture(); if (handleInitialize < 0 || handleMain < 0) { Debug.LogError("Histogram compute shader initialization failed."); } computeHistogram.SetFloat("ValueRange", (float)(numValues - 1)); computeHistogram.SetTexture(handleMain, "VolumeTexture", dataTexture); computeHistogram.SetBuffer(handleMain, "HistogramBuffer", histogramBuffer); computeHistogram.SetBuffer(handleInitialize, "HistogramBuffer", histogramBuffer); computeHistogram.Dispatch(handleInitialize, sampleCount / 8, 1, 1); computeHistogram.Dispatch(handleMain, (dataTexture.width + 7) / 8, (dataTexture.height + 7) / 8, (dataTexture.depth + 7) / 8); histogramBuffer.GetData(histogramData); int maxValue = (int)histogramData.Max(); Texture2D texture = new Texture2D(sampleCount, 1, TextureFormat.RGBA32, false); for (int iSample = 0; iSample < sampleCount; iSample++) { histogramCols[iSample] = new Color(Mathf.Log10((float)histogramData[iSample]) / Mathf.Log10((float)maxValue), 0.0f, 0.0f, 1.0f); } texture.SetPixels32(histogramCols); texture.Apply(); return(texture); }
public static Texture2D Generate2DHistogramTexture(VolumeDataset dataset) { int numSamples = dataset.GetMaxDataValue() + 1; int numGradientSamples = 256; Color[] cols = new Color[numSamples * numGradientSamples]; Texture2D texture = new Texture2D(numSamples, numGradientSamples, TextureFormat.RGBAFloat, false); for (int iCol = 0; iCol < cols.Length; iCol++) { cols[iCol] = new Color(0.0f, 0.0f, 0.0f, 0.0f); } int maxRange = dataset.GetMaxDataValue() - dataset.GetMinDataValue(); const float maxNormalisedMagnitude = 1.75f; // sqrt(1^2 + 1^2 + 1^2) = swrt(3) = a bit less than 1.75 for (int x = 1; x < dataset.dimX - 1; x++) { for (int y = 1; y < dataset.dimY - 1; y++) { for (int z = 1; z < dataset.dimZ - 1; z++) { int iData = x + y * dataset.dimX + z * (dataset.dimX * dataset.dimY); int density = dataset.data[iData]; int x1 = dataset.data[(x + 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; int x2 = dataset.data[(x - 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; int y1 = dataset.data[x + (y + 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; int y2 = dataset.data[x + (y - 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)]; int z1 = dataset.data[x + y * dataset.dimX + (z + 1) * (dataset.dimX * dataset.dimY)]; int z2 = dataset.data[x + y * dataset.dimX + (z - 1) * (dataset.dimX * dataset.dimY)]; Vector3 grad = new Vector3((x2 - x1) / (float)maxRange, (y2 - y1) / (float)maxRange, (z2 - z1) / (float)maxRange); cols[density + (int)(grad.magnitude * numGradientSamples / maxNormalisedMagnitude) * numSamples] = Color.white; } } } texture.SetPixels(cols); texture.Apply(); return(texture); }
/// <summary> /// Generates a histogram where: /// X-axis = the data sample (density) value /// Y-axis = the sample count (number of data samples with the specified density) /// </summary> /// <param name="dataset"></param> /// <returns></returns> public static Texture2D GenerateHistogramTexture(VolumeDataset dataset) { float minValue = dataset.GetMinDataValue(); float maxValue = dataset.GetMaxDataValue(); float valueRange = maxValue - minValue; int numFrequencies = Mathf.Min((int)valueRange, 1024); int[] frequencies = new int[numFrequencies]; int maxFreq = 0; float valRangeRecip = 1.0f / (maxValue - minValue); for (int iData = 0; iData < dataset.data.Length; iData++) { float dataValue = dataset.data[iData]; float tValue = (dataValue - minValue) * valRangeRecip; int freqIndex = (int)(tValue * (numFrequencies - 1)); frequencies[freqIndex] += 1; maxFreq = System.Math.Max(frequencies[freqIndex], maxFreq); } Color[] cols = new Color[numFrequencies]; Texture2D texture = new Texture2D(numFrequencies, 1, TextureFormat.RGBAFloat, false); for (int iSample = 0; iSample < numFrequencies; iSample++) { cols[iSample] = new Color(Mathf.Log10((float)frequencies[iSample]) / Mathf.Log10((float)maxFreq), 0.0f, 0.0f, 1.0f); } texture.SetPixels(cols); //texture.filterMode = FilterMode.Point; texture.Apply(); return(texture); }
public override VolumeDataset Import() { // Check that the file exists if (!File.Exists(filePath)) { Debug.LogError("The file does not exist: " + filePath); return(null); } FileStream fs = new FileStream(filePath, FileMode.Open); BinaryReader reader = new BinaryReader(fs); // Check that the dimension does not exceed the file size long expectedFileSize = (long)(dimX * dimY * dimZ) * GetSampleFormatSize(contentFormat) + skipBytes; if (fs.Length < expectedFileSize) { Debug.LogError($"The dimension({dimX}, {dimY}, {dimZ}) exceeds the file size. Expected file size is {expectedFileSize} bytes, while the actual file size is {fs.Length} bytes"); reader.Close(); fs.Close(); return(null); } VolumeDataset dataset = new VolumeDataset(); dataset.datasetName = Path.GetFileName(filePath); dataset.dimX = dimX; dataset.dimY = dimY; dataset.dimZ = dimZ; // Skip header (if any) if (skipBytes > 0) { reader.ReadBytes(skipBytes); } int uDimension = dimX * dimY * dimZ; dataset.data = new int[uDimension]; // Read the data/sample values for (int i = 0; i < uDimension; i++) { dataset.data[i] = ReadDataValue(reader); } Debug.Log("Loaded dataset in range: " + dataset.GetMinDataValue() + " - " + dataset.GetMaxDataValue()); reader.Close(); fs.Close(); return(dataset); }
public VolumeDataset Import() //fills VolumeDataset object { var extension = Path.GetExtension(filePath); if (!File.Exists(filePath)) { Debug.LogError("The file does not exist: " + filePath); return(null); } fileContentLines = File.ReadLines(filePath).Where(x => x.Trim(' ') != "").ToArray(); fileContentIndex = 0; ReadSystemTitle(); ReadLatticeConstant(); ReadLatticeVectors(); GetVolume(); ReadAtomNames(); ReadAtomSum(); ReadCoordinateSystemType(); ReadCoordinates(); if (isDirect) { cartesiancoordinatebasisCells = ToCartesian(); } ReadDimensions(); dimTotal = dimArray[0] * dimArray[1] * dimArray[2]; nx = dimArray[0]; ny = dimArray[1]; nz = dimArray[2]; // dimensions CalculateDataLines(); ReadGrid(); VolumeDataset dataFiller = new VolumeDataset(); //volume object then gets sent to VolumeObjectFactory dataFiller.datasetName = fileName; dataFiller.filePath = filePath; dataFiller.dimX = nx; dataFiller.dimY = ny; dataFiller.dimZ = nz; dataFiller.volumeScale = (float)(1 / volumeScale); dataFiller.data = new float[dimTotal]; volumeScaledData = new float[dimTotal]; for (int ix = 0; ix < nx; ix++) { for (int iy = 0; iy < ny; iy++) { for (int iz = 0; iz < nz; iz++) { int itr = (iz * nx * ny) + (iy * nx) + ix; volumeScaledData[itr] = (float)dataGrid[itr] * (float)dataFiller.volumeScale * (float)0.036749309; //density * volumescale * e_units } } } for (int i = 0; i < dimTotal; i++) { dataFiller.data[i] = dataGrid[i]; } Debug.Log("Loaded dataset in range: " + dataFiller.GetMinDataValue() + " - " + dataFiller.GetMaxDataValue()); return(dataFiller); }
public override VolumeDataset Import() { VolumeDataset dataset = new VolumeDataset(); dataset.dimX = dimX; dataset.dimY = dimY; dataset.dimZ = dimZ; FileStream fs = new FileStream(filePath, FileMode.Open); BinaryReader reader = new BinaryReader(fs); if (skipBytes > 0) { reader.ReadBytes(skipBytes); } int uDimension = dimX * dimY * dimZ; dataset.data = new int[uDimension]; int val = 0; for (int i = 0; i < uDimension; i++) { switch (contentFormat) { case DataContentFormat.Int8: val = (int)reader.ReadSByte(); break; case DataContentFormat.Int16: val = (int)reader.ReadInt16(); break; case DataContentFormat.Int32: val = (int)reader.ReadInt32(); break; case DataContentFormat.Uint8: val = (int)reader.ReadByte(); break; case DataContentFormat.Uint16: val = (int)reader.ReadUInt16(); break; case DataContentFormat.Uint32: val = (int)reader.ReadUInt32(); break; } dataset.data[i] = val; } Debug.Log("Loaded dataset in range: " + dataset.GetMinDataValue() + " - " + dataset.GetMaxDataValue()); return(dataset); }