/// <summary> /// Adds the bands from the bands view model. /// </summary> /// <param name="viewModel"></param> public void AddBands(AddLayersDialogViewModel viewModel, IProgress <double> progress) { // Initialize RGB data byte[] bgra = null; Dataset rgbDataSet = null; if (viewModel.AddRgb) { var firstRgbBand = viewModel.Layers.First(b => b.B || b.G || b.R); rgbDataSet = Gdal.Open(firstRgbBand.Path, Access.GA_ReadOnly); bgra = new byte[rgbDataSet.RasterXSize * rgbDataSet.RasterYSize * 4]; } var firstBand = viewModel.Layers.First(); var firstDataSet = Gdal.Open(firstBand.Path, Access.GA_ReadOnly); var builder = Matrix <double> .Build; int totalBands = viewModel.Layers.Count + (viewModel.AddRgb ? 1 : 0); int currentProgress = 0; // Parallel band loading Parallel.ForEach(viewModel.Layers, (currentLayer, _, bandIndex) => { // Load raster var dataSet = Gdal.Open(currentLayer.Path, Access.GA_ReadOnly); var rasterBand = dataSet.GetRasterBand(1); var bitsPerPixel = rasterBand.DataType.ToPixelFormat().BitsPerPixel; int stride = (rasterBand.XSize * bitsPerPixel / 8); IntPtr data = Marshal.AllocHGlobal(stride * rasterBand.YSize); rasterBand.ReadRaster(0, 0, rasterBand.XSize, rasterBand.YSize, data, rasterBand.XSize, rasterBand.YSize, rasterBand.DataType, bitsPerPixel / 8, stride); // Cutoff int minCutValue, maxCutValue; CalculateMinMaxCut(rasterBand, currentLayer.MinCutOff, currentLayer.MaxCutOff, out minCutValue, out maxCutValue); // Apply RGB contrast enhancement if (viewModel.AddRgb && viewModel.RgbContrastEnhancement && (currentLayer.B || currentLayer.G || currentLayer.R)) { int colorOffset = currentLayer.B ? 0 : currentLayer.G ? 1 : currentLayer.R ? 2 : -1; unsafe { // TODO what if layer is not of type uint? ushort *dataPtr = (ushort *)data.ToPointer(); Parallel.ForEach(Partitioner.Create(0, rasterBand.XSize * rasterBand.YSize), (range) => { for (int dataIndex = range.Item1; dataIndex < range.Item2; ++dataIndex) { ushort current = *(dataPtr + dataIndex); byte val = (byte)MoreMath.Clamp((current - minCutValue) / (double)(maxCutValue - minCutValue) * byte.MaxValue, 0, byte.MaxValue - 1); bgra[dataIndex * 4 + colorOffset] = val; bgra[dataIndex * 4 + 3] = 255; } }); } } // Apply band contrast enhancement if (currentLayer.ContrastEnhancement) { data = ApplyContrastEnhancement(rasterBand, data, minCutValue, maxCutValue); } Application.Current.Dispatcher.Invoke(() => { var imageBandViewModel = CreateLayerViewModel(dataSet, rasterBand, stride, data, currentLayer); Layers.AddSorted(imageBandViewModel, Comparer <LayerViewModel> .Create((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal))); progress.Report(++currentProgress); Marshal.FreeHGlobal(data); }); }); // Load rgb image if (viewModel.AddRgb) { // Create RGB image Application.Current.Dispatcher.Invoke(() => { var rgbStride = rgbDataSet.RasterXSize * 4; var rgbImage = BitmapSource.Create(rgbDataSet.RasterXSize, rgbDataSet.RasterYSize, 96, 96, PixelFormats.Bgra32, null, bgra, rgbStride); // Transformation double[] rgbTransform = new double[6]; rgbDataSet.GetGeoTransform(rgbTransform); var vecBuilder = Vector <double> .Build; var upperLeft = vecBuilder.DenseOfArray(new[] { rgbTransform[0], rgbTransform[3], 1 }); var xRes = rgbTransform[1]; var yRes = rgbTransform[5]; var bottomRight = vecBuilder.DenseOfArray(new[] { upperLeft[0] + (rgbDataSet.RasterXSize * xRes), upperLeft[1] + (rgbDataSet.RasterYSize * yRes), 1 }); double[,] matArray = { { rgbTransform[1], rgbTransform[2], rgbTransform[0] }, { rgbTransform[4], rgbTransform[5], rgbTransform[3] }, { 0, 0, 1 } }; var transformMat = builder.DenseOfArray(matArray); var layerViewModel = new LayerViewModel("RGB", SatelliteType.None, null, viewModel.RgbContrastEnhancement, xRes, yRes, new WriteableBitmap(rgbImage), transformMat, upperLeft, bottomRight, 0, 0, false, false, false, true, false, false); Layers.Insert(0, layerViewModel); progress.Report(++currentProgress); }); } // TODO use projection to get correct transformation? double[] transform = new double[6]; firstDataSet.GetGeoTransform(transform); double[,] transformArray = { { 1, transform[2], transform[0] }, { transform[4], -1, transform[3] }, { 0, 0, 1 } }; Messenger.Default.Send(builder.DenseOfArray(transformArray)); WindowEnabled = true; }