Пример #1
0
 internal ImageF(ImageF image)
     : base(
         image.Width,
         image.Height,
         image.BitsPerPixel,
         image.HorizontalResolution,
         image.VerticalResolution,
         image.Transform)
 {
 }
Пример #2
0
        /// <summary>
        /// Calculates the histogram of oriented gradients (HOG) on the <see cref="Image"/>.
        /// </summary>
        /// <param name="cellSize">The cell size, in pixels.</param>
        /// <param name="blockSize">The block size, in number of <paramref name="cellSize"/>.</param>
        /// <param name="blockStride">The block stride size, in number of <paramref name="cellSize"/>.</param>
        /// <param name="numberOfBins">The number of bins (orientations) in the histogram.</param>
        /// <param name="threshold">
        /// The threshold value to apply after normalization.
        /// Bins that are less than the threshold, are set to zero.
        /// </param>
        /// <returns>
        /// The <see cref="DenseVectorPackF"/> that contains packed points of interest.
        /// </returns>
        /// <exception cref="NotSupportedException">
        /// The <see cref="Image{T}.BitsPerPixel"/> is not 1, 8, 24, or 32.
        /// </exception>
        public DenseVectorPackF HOG(
            int cellSize,
            int blockSize,
            int blockStride,
            int numberOfBins,
            float threshold)
        {
            // convert image to float
            ImageF srcf   = PrepareImage();
            int    width  = srcf.Width;
            int    height = srcf.Height;
            int    stride = srcf.Stride;

            float[] bits = srcf.Bits;

            /*if (NativeMethods.hog(
             *  srcf.BitsPerPixel,
             *  srcf.Width,
             *  srcf.Height,
             *  srcf.Stride,
             *  srcf.Bits) != 0)
             * {
             *  throw new OutOfMemoryException();
             * }*/

            // calculate gradient vectors magnitude and direction using Prewitt operator (-1 0 1)
            float[] mag = new float[bits.Length];
            float[] ang = new float[bits.Length];
            NativeMethods.gradientVectorPrewitt_f32(width, height, bits, stride, mag, stride, ang, stride);

            // convert angles to bins
            Mathematics.DivC(ang.Length, (float)(Math.PI / numberOfBins), ang, 0);
            Vectors.Abs(ang.Length, ang, 0);

            // calculate histograms
            int cellCountX = width / cellSize;
            int cellCountY = height / cellSize;

            int blockCountX     = ComputeBlockCount(cellCountX);
            int blockCountY     = ComputeBlockCount(cellCountY);
            int blockCount      = blockCountX * blockCountY;
            int blockSizeInBins = blockSize * blockSize * numberOfBins;

            float[] blocks   = new float[blockCount * blockSizeInBins];
            int     offblock = 0; // running block offset

            // to save memory we allocate histograms needed for one row of blocks only
            // when we move throw the rows, the first histogram (not needed anymore) becomes last (working)
            List <float[]> hist = CreateRotatingHist();

            for (int iy = 0, offy = 0; iy < cellCountY; iy++, offy += stride * cellSize)
            {
                float[] h = hist[Core.MinMax.Min(iy, blockSize - 1)];
                ComputeHistLine(offy, h);

                if (iy + 1 >= blockSize)
                {
                    // calculate blocks - we are at the last block line
                    if (((iy + 1 - blockSize) % blockStride) == 0)
                    {
                        ComputeBlockLine();
                    }

                    // rotate histograms
                    if (blockSize > 1 && iy + 1 < cellCountY)
                    {
                        RotateHist(hist);
                    }
                }
            }

            Debug.Assert(offblock == blocks.Length, "We must have processed all blocks by now.");

            // normalize blocks
            const float Eps = 1e-10f;

            for (int i = 0, off = 0; i < blockCount; i++, off += blockSizeInBins)
            {
                float norm = Vectors.L2Norm(blockSizeInBins, blocks, off);
                Mathematics.DivC(blockSizeInBins, norm + Eps, blocks, off);
            }

            // apply threshold
            if (threshold > 0.0f)
            {
                Vectors.ThresholdLT(blocks.Length, threshold, 0.0f, blocks, 0);
            }

            /*DenseVectorProxyF[] dense = new DenseVectorProxyF[blockCount];
             * for (int i = 0, off = 0; i < blockCount; i++, off += blockSizeInBins)
             * {
             *  dense[i] = new DenseVectorProxyF(blockSizeInBins, blocks, off);
             * }*/

            /*SparseVectorF[] sparse = new SparseVectorF[blockCount];
             * for (int i = 0; i < blockCount; i++)
             * {
             *  sparse[i] = SparseVectorF.FromDense(blockSizeInBins, vectors[i].X, 0);
             * }*/

            return(new DenseVectorPackF(blockCount, blockSizeInBins, blocks));

            ImageF PrepareImage()
            {
                // convert image to 8bpp, then float
                return(this
                       .ConvertTo(null, 8)
                       .Convert8To32f(
                           ComputeImageSize(this.Width),
                           ComputeImageSize(this.Height),
                           BorderType.BorderRepl,
                           0));

                int ComputeImageSize(int size)
                {
                    int kernelSize   = cellSize * blockSize;
                    int kernelStride = cellSize * blockStride;

                    return(Core.MinMax.Max(size - kernelSize, 0).RoundUp(kernelStride) + kernelSize);
                }
            }

            int ComputeBlockCount(int cellCount)
            {
                return((Core.MinMax.Max(cellCount - blockSize, 0) / blockStride) + 1);
            }

            List <float[]> CreateRotatingHist()
            {
                List <float[]> h = new List <float[]>(blockSize);

                for (int i = 0; i < blockSize; i++)
                {
                    h.Add(new float[cellCountX * numberOfBins]);
                }

                return(h);
            }

            void RotateHist(List <float[]> h)
            {
                float[] temp = h[0];
                h.RemoveAt(0);
                h.Add(temp);
                Vectors.Set(temp.Length, 0, temp, 0);
            }

            void ComputeHistLine(int offy, float[] h)
            {
                for (int ix = 0, offx = offy, offh = 0; ix < cellCountX; ix++, offx += cellSize, offh += numberOfBins)
                {
                    for (int iyc = 0, offyc = offx; iyc < cellSize; iyc++, offyc += stride)
                    {
                        for (int ixc = 0, offxc = offyc; ixc < cellSize; ixc++, offxc++)
                        {
                            float value = mag[offxc];
                            if (value != 0.0f)
                            {
                                ////int bin = (int)ang[offxc] % numberOfBins;
                                ////h[offh + bin] += mag[offxc];

                                float angle = ang[offxc];

                                int   bin    = (int)angle;
                                float value1 = value * (angle - bin);

                                h[offh + (bin % numberOfBins)]       += value1;
                                h[offh + ((bin + 1) % numberOfBins)] += value - value1;
                            }
                        }
                    }
                }
            }

            void ComputeBlockLine()
            {
                int blockLengthInBins = blockSize * numberOfBins;
                int blockStrideInBins = blockStride * numberOfBins;

                for (int ix = 0, offh = 0; ix < blockCountX; ix++, offh += blockStrideInBins)
                {
                    for (int iyc = 0; iyc < blockSize; iyc++)
                    {
                        Vectors.Copy(blockLengthInBins, hist[iyc], offh, blocks, offblock);
                        offblock += blockLengthInBins;
                    }
                }
            }
        }