Esempio n. 1
0
        /// <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;
        }