1 using System; 2 using System.Collections.Generic; 3 using System.Drawing; 4 using System.Drawing.Drawing2D; 5 using System.Drawing.Imaging; 6 using System.Linq; 7 using System.Runtime.InteropServices; 8 using System.Text; 9 10 namespace ArcSoft_Face_Demo_X32 11 { 12 public class ArcSoft_FACE_API 13 { 14 public class FSDK_FACE_SHARE 15 { 16 public static string app_Id_X32 = "3yUbUj1c1YKeRuyW616PU8FB1cgei3sFpyqMRBDQVVo6"; 17 public static string sdk_Key_FD_X32 = "FCVQpXhiCm8GGbYxTVUpEc2yT6evA3stiYN68nDRJ7mG"; 18 public static string sdk_Key_FR_X32 = "FCVQpXhiCm8GGbYxTVUpEc36cVv5iBCyDsTTyHXYWtg8"; 19 20 //public static string app_Id_X64 = "3yUbUj1c1YKeRuyW616PU8F3rDRU6UzazKPvGkEdoYkR"; 21 //public static string sdk_Key_FD_X64 = "FshWfRcQPgrq9YGbmNRA6q7sp1wyGXVgfmwJacKZ1Vtn"; 22 //public static string sdk_Key_FR_X64 = "FshWfRcQPgrq9YGbmNRA6q7zyRD81y9qz9FvhJDdiwdv"; 23 24 public static IntPtr detectEngine = IntPtr.Zero; 25 public static IntPtr recogitionEngine = IntPtr.Zero; 26 27 28 public static int detectSize = 500 * 1024 * 1024; 29 public static int recogitionSize = 500 * 1024 * 1024; 30 31 public static int nScale = 16; 32 public static int nMaxFaceNum = 10; 33 34 35 //人臉矩形框信息 36 public struct MRECT 37 { 38 public int left; //左邊 39 public int top; //上邊 40 public int right; //右邊 41 public int bottom; //下邊 42 } 43 44 //定義圖像格式空間 45 public struct ASVLOFFSCREEN 46 { 47 public int u32PixelArrayFormat; //像素陣列格式 48 public int i32Width; //寬度 49 public int i32Height; //高度 50 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.SysUInt)] 51 public System.IntPtr[] ppu8Plane; //平面 52 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)] 53 public int[] pi32Pitch; //傾斜 54 } 55 56 57 public static byte[] ReadBmpToByte(Bitmap image, ref int width, ref int height, ref int pitch) 58 { 59 //將Bitmap鎖定到系統內存中,得到BitmapData 60 BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 61 //位圖中第一個像素數據的地址。它也能夠當作是位圖中的第一個掃描行 62 IntPtr ptr = data.Scan0; 63 //定義數組長度 64 int soureBitArrayLength = data.Height * Math.Abs(data.Stride); 65 byte[] sourceBitArray = new byte[soureBitArrayLength]; 66 //將bitmap中的內容拷貝到ptr_bgr數組中 67 Marshal.Copy(ptr, sourceBitArray, 0, soureBitArrayLength); width = data.Width; 68 height = data.Height; 69 pitch = Math.Abs(data.Stride); 70 71 int line = width * 3; 72 int bgr_len = line * height; 73 byte[] destBitArray = new byte[bgr_len]; 74 for (int i = 0; i < height; ++i) 75 { 76 Array.Copy(sourceBitArray, i * pitch, destBitArray, i * line, line); 77 } 78 pitch = line; 79 image.UnlockBits(data); 80 return destBitArray; 81 } 82 83 public static Bitmap CutFace(Bitmap srcImage, int StartX, int StartY, int iWidth, int iHeight) 84 { 85 if (srcImage == null) 86 { 87 return null; 88 } 89 int w = srcImage.Width; 90 int h = srcImage.Height; 91 if (StartX >= w || StartY >= h) 92 { 93 return null; 94 } 95 if (StartX + iWidth > w) 96 { 97 iWidth = w - StartX; 98 } 99 if (StartY + iHeight > h) 100 { 101 iHeight = h - StartY; 102 } 103 try 104 { 105 Bitmap bmpOut = new Bitmap(iWidth, iHeight, PixelFormat.Format24bppRgb); 106 Graphics g = Graphics.FromImage(bmpOut); 107 g.DrawImage(srcImage, new Rectangle(0, 0, iWidth, iHeight), new Rectangle(StartX, StartY, iWidth, iHeight), GraphicsUnit.Pixel); 108 g.Dispose(); 109 return bmpOut; 110 } 111 catch 112 { 113 return null; 114 } 115 } 116 117 public static Image DrawRectangleInPicture2(Image bmp, MRECT[] rectArr, Color RectColor, int LineWidth, DashStyle ds) 118 { 119 if (bmp == null) return null; 120 Graphics g = Graphics.FromImage(bmp); 121 Brush brush = new SolidBrush(RectColor); 122 Pen pen = new Pen(brush, LineWidth); 123 pen.DashStyle = ds; 124 for (int i = 0; i < rectArr.Length; i++) 125 { 126 Point p0 = new Point(rectArr[i].left, rectArr[i].top); 127 Point p1 = new Point(rectArr[i].right, rectArr[i].bottom); 128 g.DrawRectangle(pen, new Rectangle(p0.X, p0.Y, Math.Abs(p0.X - p1.X), Math.Abs(p0.Y - p1.Y))); 129 130 } 131 g.Dispose(); 132 return bmp; 133 } 134 135 /// <summary> 136 /// 將一個字節數組轉換爲24位真彩色圖 137 /// </summary> 138 /// <param name="imageArray">字節數組</param> 139 /// <param name="width">圖像的寬度</param> 140 /// <param name="height">圖像的高度</param> 141 /// <returns>位圖對象</returns> 142 public static Bitmap ToGrayBitmap(byte[] imageArray, int width, int height) 143 { 144 145 //將用戶指定的imageArray二維數組轉換爲一維數組rawValues 146 byte[] rawValues = imageArray; 147 //申請目標位圖的變量,並將其內存區域鎖定 148 Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); 149 BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); 150 151 //得到圖像的參數 152 int stride = bmpData.Stride; //掃描線的寬度 153 154 // int offset = stride - width; 轉換爲8位灰度圖時 155 int offset = stride - width * 3; //顯示寬度與掃描線寬度的間隙, 156 //與8位灰度圖不一樣width*3很重要,由於此時一個像素佔3字節 157 158 IntPtr iptr = bmpData.Scan0; //得到 bmpData的內存起始位置 159 int scanBytes = stride * height; //用Stride寬度,表示內存區域的大小 160 161 //下面把原始的顯示大小字節數組轉換爲內存中的實際存放的字節數組 162 int posScan = 0, posReal = 0; //分別設置兩個位置指針指向源數組和目標數組 163 byte[] pixelValues = new byte[scanBytes]; //爲目標數組分配內存 164 165 for (int x = 0; x < height; x++) 166 { 167 for (int y = 0; y < width; y++) 168 { 169 //轉換爲8位灰度圖時 170 //pixelValues[posScan++]=rawValues[posReal++]; 171 //} 172 //posScan+=offset; 173 //此處也與8位灰度圖不一樣,分別對R,G,B份量賦值,R=G=B 174 //posScan也由posScan++變爲posScan+= 3; 175 176 pixelValues[posScan] = pixelValues[posScan + 1] = pixelValues[posScan + 2] = rawValues[posReal++]; 177 posScan += 3; 178 } 179 posScan += offset; //行掃描結束,要將目標位置指針移過那段間隙 180 } 181 182 //// 用Marshal的Copy方法,將剛纔獲得的內存字節數組複製到BitmapData中 183 System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes); 184 bmp.UnlockBits(bmpData); //解鎖內存區域 185 186 ////// --------------------------------------------------------------------------- 187 188 ////下面的代碼是8位灰度索引圖時才須要的,是爲了修改生成位圖的索引表,從僞彩修改成灰度 189 //ColorPalette tempPalette; 190 //using (Bitmap tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) 191 //{ 192 // tempPalette = tempBmp.Palette; 193 //} 194 //for (int i = 0; i < 256; i++) 195 //{ 196 // tempPalette.Entries[i] = Color.FromArgb(i, i, i); 197 //} 198 199 //bmp.Palette = tempPalette; 200 //----------------------------------------------------------------------------- 201 //// 算法到此結束,返回結果 202 return bmp; 203 } 204 205 206 public static Bitmap ToGrayBitmap2(byte[] imageArray, int width, int height) 207 { 208 209 //將用戶指定的imageArray二維數組轉換爲一維數組rawValues 210 byte[] rawValues = imageArray; 211 //申請目標位圖的變量,並將其內存區域鎖定 212 Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); 213 BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); 214 215 //得到圖像的參數 216 int stride = bmpData.Stride; //掃描線的寬度 217 218 // int offset = stride - width; 轉換爲8位灰度圖時 219 int offset = stride - width * 3; //顯示寬度與掃描線寬度的間隙, 220 //與8位灰度圖不一樣width*3很重要,由於此時一個像素佔3字節 221 222 IntPtr iptr = bmpData.Scan0; //得到 bmpData的內存起始位置 223 int scanBytes = stride * height; //用Stride寬度,表示內存區域的大小 224 225 //下面把原始的顯示大小字節數組轉換爲內存中的實際存放的字節數組 226 int posScan = 0, posReal = 0; //分別設置兩個位置指針指向源數組和目標數組 227 byte[] pixelValues = new byte[scanBytes]; //爲目標數組分配內存 228 229 for (int x = 0; x < height; x++) 230 { 231 for (int y = 0; y < width; y++) 232 { 233 //pixelValues[posScan] = pixelValues[posScan + 1] = pixelValues[posScan + 2] = rawValues[posReal++]; 234 235 pixelValues[posScan] = rawValues[posReal++]; 236 pixelValues[posScan + 1] = rawValues[posReal++]; 237 pixelValues[posScan + 2] = rawValues[posReal++]; 238 posScan += 3; 239 } 240 posScan += offset; //行掃描結束,要將目標位置指針移過那段間隙 241 } 242 243 //// 用Marshal的Copy方法,將剛纔獲得的內存字節數組複製到BitmapData中 244 System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes); 245 bmp.UnlockBits(bmpData); //解鎖內存區域 246 247 return bmp; 248 } 249 250 //圖片轉爲base64編碼的文本 251 private string ImgToBase64String(string Imagefilename) 252 { 253 String strbaser64 = ""; 254 try 255 { 256 Bitmap bmp = new Bitmap(Imagefilename); 257 pictureBox1.Image = bmp; 258 //FileStream fs = new FileStream(Imagefilename + ".txt", FileMode.Create); 259 //StreamWriter sw = new StreamWriter(fs); 260 261 MemoryStream ms = new MemoryStream(); 262 bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); 263 byte[] arr = new byte[ms.Length]; 264 ms.Position = 0; 265 ms.Read(arr, 0, (int)ms.Length); 266 ms.Close(); 267 strbaser64 = Convert.ToBase64String(arr); 268 //sw.Write(strbaser64); 269 270 //sw.Close(); 271 //fs.Close(); 272 // MessageBox.Show("轉換成功!"); 273 } 274 catch (Exception ex) 275 { 276 MessageBox.Show("ImgToBase64String 轉換失敗\nException:" + ex.Message); 277 } 278 return strbaser64; 279 } 280 281 282 //base64編碼的文本轉爲圖片 283 private void Base64StringToImage(string txtFileName, PictureBox picbox) 284 { 285 try 286 { 287 FileStream ifs = new FileStream(txtFileName, FileMode.Open, FileAccess.Read); 288 StreamReader sr = new StreamReader(ifs); 289 290 String inputStr = sr.ReadToEnd(); 291 byte[] arr = Convert.FromBase64String(inputStr); 292 MemoryStream ms = new MemoryStream(arr); 293 Bitmap bmp = new Bitmap(ms); 294 295 //bmp.Save(txtFileName + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg); 296 //bmp.Save(txtFileName + ".bmp", ImageFormat.Bmp); 297 //bmp.Save(txtFileName + ".gif", ImageFormat.Gif); 298 //bmp.Save(txtFileName + ".png", ImageFormat.Png); 299 ms.Close(); 300 sr.Close(); 301 ifs.Close(); 302 picbox.Image = bmp; 303 if (File.Exists(txtFileName)) 304 { 305 File.Delete(txtFileName); 306 } 307 //MessageBox.Show("轉換成功!"); 308 } 309 catch (Exception ex) 310 { 311 MessageBox.Show("Base64StringToImage 轉換失敗\nException:" + ex.Message); 312 } 313 } 314 } 315 316 public class FSDK_FACE_DETECTION 317 { 318 //定義SDK版本信息--FD 319 public struct AFD_FSDK_Version 320 { 321 public int lCodebase; //代碼庫版本號 322 public int lMajor; //主版本號 323 public int lMinor; //次版本號 324 public int lBuild; //編譯版本號,遞增 325 public IntPtr Version; //字符串形式的版本號 326 public IntPtr BuildDate; //編譯時間 327 public IntPtr CopyRight; //copyright 328 } 329 330 //定義人臉檢查結果中人臉的角度 331 public enum AFD_FSDK_OrientCode 332 { 333 AFD_FSDK_FOC_0 = 1, 334 AFD_FSDK_FOC_90 = 2, 335 AFD_FSDK_FOC_270 = 3, 336 AFD_FSDK_FOC_180 = 4, 337 AFD_FSDK_FOC_30 = 5, 338 AFD_FSDK_FOC_60 = 6, 339 AFD_FSDK_FOC_120 = 7, 340 AFD_FSDK_FOC_150 = 8, 341 AFD_FSDK_FOC_210 = 9, 342 AFD_FSDK_FOC_240 = 10, 343 AFD_FSDK_FOC_300 = 11, 344 AFD_FSDK_FOC_330 = 12 345 } 346 347 //定義臉部檢查角度的優先級 348 public enum AFD_FSDK_OrientPriority 349 { 350 AFD_FSDK_OPF_0_ONLY = 1, //檢測 0 度方向 351 AFD_FSDK_OPF_90_ONLY = 2, //檢測 90 度方向 352 AFD_FSDK_OPF_270_ONLY = 3, //檢測 270 度方向 353 AFD_FSDK_OPF_180_ONLY = 4, //檢測 180 度方向 354 AFD_FSDK_OPF_0_HIGHER_EXT = 5 //檢測 0, 90, 180, 270 四個方向,0 度更優先 355 } 356 357 //檢測到的臉部信息 358 public struct AFD_FSDK_FACERES 359 { 360 public int nFace; //人臉個數 361 public IntPtr rcFace; //人臉矩形框信息 — MRECT 362 public IntPtr lfaceOrient; //人臉角度信息 — AFD_FSDK_OrientCode 363 } 364 365 /******************************************——ArcSoft Face Detection——******************************/ 366 /* 367 *初始化臉部檢測引擎 368 *函數原形 369 MRESULT AFD_FSDK_InitialFaceEngine( 370 MPChar AppId, 371 MPChar SDKKey, 372 MByte *pMem, 373 MInt32 lMemSize, 374 MHandle *pEngine, 375 AFD_FSDK_OrientPriority iOrientPriority, 376 MInt32 nScale, 377 MInt32 nMaxFaceNum 378 ); 379 AppId [in] 用戶申請 SDK 時獲取的 App Id 380 SDKKey [in] 用戶申請 SDK 時獲取的 SDK Key 381 pMem [in] 分配給引擎使用的內存地址 382 lMemSize [in] 分配給引擎使用的內存大小 383 pEngine [out] 引擎 handle 384 iOrientPriority [in] 指望的臉部檢測角度的優先級 385 nScale [in] 用於數值表示的最小人臉尺寸 有效值範圍[2,50] 推薦值 16 386 nMaxFaceNum [in] 用戶指望引擎最多能檢測出的人臉數 有效值範圍[1,100] 387 */ 388 [DllImport("libarcsoft_fsdk_face_detection.dll", EntryPoint = "AFD_FSDK_InitialFaceEngine", CallingConvention = CallingConvention.Cdecl)] 389 public static extern int AFD_FSDK_InitialFaceEngine(string appId, string sdkKey, IntPtr pMem, int lMemSize, ref IntPtr pEngine, int iOrientPriority, int nScale, int nMaxFaceNum); 390 391 392 /* 393 *根據輸入的圖像檢測出人臉位置,通常用於靜態圖像檢測 394 *函數原形 395 MRESULT AFD_FSDK_StillImageFaceDetection( 396 MHandle hEngine, 397 LPASVLOFFSCREEN pImgData, 398 LPAFD_FSDK_FACERES pFaceRes 399 ); 400 hEngine [in] 引擎 handle 401 pImgData [in] 帶檢測圖像信息 402 pFaceRes [out] 人臉檢測結果 403 */ 404 [DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)] 405 public static extern int AFD_FSDK_StillImageFaceDetection(IntPtr pEngine, IntPtr pImgData, ref IntPtr pFaceRes); 406 407 408 /* 409 *獲取 SDK 版本信息 410 *函數原形 411 const AFD_FSDK_Version * AFD_FSDK_GetVersion( 412 MHandle hEngine 413 ); 414 hEngine [in] 引擎 handle 415 416 */ 417 [DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)] 418 public static extern IntPtr AFD_FSDK_GetVersion(IntPtr pEngine); 419 420 421 /* 422 *銷燬引擎,釋放相應資源 423 *函數原形 424 MRESULT AFD_FSDK_UninitialFaceEngine( 425 MHandle hEngine 426 ); 427 hEngine [in] 引擎 handle 428 */ 429 [DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)] 430 public static extern int AFD_FSDK_UninitialFaceEngine(IntPtr pEngine); 431 /*********************************************************************************************************/ 432 433 } 434 435 436 public class FSDK_FACE_RECOGNITION 437 { 438 public struct AFR_FSDK_VERSION 439 { 440 public int lCodebase; //代碼庫版本號 441 public int lMajor; //主版本號 442 public int lMinor; //次版本號 443 public int lBuild; //編譯版本號,遞增 444 public int lFeatureLevel; //特徵庫版本號 445 public IntPtr Version; //字符串形式的版本號 446 public IntPtr BuildDate; //編譯時間 447 public IntPtr CopyRight; //copyright 448 } 449 450 //臉部信息 451 public struct AFR_FSDK_FACEINPUT 452 { 453 public FSDK_FACE_SHARE.MRECT rcFace; //臉部矩形框信息 — MRECT 454 public int lfaceOrient; //臉部旋轉角度 — AFD_FSDK_OrientCode 455 } 456 457 458 //臉部特徵信息 459 public struct AFR_FSDK_FACEMODEL 460 { 461 public IntPtr pbFeature; //提取到的臉部特徵 462 public int lFeatureSize; //特徵信息長度 463 } 464 465 public Int32 AFD_FSDK_OrientPriority; 466 public Int32 AFD_FSDK_OrientCode; 467 468 /*************************************——ArcSoft Face Recognition——***********************************/ 469 /* 470 *初始化引擎 471 *函數原形 472 MRESULT AFR_FSDK_InitialEngine( 473 MPChar AppId, 474 MPChar SDKKey, 475 Mbyte *pMem, 476 MInt32 lMemSize, 477 MHandle *phEngine 478 ); 479 Appid [in] 用戶申請 SDK 時獲取的 id 480 SDKKey [in] 用戶申請 SDK 時獲取的 id 481 pMem [in] 分配給引擎使用的內存地址 482 lMemSize [in] 分配給引擎使用的內存大小 483 phEngine [out] 引擎 handle 484 */ 485 [DllImport("libarcsoft_fsdk_face_recognition.dll", EntryPoint = "AFR_FSDK_InitialEngine", CallingConvention = CallingConvention.Cdecl)] 486 public static extern int AFR_FSDK_InitialEngine(string appId, string sdkKey, IntPtr pMem, int lMemSize, ref IntPtr pEngine); 487 488 /* 489 *獲取臉部特徵 490 *函數原形 491 MRESULT AFR_FSDK_ExtractFRFeature ( 492 MHandle hEngine, 493 LPASVLOFFSCREEN pInputImage, 494 LPAFR_FSDK_FACEINPUT pFaceRes, 495 LPAFR_FSDK_FACEMODEL pFaceModels 496 ); 497 hEngine [in] 引擎 handle 498 pInputImage [in] 輸入的圖像數據 499 pFaceRes [in] 已檢測到到的臉部信息 500 pFaceModels [out] 提取的臉部特徵信息 501 */ 502 [DllImport("libarcsoft_fsdk_face_recognition.dll", CallingConvention = CallingConvention.Cdecl)] 503 public static extern int AFR_FSDK_ExtractFRFeature(IntPtr pEngine, IntPtr pImgData, IntPtr pFaceRes, IntPtr pFaceModels); 504 505 506 /* 507 *臉部特徵比較 508 *函數原形 509 MRESULT AFR_FSDK_FacePairMatching( 510 MHandle hEngine, 511 AFR_FSDK_FACEMODEL *reffeature, 512 AFR_FSDK_FACEMODEL *probefeature, 513 MFloat *pfSimilScore 514 ); 515 hEngine [in] 引擎 handle 516 reffeature [in] 已有臉部特徵信息 517 probefeature [in] 被比較的臉部特徵信 518 pfSimilScore [out] 類似程度數值 519 */ 520 [DllImport("libarcsoft_fsdk_face_recognition.dll", CallingConvention = CallingConvention.Cdecl)] 521 public static extern int AFR_FSDK_FacePairMatching(IntPtr pEngine, IntPtr reffeature, IntPtr probefeature, ref float pfSimilScore); 522 523 /* 524 *結束引擎 525 *函數原形 526 MRESULT AFR_FSDK_UninitialEngine( 527 MHandle hEngine 528 ); 529 hEngine [in] 引擎 handle 530 */ 531 [DllImport("libarcsoft_fsdk_face_recognition.dll", CallingConvention = CallingConvention.Cdecl)] 532 public static extern int AFR_FSDK_UninitialEngine(IntPtr pEngine); 533 534 /* 535 *獲取 SDK 版本信息 536 *函數原形 537 const AFR_FSDK_VERSION * AFR_FSDK_GetVersion( 538 MHandle hEngine 539 ); 540 hEngine [in] 引擎 handle 541 */ 542 [DllImport("libarcsoft_fsdk_face_recognition.dll", CallingConvention = CallingConvention.Cdecl)] 543 public static extern IntPtr AFR_FSDK_GetVersion(IntPtr pEngine); 544 /*****************************************************************************************************/ 545 } 546 547 } 548 }