Beispiel #1
0
        /// <summary>
        /// Returns the brightness of each pixel, storing their quantity of incidence into a 256-item array.
        /// Each index holds the number of pixels whose brightness was the index.
        /// Useful for quickly calculating median, mode, etc
        /// </summary>
        /// <param name="bitmap">The input bitmap</param>
        /// <returns>The array of quantities of indicence per brightness level, in pixels</returns>
        private int[] GetBrightnessSamples(Bitmap bitmap)
        {
            // Begin with an array of 0 for each brightness value
            int[] outputArray = new int[256];

            Array.Clear(outputArray, 0, 256);

            // Scan through all the pixels of the bitmap
            BitmapData imageData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            unsafe
            {
                // For each pixel of 'brightness', increment outputArray[brightness]
                for (uint *pixel = (uint *)imageData.Scan0.ToPointer(), lastPixel = &pixel[imageData.Height * imageData.Stride / 4];
                     pixel < lastPixel;
                     ++pixel)
                {
                    int brightness = ImageMath.Max((byte)(*pixel >> 16), (byte)(*pixel >> 8), (byte)*pixel);

                    ++outputArray[brightness];
                }
            }

            bitmap.UnlockBits(imageData);

            return(outputArray);
        }
            /// <summary>
            /// Calculates the similarity between this point and either 1 or 2 previous points representing a line segment
            /// This function decides how appropriately this point would fit into a path joining 'point'
            /// Comparison factors include: thickness of this valley compared to the last, valley colour, relative directions of the valleys
            /// </summary>
            /// <param name="point">Point to compare with</param>
            /// <param name="previousPoint">Point prior to 'point', if applicable</param>
            /// <returns>A floating-point similarity value between 0 and 1 where 1 is virtually identical</returns>
            public SimilarityPack CalculateSimilarity(EdgePoint point, EdgePoint previousPoint = null)
            {
                SimilarityPack similarity = new SimilarityPack()
                {
                    Colour    = ImageMath.PixelDifference(ColourUnderPoint, point.ColourUnderPoint),
                    Direction = 1.0f,
                    Length    = 1.0f,
                    Width     = 1.0f,
                    Distance  = 1.0f,
                };

                if (previousPoint != null)
                {
                    Vector2 previousVector = new Vector2(point.X - previousPoint.X, point.Y - previousPoint.Y);
                    Vector2 currentVector  = new Vector2(X - point.X, Y - point.Y);

                    if (previousVector.LengthSquared() > 0 && currentVector.LengthSquared() > 0)
                    {
                        // Direction similarity: Use the dot product of the normalised segment vectors
                        similarity.Direction = Vector2.Dot(previousVector / previousVector.Length(), currentVector / currentVector.Length());

                        // Length similarity: Use the smaller length divided by the bigger length.....?
                        similarity.Length = previousVector.Length() / currentVector.Length();

                        if (similarity.Length > 1.0f)
                        {
                            similarity.Length = 1.0f / similarity.Length; // swap the division operands lazily
                        }
                    }
                }

                if (point.LastPoint != null && LastPoint != null)
                {
                    // Width similarity: Use the smaller width divided by the bigger width?
                    similarity.Width = Vector2.Distance(new Vector2(X, Y), new Vector2(LastPoint.X, LastPoint.Y)) /
                                       Vector2.Distance(new Vector2(point.X, point.Y), new Vector2(point.LastPoint.X, point.LastPoint.Y));

                    if (similarity.Width > 1.0f)
                    {
                        similarity.Width = 1.0f / similarity.Width;
                    }
                }

                if (previousPoint == null)
                {
                    float distanceToPoint = Vector2.Distance(new Vector2(X, Y), new Vector2(point.X, point.Y));
                    similarity.Distance = distanceToPoint > 0 ? 1.0f / distanceToPoint : 1.0f;
                }

                return(similarity);
            }
Beispiel #3
0
        public override void Apply(ref Bitmap bitmap, out Highlighter[] highlighters)
        {
            Bitmap outputBitmap = new Bitmap(bitmap);

            BitmapData imageData       = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            BitmapData outputImageData = outputBitmap.LockBits(new Rectangle(0, 0, outputBitmap.Width, outputBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

            unsafe
            {
                // Welcome back to unsafe-land, home of C++ and myself
                uint *pixels       = (uint *)imageData.Scan0.ToPointer();
                uint *outputPixels = (uint *)outputImageData.Scan0.ToPointer();

                for (int baseY = 0; baseY < bitmap.Height - PixelRadius; ++baseY)
                {
                    uint *pixelRow = &pixels[baseY * imageData.Stride / 4];
                    byte *pixelBs = (byte *)pixelRow, pixelGs = (byte *)&pixelRow[1], pixelRs = (byte *)&pixelRow[2];

                    for (int baseX = 0; baseX < bitmap.Width - PixelRadius; ++baseX)
                    {
                        byte curR = pixelRs[baseX << 2], curG = pixelGs[baseX << 2], curB = pixelBs[baseX << 2];
                        int  rMin = 255, gMin = 255, bMin = 255;
                        int  rMax = 0, gMax = 0, bMax = 0;

                        // Search the radius around this pixel and track the difference
                        for (int y = 0; y <= PixelRadius; ++y)
                        {
                            byte *subBs = &pixelBs[(y * imageData.Stride) + (baseX << 2)], subGs = &subBs[1], subRs = &subBs[2];

                            for (int x = 0; x <= PixelRadius; ++x)
                            {
                                // Compare red
                                // TODO is there a cleaner way to do this?
                                if (subRs[x << 2] < rMin)
                                {
                                    rMin = subRs[x << 2];
                                }
                                if (subGs[x << 2] < gMin)
                                {
                                    gMin = subGs[x << 2];
                                }
                                if (subBs[x << 2] < bMin)
                                {
                                    bMin = subBs[x << 2];
                                }
                                if (subRs[x << 2] > rMax)
                                {
                                    rMax = subRs[x << 2];
                                }
                                if (subGs[x << 2] > gMax)
                                {
                                    gMax = subGs[x << 2];
                                }
                                if (subBs[x << 2] > bMax)
                                {
                                    bMax = subBs[x << 2];
                                }
                            }
                        }

                        // Write the difference to the output
                        outputPixels[baseY * outputImageData.Stride / 4 + baseX] = 0xFF000000 | (uint)((rMax - rMin) << 16 | (gMax - gMin) << 8 | (bMax - bMin));
                        // or the maximum difference of all colour channels..
                        byte maxDiff = ImageMath.Max((byte)(rMax - rMin), (byte)(gMax - gMin), (byte)(bMax - bMin));
                        outputPixels[baseY * outputImageData.Stride / 4 + baseX] = 0xFF000000 | (uint)(maxDiff << 16 | maxDiff << 8 | maxDiff);
                    }
                }
            }

            // Release resources
            bitmap.UnlockBits(imageData);
            outputBitmap.UnlockBits(outputImageData);

            // Copy output data to input data
            bitmap = new Bitmap(outputBitmap); // TODO there is a better way to do this...right?

            // Done!No highlighters to return
            highlighters = null;
        }