tbowers / aforge

Automatically exported from code.google.com/p/aforge
0 stars 0 forks source link

16-bit greyscale/48-bit RGB support in RotateNearestNeighbor.cs #230

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Describe the fix or new feature which you would like to contribute to the 
project ...

Addition of 16-bit greyscale/48-bit RGB support in RotateNearestNeighbor.cs

Provide SVN patch for a code change or source file if it is something new ...

Index: AForge.NET 
Framework-2.1.5/Sources/Imaging/Filters/Transform/RotateNearestNeighbor.cs
===================================================================
--- AForge.NET 
Framework-2.1.5/Sources/Imaging/Filters/Transform/RotateNearestNeighbor.cs  (revi
sion 4360)
+++ AForge.NET 
Framework-2.1.5/Sources/Imaging/Filters/Transform/RotateNearestNeighbor.cs  (revi
sion 4361)
@@ -9,7 +9,6 @@
 {
     using System;
     using System.Collections.Generic;
-    using System.Drawing;
     using System.Drawing.Imaging;

     /// <summary>
@@ -81,6 +80,8 @@
         {
             formatTranslations[PixelFormat.Format8bppIndexed] = PixelFormat.Format8bppIndexed;
             formatTranslations[PixelFormat.Format24bppRgb]    = PixelFormat.Format24bppRgb;
+            formatTranslations[PixelFormat.Format16bppGrayScale] = 
PixelFormat.Format16bppGrayScale;
+            formatTranslations[PixelFormat.Format48bppRgb] = 
PixelFormat.Format48bppRgb;
         }

         /// <summary>
@@ -90,28 +91,52 @@
         /// <param name="sourceData">Source image data.</param>
         /// <param name="destinationData">Destination image data.</param>
         /// 
-        protected override unsafe void ProcessFilter( UnmanagedImage 
sourceData, UnmanagedImage destinationData )
+        protected override void ProcessFilter(UnmanagedImage sourceData, 
UnmanagedImage destinationData)
         {
+            int pixelSize = sourceData.Stride/sourceData.Width;
+            switch (pixelSize)
+            {
+                case 1:
+                case 3:
+                    ProcessFilter8bpc(sourceData, destinationData); break;
+                case 2:
+                case 6:
+                    ProcessFilter16bpc(sourceData, destinationData); break;
+                default:
+                    throw new NotImplementedException();
+            }
+        }
+
+        /// <summary>
+        /// Process the filter on the specified image.
+        /// </summary>
+        /// <remarks>
+        /// This method handles images with 8 bits per channel.
+        /// </remarks>
+        /// <param name="sourceData">Source image data.</param>
+        /// <param name="destinationData">Destination image data.</param>
+        private unsafe void ProcessFilter8bpc(UnmanagedImage sourceData, 
UnmanagedImage destinationData)
+        {
             // get source image size
-            int     width       = sourceData.Width;
-            int     height      = sourceData.Height;
-            double  halfWidth   = (double) width / 2;
-            double  halfHeight  = (double) height / 2;
+            int width = sourceData.Width;
+            int height = sourceData.Height;
+            double halfWidth = (double)width / 2;
+            double halfHeight = (double)height / 2;

             // get destination image size
-            int     newWidth    = destinationData.Width;
-            int     newHeight   = destinationData.Height;
-            double  halfNewWidth    = (double) newWidth / 2;
-            double  halfNewHeight   = (double) newHeight / 2;
+            int newWidth = destinationData.Width;
+            int newHeight = destinationData.Height;
+            double halfNewWidth = (double)newWidth / 2;
+            double halfNewHeight = (double)newHeight / 2;

             // angle's sine and cosine
             double angleRad = -angle * Math.PI / 180;
-            double angleCos = Math.Cos( angleRad );
-            double angleSin = Math.Sin( angleRad );
+            double angleCos = Math.Cos(angleRad);
+            double angleSin = Math.Sin(angleRad);

             int srcStride = sourceData.Stride;
             int dstOffset = destinationData.Stride -
-                ( ( destinationData.PixelFormat == 
PixelFormat.Format8bppIndexed ) ? newWidth : newWidth * 3 );
+                ((destinationData.PixelFormat == 
PixelFormat.Format8bppIndexed) ? newWidth : newWidth * 3);

             // fill values
             byte fillR = fillColor.R;
@@ -119,8 +144,8 @@
             byte fillB = fillColor.B;

             // do the job
-            byte* src = (byte*) sourceData.ImageData.ToPointer( );
-            byte* dst = (byte*) destinationData.ImageData.ToPointer( );
+            byte* src = (byte*)sourceData.ImageData.ToPointer();
+            byte* dst = (byte*)destinationData.ImageData.ToPointer();

             // destination pixel's coordinate relative to image center
             double cx, cy;
@@ -130,21 +155,21 @@
             byte* p;

             // check pixel format
-            if ( destinationData.PixelFormat == PixelFormat.Format8bppIndexed )
+            if (destinationData.PixelFormat == PixelFormat.Format8bppIndexed)
             {
                 // grayscale
                 cy = -halfNewHeight;
-                for ( int y = 0; y < newHeight; y++ )
+                for (int y = 0; y < newHeight; y++)
                 {
                     cx = -halfNewWidth;
-                    for ( int x = 0; x < newWidth; x++, dst++ )
+                    for (int x = 0; x < newWidth; x++, dst++)
                     {
                         // coordinate of the nearest point
-                        ox = (int) (  angleCos * cx + angleSin * cy + 
halfWidth );
-                        oy = (int) ( -angleSin * cx + angleCos * cy + 
halfHeight );
+                        ox = (int)(angleCos * cx + angleSin * cy + halfWidth);
+                        oy = (int)(-angleSin * cx + angleCos * cy + 
halfHeight);

                         // validate source pixel's coordinates
-                        if ( ( ox < 0 ) || ( oy < 0 ) || ( ox >= width ) || ( 
oy >= height ) )
+                        if ((ox < 0) || (oy < 0) || (ox >= width) || (oy >= 
height))
                         {
                             // fill destination image with filler
                             *dst = fillG;
@@ -164,17 +189,17 @@
             {
                 // RGB
                 cy = -halfNewHeight;
-                for ( int y = 0; y < newHeight; y++ )
+                for (int y = 0; y < newHeight; y++)
                 {
                     cx = -halfNewWidth;
-                    for ( int x = 0; x < newWidth; x++, dst += 3 )
+                    for (int x = 0; x < newWidth; x++, dst += 3)
                     {
                         // coordinate of the nearest point
-                        ox = (int) (  angleCos * cx + angleSin * cy + 
halfWidth );
-                        oy = (int) ( -angleSin * cx + angleCos * cy + 
halfHeight );
+                        ox = (int)(angleCos * cx + angleSin * cy + halfWidth);
+                        oy = (int)(-angleSin * cx + angleCos * cy + 
halfHeight);

                         // validate source pixel's coordinates
-                        if ( ( ox < 0 ) || ( oy < 0 ) || ( ox >= width ) || ( 
oy >= height ) )
+                        if ((ox < 0) || (oy < 0) || (ox >= width) || (oy >= 
height))
                         {
                             // fill destination image with filler
                             dst[RGB.R] = fillR;
@@ -197,5 +222,120 @@
                 }
             }
         }
+
+        /// <summary>
+        /// Process the filter on the specified image.
+        /// </summary>
+        /// 
+        /// <param name="sourceData">Source image data.</param>
+        /// <param name="destinationData">Destination image data.</param>
+        /// 
+        private unsafe void ProcessFilter16bpc(UnmanagedImage sourceData, 
UnmanagedImage destinationData)
+        {
+            // get source image size
+            int width = sourceData.Width;
+            int height = sourceData.Height;
+            double halfWidth = (double)width / 2;
+            double halfHeight = (double)height / 2;
+
+            // get destination image size
+            int newWidth = destinationData.Width;
+            int newHeight = destinationData.Height;
+            double halfNewWidth = (double)newWidth / 2;
+            double halfNewHeight = (double)newHeight / 2;
+
+            // angle's sine and cosine
+            double angleRad = -angle * Math.PI / 180;
+            double angleCos = Math.Cos(angleRad);
+            double angleSin = Math.Sin(angleRad);
+
+            int srcStride = sourceData.Stride;
+            int dstOffset = destinationData.Stride -
+                ((destinationData.PixelFormat == 
PixelFormat.Format16bppGrayScale) ? newWidth : newWidth * 6);
+
+            // fill values
+            ushort fillR = (ushort)(fillColor.R << 8);
+            ushort fillG = (ushort)(fillColor.G << 8);
+            ushort fillB = (ushort)(fillColor.B << 8);
+
+            // do the job
+            ushort* src = (ushort*)sourceData.ImageData.ToPointer();
+            ushort* dst = (ushort*)destinationData.ImageData.ToPointer();
+
+            // destination pixel's coordinate relative to image center
+            double cx, cy;
+            // source pixel's coordinates
+            int ox, oy;
+            // temporary pointer
+            ushort* p;
+
+            // check pixel format
+            if (destinationData.PixelFormat == 
PixelFormat.Format16bppGrayScale)
+            {
+                // grayscale
+                cy = -halfNewHeight;
+                for (int y = 0; y < newHeight; y++)
+                {
+                    cx = -halfNewWidth;
+                    for (int x = 0; x < newWidth; x++, dst++)
+                    {
+                        // coordinate of the nearest point
+                        ox = (int)(angleCos * cx + angleSin * cy + halfWidth);
+                        oy = (int)(-angleSin * cx + angleCos * cy + 
halfHeight);
+
+                        // validate source pixel's coordinates
+                        if ((ox < 0) || (oy < 0) || (ox >= width) || (oy >= 
height))
+                        {
+                            // fill destination image with filler
+                            *dst = fillG;
+                        }
+                        else
+                        {
+                            // fill destination image with pixel from source 
image
+                            *dst = src[oy * srcStride + ox];
+                        }
+                        cx++;
+                    }
+                    cy++;
+                    dst += dstOffset;
+                }
+            }
+            else
+            {
+                // RGB
+                cy = -halfNewHeight;
+                for (int y = 0; y < newHeight; y++)
+                {
+                    cx = -halfNewWidth;
+                    for (int x = 0; x < newWidth; x++, dst += 3)
+                    {
+                        // coordinate of the nearest point
+                        ox = (int)(angleCos * cx + angleSin * cy + halfWidth);
+                        oy = (int)(-angleSin * cx + angleCos * cy + 
halfHeight);
+
+                        // validate source pixel's coordinates
+                        if ((ox < 0) || (oy < 0) || (ox >= width) || (oy >= 
height))
+                        {
+                            // fill destination image with filler
+                            dst[RGB.R] = fillR;
+                            dst[RGB.G] = fillG;
+                            dst[RGB.B] = fillB;
+                        }
+                        else
+                        {
+                            // fill destination image with pixel from source 
image
+                            p = src + (oy * srcStride + ox * 6) / 
sizeof(ushort);
+
+                            dst[RGB.R] = p[RGB.R];
+                            dst[RGB.G] = p[RGB.G];
+                            dst[RGB.B] = p[RGB.B];
+                        }
+                        cx++;
+                    }
+                    cy++;
+                    dst += dstOffset;
+                }
+            }
+        }
     }
 }

Original issue reported on code.google.com by yvan.rod...@gmail.com on 21 Jun 2011 at 6:32

Attachments:

GoogleCodeExporter commented 8 years ago
RotateNearestNeighbor image processing routine is extended to support 16 bpp 
grayscale images and 48 bpp color images.

Committed in revision 1534. Will be released in version 2.2.0.

P.S. few issues were fixed in the suggested patch. Please, have a look.
1) pixel size was calculated wrong - stride is not always related to image 
width and can be more than <width>*<bpp>;
2) grayscale version seem to be not tested:
                            *dst = src[oy * srcStride + ox];
if src is ushort*, then indexing is wrong, because srcStride gives number of 
bytes - not width. Try your version on 16bpp gray image - 
AccessViolationException.

Original comment by andrew.k...@gmail.com on 27 Jun 2011 at 9:42

GoogleCodeExporter commented 8 years ago

Original comment by andrew.k...@gmail.com on 28 Jul 2011 at 9:49

GoogleCodeExporter commented 8 years ago

Original comment by andrew.k...@gmail.com on 10 Aug 2011 at 9:39