//// Copyright Notice 2005 // Paul Kinlan All rights Reserved // Adapted From an Jason Waltman Algorithm using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Imaging; namespace Tiger.Imaging.Filters { public class FishEye: IFilter { private float _curvature; public float Curvature { get { return _curvature; } set { _curvature = value; } } #region IFilter Members public FishEye(float inCurvature) { _curvature = inCurvature; } public Bitmap Apply(Bitmap srcImg) { if(_curvature <= 0.0f) { throw new ArgumentException("Curvature Must Be Set and It Must Be > 0.0f"); } // get source image size int width = srcImg.Width; int height = srcImg.Height; int halfWidth = width / 2; int halfHeight = height / 2; //Obtain the Maxium Size Of the Fish Eye int maxRadius = (int) Math.Min(width, height) / 2; //The S parameter mentioned in Jason Walton Algo. double s = maxRadius / Math.Log(_curvature * maxRadius + 1); PixelFormat fmt = (srcImg.PixelFormat == PixelFormat.Format8bppIndexed) ? PixelFormat.Format8bppIndexed : PixelFormat.Format24bppRgb; // lock source bitmap data BitmapData srcData = srcImg.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, fmt); // create new image Bitmap dstImg = (fmt == PixelFormat.Format8bppIndexed) ? Tiger.Imaging.Image.CreateGrayscaleImage(width, height) : new Bitmap(width, height, fmt); // lock destination bitmap data BitmapData dstData = dstImg.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, fmt); int stride = srcData.Stride; int offset = stride - ((fmt == PixelFormat.Format8bppIndexed) ? width : width * 3); // Perform The Fish Eye Conversion // unsafe { byte* src = (byte*)srcData.Scan0.ToPointer(); byte* dst = (byte*)dstData.Scan0.ToPointer(); byte* p; if (fmt == PixelFormat.Format8bppIndexed) { #region Grayscale for (int y = -1 * halfHeight; y < height - halfHeight; y++) { for (int x = -1 * halfWidth; x < width - halfWidth; x++) { //Get the Current Pixels Polar Co-ordinates double radius = Math.Sqrt(x * x + y * y); double angle = Math.Atan2(y, x); //Check to see if the polar pixel is out of bounds if (radius <= maxRadius) { //Current Pixel is inside the Fish Eye //newRad is the pixel that we want to shift to current pixel based on the fish eye posistion double newRad = (Math.Exp(radius / s) - 1) / _curvature; int newX = (int)(newRad * Math.Cos(angle)); int newY = (int)(newRad * Math.Sin(angle)); newX += halfWidth; newY += halfHeight; p = src + newY * stride + newX; byte* dst2 = dst + (y + halfHeight) * stride + (x + halfWidth); dst2 = p; } else { *dst = src[y * stride + x]; } } dst += offset; } #endregion } else { #region RGB //Start from the middle because point (0,0) in cartesian co-ordinates should not be in the center for (int y = -1 * halfHeight; y < height - halfHeight; y++) { for (int x = -1 * halfWidth; x < width - halfWidth; x++) { //Get the Current Pixels Polar Co-ordinates double radius = Math.Sqrt(x * x + y * y); double angle = Math.Atan2(y , x); //Check to see if the polar pixel is out of bounds if (radius <= maxRadius) { //Current Pixel is inside the Fish Eye //newRad is the pixel that we want to shift to current pixel based on the fish eye posistion double newRad = (Math.Exp(radius/s)-1)/_curvature; //Current Pixels Polar Cordinates Back To Cartesian int newX = (int)(newRad * Math.Cos(angle)); int newY = (int)(newRad * Math.Sin(angle)); newX += halfWidth; newY += halfHeight; //Chage the Pointer to the Src p = src + newY * stride + newX * 3; //Change the Pointer to the destination byte* dst2 = dst + (y + halfHeight) * stride + (x + halfWidth) * 3; dst2[RGB.R] = p[RGB.R]; dst2[RGB.G] = p[RGB.G]; dst2[RGB.B] = p[RGB.B]; } else { //Current Pixel is outside the Fish Eye thus should be output as is p = src + (y + halfHeight) * stride + (x + halfWidth) * 3; //Change the Pointer to the destination byte* dst2 = dst + (y + halfHeight) * stride + (x + halfWidth) * 3; dst2[RGB.R] = p[RGB.R]; dst2[RGB.G] = p[RGB.G]; dst2[RGB.B] = p[RGB.B]; } } } #endregion } } // unlock both images dstImg.UnlockBits(dstData); srcImg.UnlockBits(srcData); return dstImg; } #endregion } }