/// <summary>
        /// Prepares the result of the operation.
        /// </summary>
        /// <returns>The resulting geometry.</returns>
        protected override ISpectralGeometry PrepareResult()
        {
            Dictionary <Segment, Dictionary <Int32, Int32> > segmentToClassDictionary = new Dictionary <Segment, Dictionary <Int32, Int32> >();
            Dictionary <Int32, Int32> classToIndexDictionary = new Dictionary <Int32, Int32>();

            IRaster referenceRaster = _referenceGeometry.Raster;
            Int32   sourceRowIndex, sourceColumnIndex;

            // map all values (and indices) to segments
            for (Int32 rowIndex = 0; rowIndex < referenceRaster.NumberOfRows; rowIndex++)
            {
                for (Int32 columnIndex = 0; columnIndex < referenceRaster.NumberOfColumns; columnIndex++)
                {
                    Int32 referenceHashCode = 0;

                    switch (referenceRaster.Format)
                    {
                    case RasterFormat.Floating:
                        Double[] referenceFloatValues = referenceRaster.GetFloatValues(rowIndex, columnIndex);
                        if (referenceFloatValues.All(value => value == 0))
                        {
                            continue;
                        }

                        referenceHashCode = referenceFloatValues.Select(value => value.GetHashCode()).Aggregate((x, y) => (x << 1) ^ y);
                        break;

                    case RasterFormat.Integer:

                        UInt32[] referenceValues = referenceRaster.GetValues(rowIndex, columnIndex);
                        if (referenceValues.All(value => value == 0))
                        {
                            continue;
                        }

                        referenceHashCode = referenceValues.Select(value => value.GetHashCode()).Aggregate((x, y) => (x << 1) ^ y);
                        break;
                    }

                    // match the source coordinates
                    if (!referenceRaster.IsMapped || !Source.Raster.IsMapped || Source.Raster.Coordinates.SequenceEqual(referenceRaster.Coordinates))
                    {
                        sourceColumnIndex = columnIndex;
                        sourceRowIndex    = rowIndex;
                    }
                    else
                    {
                        Coordinate coordinate = referenceRaster.Mapper.MapCoordinate(rowIndex, columnIndex);
                        Source.Raster.Mapper.MapRaster(coordinate, out sourceRowIndex, out sourceColumnIndex);
                    }

                    // check if the reference location is available in the source
                    if (sourceRowIndex < 0 || sourceRowIndex >= Source.Raster.NumberOfRows || sourceColumnIndex < 0 || sourceColumnIndex >= Source.Raster.NumberOfColumns)
                    {
                        continue;
                    }

                    Segment segment = _segmentCollection.GetSegment(sourceRowIndex, sourceColumnIndex);

                    // check if the segment was already mapped
                    if (!segmentToClassDictionary.ContainsKey(segment))
                    {
                        segmentToClassDictionary.Add(segment, new Dictionary <Int32, Int32>());
                    }

                    if (!segmentToClassDictionary[segment].ContainsKey(referenceHashCode))
                    {
                        segmentToClassDictionary[segment].Add(referenceHashCode, 0);
                    }

                    segmentToClassDictionary[segment][referenceHashCode]++;

                    if (!classToIndexDictionary.ContainsKey(referenceHashCode))
                    {
                        classToIndexDictionary.Add(referenceHashCode, rowIndex * referenceRaster.NumberOfColumns + columnIndex);
                    }
                }
            }

            _segmentToIndexDictionary = new Dictionary <Segment, Int32>();

            // filter indices for most frequent value
            foreach (Segment segment in segmentToClassDictionary.Keys)
            {
                Int32 maxValueHashCode = 0;

                foreach (Int32 referenceHashCode in segmentToClassDictionary[segment].Keys)
                {
                    if (maxValueHashCode == 0 || segmentToClassDictionary[segment][referenceHashCode] > segmentToClassDictionary[segment][maxValueHashCode])
                    {
                        maxValueHashCode = referenceHashCode;
                    }
                }

                _segmentToIndexDictionary.Add(segment, classToIndexDictionary[maxValueHashCode]);
            }

            SetResultProperties(_referenceGeometry.Raster.Format, _referenceGeometry.Raster.NumberOfBands, Source.Raster.NumberOfRows, Source.Raster.NumberOfColumns, _referenceGeometry.Raster.RadiometricResolution, Source.Raster.Mapper, _referenceGeometry.Presentation, _referenceGeometry.Imaging);

            return(base.PrepareResult());
        }
Пример #2
0
        /// <summary>
        /// This will sample randomly from the raster, preventing duplicates.
        /// If the sampleSize is larger than this raster, this returns all of the values from the raster.
        /// If a "Sample" has been prefetched and stored in the Sample array, then this will return that.
        /// </summary>
        /// <param name="raster">The raster to obtain the values from.</param>
        /// <param name="sampleSize">Number of values to get.</param>
        /// <returns>List of random double values contained in the raster.</returns>
        public static List <double> GetRandomValues(this IRaster raster, int sampleSize)
        {
            if (raster.Sample != null)
            {
                return(raster.Sample.ToList());
            }

            int           numRows = raster.NumRows;
            int           numCols = raster.NumColumns;
            List <double> result  = new List <double>();
            double        noData  = raster.NoDataValue;

            if (numRows * numCols < sampleSize)
            {
                for (int row = 0; row < numRows; row++)
                {
                    for (int col = 0; col < numCols; col++)
                    {
                        double val = raster.Value[row, col];
                        if (val != noData)
                        {
                            result.Add(raster.Value[row, col]);
                        }
                    }
                }

                return(result);
            }

            Random rnd = new Random(DateTime.Now.Millisecond);

            if (numRows * (long)numCols < (long)sampleSize * 5 && numRows * (long)numCols < int.MaxValue)
            {
                // When the raster is only just barely larger than the sample size,
                // we want to prevent lots of repeat guesses that fail (hit the same previously sampled values).
                // We create a copy of all the values and sample from this reservoir while removing sampled values.
                List <double> resi = new List <double>();
                for (int row = 0; row < numRows; row++)
                {
                    for (int col = 0; col < numCols; col++)
                    {
                        double val = raster.Value[row, col];
                        if (val != noData)
                        {
                            resi.Add(val);
                        }
                    }
                }

                // int count = numRows * numCols; // this could failed if there's lot of noDataValues
                long longcount = raster.NumValueCells;
                int  count     = numRows * numCols;
                if (count < int.MaxValue)
                {
                    count = (int)longcount;
                }

                for (int i = 0; i < sampleSize; i++)
                {
                    if (resi.Count == 0)
                    {
                        break;
                    }

                    int indx = rnd.Next(count);
                    result.Add(resi[indx]);
                    resi.RemoveAt(indx);
                    count--;
                }

                raster.Sample = result;
                return(result);
            }

            // Use a HashSet here, because it has O(1) lookup for preventing duplicates
            HashSet <long> exclusiveResults = new HashSet <long>();
            int            remaining        = sampleSize;

            while (remaining > 0)
            {
                int  row   = rnd.Next(numRows);
                int  col   = rnd.Next(numCols);
                long index = (row * numCols) + col;
                if (exclusiveResults.Contains(index))
                {
                    continue;
                }

                exclusiveResults.Add(index);
                remaining--;
            }

            // Sorting is O(n ln(n)), but sorting once is better than using a SortedSet for previous lookups.
            List <long> sorted = exclusiveResults.ToList();

            sorted.Sort();

            // Sorted values are much faster to read than reading values in at random, since the file actually
            // is reading in a whole line at a time. If we can get more than one value from a line, then that
            // is better than getting one value, discarding the cache and then comming back later for the value
            // next to it.
            result = raster.GetValues(sorted);

            raster.Sample = result;
            return(result);
        }
Пример #3
0
 /// <summary>
 /// Returns all spectral values at a specified row and column index.
 /// </summary>
 /// <param name="rowIndex">The zero-based row index of the values.</param>
 /// <param name="columnIndex">The zero-based column index of the values.</param>
 /// <returns>The array containing the spectral values for each band at the specified index.</returns>
 protected override UInt32[] ApplyGetValues(Int32 rowIndex, Int32 columnIndex)
 {
     return(_source.GetValues(_rowIndex + rowIndex, _columnIndex + columnIndex));
 }