Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 7th, 2012  |  syntax: None  |  size: 9.51 KB  |  hits: 13  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Windows.Media;
  6. using System.Windows.Media.Imaging;
  7.  
  8. namespace OpenCVFaceDetector
  9. {
  10.     class DllPaths
  11.     {
  12.         public const string KERNEL32_DLL_PATH = "kernel32.dll";
  13.         public const string OPENCV_CORE_DLL_PATH = "opencv_core230.dll";
  14.         public const string OPENCV_OBJDETECT_DLL_PATH = "opencv_objdetect230.dll";
  15.     }
  16.  
  17.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  18.     public struct IplImage
  19.     {
  20.         public int nSize;
  21.         public int ID;
  22.         public int nChannels;
  23.         public int alphaChannel;
  24.         public int depth;
  25.         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
  26.         public string colorModel;
  27.         [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
  28.         public string channelSeq;
  29.         public int dataOrder;
  30.         public int origin;
  31.         public int align;
  32.         public int width;
  33.         public int height;
  34.         public System.IntPtr roi;
  35.         public System.IntPtr maskROI;
  36.         public System.IntPtr imageId;
  37.         public System.IntPtr tileInfo;
  38.         public int imageSize;
  39.         public System.IntPtr imageData;
  40.         public int widthStep;
  41.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.I4)]
  42.         public int[] BorderMode;
  43.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.I4)]
  44.         public int[] BorderConst;
  45.         public System.IntPtr imageDataOrigin;
  46.     }
  47.  
  48.     [StructLayout(LayoutKind.Sequential)]
  49.     public struct CvSize
  50.     {
  51.         public int width;
  52.         public int height;
  53.  
  54.         public CvSize(int width, int height) { this.width = width; this.height = height; }
  55.     }
  56.  
  57.     [StructLayout(LayoutKind.Sequential)]
  58.     public struct CvRect
  59.     {
  60.         public int x;
  61.         public int y;
  62.         public int width;
  63.         public int height;
  64.     }
  65.  
  66.     public class NativeMethods
  67.     {
  68.         [DllImport(DllPaths.KERNEL32_DLL_PATH, SetLastError = true)]
  69.         public static extern IntPtr LoadLibrary(string dllToLoad);
  70.  
  71.         [DllImport(DllPaths.KERNEL32_DLL_PATH, SetLastError=true)]
  72.         public static extern bool FreeLibrary(IntPtr hModule);
  73.  
  74.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvCreateImage", CallingConvention = CallingConvention.Cdecl)]
  75.         public static extern IntPtr cvCreateImage(CvSize size, int depth, int channels);
  76.  
  77.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvReleaseImage", CallingConvention = CallingConvention.Cdecl)]
  78.         public static extern void cvReleaseImage(ref IntPtr image);
  79.  
  80.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvLoad", CallingConvention = CallingConvention.Cdecl)]
  81.         public static extern IntPtr cvLoad([In][MarshalAs(UnmanagedType.LPStr)]string filename, IntPtr storage, IntPtr name,
  82.             IntPtr real_name);
  83.  
  84.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvCreateMemStorage", CallingConvention = CallingConvention.Cdecl)]
  85.         public static extern IntPtr cvCreateMemStorage(int block_size = 0);
  86.  
  87.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvClearMemStorage", CallingConvention = CallingConvention.Cdecl)]
  88.         public static extern IntPtr cvClearMemStorage(IntPtr memory_storage);
  89.  
  90.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvReleaseMemStorage", CallingConvention = CallingConvention.Cdecl)]
  91.         public static extern void cvReleaseMemStorage(ref IntPtr storage);
  92.  
  93.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvGetSeqElem", CallingConvention = CallingConvention.Cdecl)]
  94.         public static extern IntPtr cvGetSeqElem(IntPtr sequence, int index);
  95.        
  96.         [DllImport(DllPaths.OPENCV_CORE_DLL_PATH, EntryPoint = "cvSeqPopFront", CallingConvention = CallingConvention.Cdecl)]
  97.         public static extern IntPtr cvSeqPopFront(IntPtr sequence, IntPtr dest);
  98.  
  99.         [DllImport(DllPaths.OPENCV_OBJDETECT_DLL_PATH, EntryPoint = "cvReleaseHaarClassifierCascade", CallingConvention =
  100.             CallingConvention.Cdecl)]
  101.         public static extern void cvReleaseHaarClassifierCascade(ref IntPtr cascade);
  102.  
  103.         [DllImport(DllPaths.OPENCV_OBJDETECT_DLL_PATH, EntryPoint = "cvHaarDetectObjects", CallingConvention = CallingConvention.Cdecl)]
  104.         public static extern IntPtr cvHaarDetectObjects(IntPtr image, IntPtr cascade, IntPtr mem_storage,
  105.             double scale_factor, int min_neighbours, int flags,
  106.             CvSize min_size, CvSize max_size);
  107.     }
  108.  
  109.     class IntelImage : IDisposable
  110.     {        
  111.         IntPtr iplImagePointer;
  112.         IplImage iplImageStruct;
  113.        
  114.         public IntelImage(int width, int height, bool color = true)
  115.         {
  116.             iplImagePointer = NativeMethods.cvCreateImage(new CvSize() { width = width, height = height }, 8, color ? 3 : 1);
  117.             iplImageStruct = (IplImage)Marshal.PtrToStructure(iplImagePointer, typeof(IplImage));
  118.         }
  119.  
  120.         public void CopyPixels(byte[] sourcePixelBuffer, int startIndex = 0)
  121.         {
  122.             Marshal.Copy(sourcePixelBuffer, startIndex, iplImageStruct.imageData, sourcePixelBuffer.Length);
  123.         }
  124.  
  125.         public int Stride { get{return iplImageStruct.widthStep;} }
  126.  
  127.         public IntPtr IplImage()
  128.         {
  129.             return iplImagePointer;
  130.         }
  131.  
  132.         public void Dispose()
  133.         {
  134.             NativeMethods.cvReleaseImage(ref iplImagePointer);
  135.             GC.SuppressFinalize(this);
  136.         }
  137.  
  138.         ~IntelImage()
  139.         {
  140.             Dispose();
  141.         }
  142.     }
  143.  
  144.     class HaarClassifier : IDisposable
  145.     {
  146.         IntPtr dllHandle, haarCascade, memoryStorage;
  147.        
  148.         void LoadObjDetectDll()
  149.         {
  150.             dllHandle = NativeMethods.LoadLibrary(DllPaths.OPENCV_OBJDETECT_DLL_PATH);
  151.             if (dllHandle == IntPtr.Zero) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
  152.         }
  153.  
  154.         public HaarClassifier(string cascadeFilePath)
  155.         {
  156.             LoadObjDetectDll(); // this is a workaround, leave it be
  157.             haarCascade = NativeMethods.cvLoad(cascadeFilePath, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
  158.             memoryStorage = NativeMethods.cvCreateMemStorage();
  159.         }
  160.  
  161.         [Flags]
  162.         public enum DetectionFlags : int
  163.         {
  164.             None = 0,
  165.             DoCannyPruning = 1,
  166.             ScaleImage = 2,
  167.             FindBiggestObject = 4,
  168.             DoRoughSearch = 8
  169.         }
  170.  
  171.         public LinkedList<CvRect> DetectObjects(IntelImage sourceImage, double scaleFactor = 1.1, int minNeighbours = 3,
  172.             DetectionFlags flags = DetectionFlags.None, CvSize minSize = default(CvSize), CvSize maxSize = default(CvSize))
  173.         {
  174.             NativeMethods.cvClearMemStorage(memoryStorage);
  175.             LinkedList<CvRect> result = new LinkedList<CvRect>();
  176.             IntPtr faceSequence = NativeMethods.cvHaarDetectObjects(sourceImage.IplImage(), haarCascade, memoryStorage,
  177.                 scaleFactor, minNeighbours, (int)flags, minSize, maxSize);
  178.             for (;;)
  179.             {
  180.                 IntPtr faceRectPointer = NativeMethods.cvGetSeqElem(faceSequence, 0);
  181.                 if (faceRectPointer == IntPtr.Zero) break;
  182.                 NativeMethods.cvSeqPopFront(faceSequence, IntPtr.Zero); // TODO: merge with cvGetSeqElem
  183.                 result.AddFirst((CvRect)Marshal.PtrToStructure(faceRectPointer, typeof(CvRect)));
  184.             }
  185.             return result;
  186.         }
  187.  
  188.         public void Dispose()
  189.         {
  190.             NativeMethods.cvReleaseMemStorage(ref memoryStorage);
  191.             NativeMethods.cvReleaseHaarClassifierCascade(ref haarCascade);
  192.             NativeMethods.FreeLibrary(dllHandle);
  193.             GC.SuppressFinalize(this);
  194.         }
  195.  
  196.         ~HaarClassifier()
  197.         {
  198.             Dispose();
  199.         }
  200.     }
  201.  
  202.     class Program
  203.     {
  204.         static BitmapSource CreateBitmapSourceFromFile(string filePath, PixelFormat targetPixelFormat)
  205.         {
  206.             using (var fileStream = new FileStream(filePath, FileMode.Open))
  207.             {
  208.                 var decoder = BitmapDecoder.Create(fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
  209.                 return new FormatConvertedBitmap(decoder.Frames[0], targetPixelFormat, null, 0);
  210.             }
  211.         }
  212.  
  213.         static IntelImage CreateIntelImageFromBitmapSource(BitmapSource bitmapSource)
  214.         {
  215.             var intelImage = new IntelImage(bitmapSource.PixelWidth, bitmapSource.PixelHeight, bitmapSource.Format != PixelFormats.Gray8);
  216.             byte[] pixelBuffer = new byte[bitmapSource.PixelHeight * intelImage.Stride];
  217.             bitmapSource.CopyPixels(pixelBuffer, intelImage.Stride, 0);
  218.             intelImage.CopyPixels(pixelBuffer);
  219.             return intelImage;
  220.         }
  221.  
  222.         static IntelImage CreateIntelImageFromFile(string filePath, bool convertToGrayscale = false)
  223.         {
  224.             var bitmapSource = CreateBitmapSourceFromFile(filePath, convertToGrayscale ? PixelFormats.Gray8 : PixelFormats.Bgr24);
  225.             return CreateIntelImageFromBitmapSource(bitmapSource);
  226.         }
  227.  
  228.         static void Main(string[] args)
  229.         {
  230.             var image = CreateIntelImageFromFile("myface.jpg");
  231.             var haar = new HaarClassifier("haarcascade_frontalface_alt2.xml"); // get it from opencv/data/haarcascades
  232.             var faces = haar.DetectObjects(image);
  233.             foreach(var faceRect in faces)
  234.             {
  235.                 Console.WriteLine("Face detected: {0}, {1} - {2}, {3}", faceRect.x, faceRect.y,
  236.                     faceRect.x + faceRect.width, faceRect.y + faceRect.height);
  237.             }
  238.         }
  239.     }
  240. }