MainWindow.xaml.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. using System.Windows;
  2. using System.Windows.Forms;
  3. using System.Threading;
  4. using System.IO;
  5. using System.Drawing;
  6. using System.Drawing.Imaging;
  7. using System.Runtime.InteropServices;
  8. using System;
  9. using System.Collections.Concurrent;
  10. using System.Collections.Generic;
  11. using System.Linq;
  12. using System.Runtime.CompilerServices;
  13. using System.Threading.Tasks;
  14. using System.Windows.Threading;
  15. using System.Xml.Serialization;
  16. using Accord.Video.FFMPEG;
  17. using static System.Net.WebRequestMethods;
  18. using AI.Common.Crypto;
  19. namespace AutomaticallyCropImg
  20. {
  21. enum EnumResultImgType
  22. {
  23. OrigImgWithCropRect,
  24. CroppedImg,
  25. BothImgWithCropRectAndCroppedImg,
  26. }
  27. public class ImgInfoForSegEntity
  28. {
  29. /// <summary>
  30. /// 图片ID
  31. /// </summary>
  32. public string ImgId { get; set; } = string.Empty;
  33. /// <summary>
  34. /// 图片路径
  35. /// </summary>
  36. public string ImgLocalPath { get; set; } = string.Empty;
  37. /// <summary>
  38. /// 裁切是否成功
  39. /// </summary>
  40. public bool SegSucceed { get; set; } = false;
  41. /// <summary>
  42. /// 裁切后,图像左上点在原始图像上的像素坐标x
  43. /// </summary>
  44. public int Left { get; set; } = 0;
  45. /// <summary>
  46. /// 裁切后,图像右下点在原始图像上的像素坐标x
  47. /// </summary>
  48. public int Right { get; set; } = 0;
  49. /// <summary>
  50. /// 裁切后,图像左上点在原始图像上的像素坐标y
  51. /// </summary>
  52. public int Top { get; set; } = 0;
  53. /// <summary>
  54. /// 裁切后,图像右下点在原始图像上的像素坐标y
  55. /// </summary>
  56. public int Bottom { get; set; } = 0;
  57. }
  58. public class FileInfosForSeg
  59. {
  60. private string _origFilePath;
  61. private bool _isVideo;
  62. private string _origFolder;
  63. private string _randomId;
  64. public string OrigFilePath { get => _origFilePath; set => _origFilePath = value; }
  65. public bool IsVideo { get => _isVideo; set => _isVideo = value; }
  66. public string OrigFolder { get => _origFolder; set => _origFolder = value; }
  67. public string RandomId { get => _randomId; set => _randomId = value; }
  68. public FileInfosForSeg(string origFilePath, bool isVideo, string origFolder, string randomId)
  69. {
  70. _origFilePath = origFilePath;
  71. _isVideo = isVideo;
  72. _origFolder = origFolder;
  73. _randomId = randomId;
  74. }
  75. }
  76. /// <summary>
  77. /// MainWindow.xaml 的交互逻辑
  78. /// </summary>
  79. public partial class MainWindow : Window
  80. {
  81. private volatile bool _processing = false;
  82. private string _dstFolder = null;
  83. private string _dstTxtFolder = null;
  84. private Dictionary<string, string> _imageFiles = new Dictionary<string, string>();
  85. private Dictionary<string, string> _videoFiles = new Dictionary<string, string>();
  86. private Dictionary<string, string> _cropNameOriNameDict = new Dictionary<string, string>();
  87. private int _sameImgNum = 0;
  88. private static int _processedCount = 0;
  89. private static int _totalCount = 0;
  90. private ConcurrentQueue<FileInfosForSeg> _processingFiles = new ConcurrentQueue<FileInfosForSeg>();
  91. private ConcurrentBag<ImgInfoForSegEntity> _cropResults = new ConcurrentBag<ImgInfoForSegEntity>();
  92. private readonly int _threadCount = Math.Max(1, Environment.ProcessorCount / 2 - 1);
  93. private List<Thread> _processThreads = new List<Thread>();
  94. private Thread _waitThread = null;
  95. private volatile bool _closing = false;
  96. private EnumResultImgType _resulttype;
  97. private bool _saveCropInfo;
  98. private bool _rename;
  99. private string _dataSource = "";
  100. /// <summary>
  101. /// 调用CvCore.dll裁图
  102. /// </summary>
  103. /// <param name="scrImgData"></param>
  104. /// <param name="imgInfoIn"></param>
  105. /// <param name="rectInfoOut">左,上,宽,高</param>
  106. /// <returns></returns>
  107. [DllImport(@"CvCropUltImgRegion.dll", CallingConvention = CallingConvention.Cdecl)]
  108. [return: MarshalAs(UnmanagedType.I1)]
  109. public static extern bool CropImage(IntPtr scrImgData, int[] imgInfoIn, int[] rectInfoOut);
  110. public MainWindow()
  111. {
  112. InitializeComponent();
  113. }
  114. private void OnSelectFolderClick(object sender, RoutedEventArgs e)
  115. {
  116. FolderBrowserDialog srcdialog = new FolderBrowserDialog();
  117. srcdialog.Description = "请选择待裁切图片所在文件夹";
  118. if (srcdialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  119. {
  120. if (string.IsNullOrEmpty(srcdialog.SelectedPath))
  121. {
  122. System.Windows.MessageBox.Show("文件夹路径不能为空", "提示");
  123. return;
  124. }
  125. if (_dstFolder == null)
  126. {
  127. FolderBrowserDialog dstdialog = new FolderBrowserDialog();
  128. dstdialog.Description = "请选择保存裁切结果的文件夹";
  129. if (dstdialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  130. {
  131. if (string.IsNullOrEmpty(dstdialog.SelectedPath))
  132. {
  133. System.Windows.MessageBox.Show("文件夹路径不能为空", "提示");
  134. return;
  135. }
  136. _dstFolder = dstdialog.SelectedPath;
  137. }
  138. FolderBrowserDialog dstdialog2 = new FolderBrowserDialog();
  139. dstdialog.Description = "为后续手动裁切能找到原图,请选择保存裁切结果图像名称和原图名称组成的 cropNameAndOriName.txt 的文件夹";
  140. if (dstdialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  141. {
  142. if (string.IsNullOrEmpty(dstdialog.SelectedPath))
  143. {
  144. System.Windows.MessageBox.Show("文件夹路径不能为空", "提示");
  145. return;
  146. }
  147. _dstTxtFolder = dstdialog.SelectedPath;
  148. }
  149. EnumResultImgType resulttype = new EnumResultImgType();
  150. if ((RadioBtnResultCropped.IsChecked ?? false) && (RadioBtnResultCropRect.IsChecked ?? false))
  151. {
  152. resulttype = EnumResultImgType.BothImgWithCropRectAndCroppedImg;
  153. }
  154. else if (RadioBtnResultCropped.IsChecked ?? false)
  155. {
  156. resulttype = EnumResultImgType.CroppedImg;
  157. }
  158. else if (RadioBtnResultCropRect.IsChecked ?? false)
  159. {
  160. resulttype = EnumResultImgType.OrigImgWithCropRect;
  161. }
  162. else
  163. {
  164. System.Windows.MessageBox.Show("保留裁图框位置信息 和 文件重命名 必须至少选择其中一项", "提示");
  165. return;
  166. }
  167. _resulttype = resulttype;
  168. _saveCropInfo = CheckBoxSaveCropInfo.IsChecked != null && (bool)CheckBoxSaveCropInfo.IsChecked;
  169. _rename = CheckBoxRename.IsChecked != null && (bool)CheckBoxRename.IsChecked;
  170. }
  171. SearchFiles(srcdialog.SelectedPath);
  172. if (_imageFiles.Count > 0 || _videoFiles.Count > 0)
  173. {
  174. System.Windows.MessageBox.Show("共查询到待脱敏的视频:" + _videoFiles.Count +
  175. "个,图像:" + _imageFiles.Count + "张,点击确认后立即开始脱敏,请稍候...", "提示");
  176. foreach (KeyValuePair<string, string> kvp in _imageFiles)
  177. {
  178. string imageFile = kvp.Key;
  179. string randomId = kvp.Value;
  180. var fileInfo = new FileInfosForSeg(imageFile, false, srcdialog.SelectedPath, randomId);
  181. _processingFiles.Enqueue(fileInfo);
  182. }
  183. _totalCount += _imageFiles.Count;
  184. _imageFiles.Clear();
  185. foreach (KeyValuePair<string, string> kvp in _videoFiles)
  186. {
  187. string videoFile = kvp.Key;
  188. string randomId = kvp.Value;
  189. var fileInfo = new FileInfosForSeg(videoFile, true, srcdialog.SelectedPath, randomId);
  190. _processingFiles.Enqueue(fileInfo);
  191. }
  192. _totalCount += _videoFiles.Count;
  193. _videoFiles.Clear();;
  194. int threadCount = Math.Min(_threadCount, _processingFiles.Count);
  195. for (int ni = 0; ni < threadCount; ni++)
  196. {
  197. if (_processThreads.Count < ni+1)
  198. {
  199. var thread = new Thread(() => DoImgCrop())
  200. {
  201. IsBackground = true,
  202. Name = "CropThread_"+ni.ToString(),
  203. };
  204. _processThreads.Add(thread);
  205. thread.Start();
  206. }
  207. else
  208. {
  209. var thread = _processThreads[ni];
  210. if (thread == null || !thread.IsAlive)
  211. {
  212. thread = new Thread(() => DoImgCrop())
  213. {
  214. IsBackground = true,
  215. Name = "CropThread_" + ni.ToString(),
  216. };
  217. thread.Start();
  218. }
  219. }
  220. }
  221. }
  222. }
  223. }
  224. private void setDataSourceTextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
  225. {
  226. _dataSource = ((System.Windows.Controls.TextBox)sender).Text;
  227. }
  228. private byte[] ImageToByteArray(Bitmap bitmap)
  229. {
  230. using (MemoryStream ms = new MemoryStream())
  231. {
  232. bitmap.Save(ms, ImageFormat.Jpeg);
  233. return ms.ToArray();
  234. }
  235. }
  236. private void DoImgCrop()
  237. {
  238. _processing = true;
  239. while (!_closing && _processingFiles.Count > 0)
  240. {
  241. if (_processingFiles.TryDequeue(out var fileInfo))
  242. {
  243. try
  244. {
  245. // 创建子文件夹
  246. string origFolder = fileInfo.OrigFolder;
  247. string origFilePath = fileInfo.OrigFilePath;
  248. string fileName = Path.GetFileNameWithoutExtension(origFilePath);
  249. string extension = Path.GetExtension(origFilePath);
  250. string localSubFolder = Path.GetDirectoryName(origFilePath).Substring(origFolder.Length);
  251. if (localSubFolder != string.Empty)
  252. {
  253. localSubFolder = localSubFolder.Substring(1);
  254. string[] subFolders = localSubFolder.Split('\\');
  255. string dstFolder = _dstFolder;
  256. foreach (var subFolder in subFolders)
  257. {
  258. if (subFolder != string.Empty)
  259. {
  260. dstFolder = Path.Combine(dstFolder, subFolder);
  261. if (!Directory.Exists(dstFolder))
  262. {
  263. Directory.CreateDirectory(dstFolder);
  264. }
  265. }
  266. }
  267. }
  268. if (fileInfo.IsVideo)
  269. {
  270. var videoFileReader = new VideoFileReader();
  271. videoFileReader.Open(origFilePath);
  272. var frameCount = videoFileReader.FrameCount;
  273. // 一个视频用一个固定的裁切框
  274. // 为了避免一两幅图上裁切框效果不佳导致整个视频裁切的不好
  275. // 先将视频的每一帧取出来,计算裁切框的位置
  276. // 将每个裁切框的左上右下角位置排序,取中值,得到最终整个视频的裁切框位置
  277. List<int> cropRectLeft = new List<int>();
  278. List<int> cropRectTop = new List<int>();
  279. List<int> cropRectBottom = new List<int>();
  280. List<int> cropRectRight = new List<int>();
  281. for (int ni = 0; ni < frameCount; ni+=5)
  282. {
  283. if (_closing)
  284. {
  285. break;
  286. }
  287. var img = videoFileReader.ReadVideoFrame(ni);
  288. if (CropImageWithOpenCVCppdll(img, out var rect))
  289. {
  290. cropRectLeft.Add(rect.Left);
  291. cropRectTop.Add(rect.Top);
  292. cropRectRight.Add(rect.Right);
  293. cropRectBottom.Add(rect.Bottom);
  294. }
  295. img.Dispose();
  296. }
  297. if (cropRectLeft.Count <= 0)
  298. {
  299. continue;
  300. }
  301. cropRectLeft.Sort();
  302. cropRectTop.Sort();
  303. cropRectRight.Sort();
  304. cropRectBottom.Sort();
  305. cropRectRight.Reverse();
  306. cropRectBottom.Reverse();
  307. // 考虑到希望尽量取一个稍微大一点的框,左上角尽量靠左上,右下角尽量靠右下,所以这里没有直接取最中间的结果
  308. // 而是取的1/4处(没有取最左上和最右下的点,是为了避免极个别裁切的不好的结果被选用)
  309. int index = cropRectLeft.Count / 4;
  310. var left = cropRectLeft[index];
  311. var top = cropRectTop[index];
  312. var bottom = cropRectBottom[index];
  313. var right = cropRectRight[index];
  314. if (right <= left || bottom <= top)
  315. {
  316. continue;
  317. }
  318. var cropRectForWholeVideo = new Rectangle(left, top, right - left, bottom - top);
  319. string fileId;
  320. if (_rename)
  321. {
  322. fileId = fileInfo.RandomId.ToString();
  323. }
  324. else
  325. {
  326. fileId = fileName;
  327. }
  328. for (int ni = 0; ni < frameCount; ni++)
  329. {
  330. if (_closing)
  331. {
  332. break;
  333. }
  334. var img = videoFileReader.ReadVideoFrame(ni);
  335. byte[] imageBytes = ImageToByteArray(img);
  336. string imgHashCode = HashCode.ComputeHashCode(imageBytes);
  337. string imgNewName = _dataSource + "_" + fileId + "_" + ni.ToString() + "_" + imgHashCode + ".jpg";
  338. string imgLocalPath = Path.Combine(localSubFolder, imgNewName);
  339. _cropNameOriNameDict.Add(imgNewName, origFilePath + "_" + ni.ToString());
  340. var segInfo = ProcessOneImage(img, _resulttype, _dstFolder, imgLocalPath, ImageFormat.Jpeg,cropRectForWholeVideo, true);
  341. _cropResults.Add(segInfo);
  342. img.Dispose();
  343. GC.Collect();
  344. GC.WaitForFullGCComplete();
  345. }
  346. videoFileReader.Close();
  347. videoFileReader.Dispose();
  348. Interlocked.Increment(ref _processedCount);
  349. Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  350. {
  351. ProgressBar.Value = (int)((double)_processedCount / _totalCount * 100);
  352. }));
  353. }
  354. else
  355. {
  356. var img = new Bitmap(origFilePath);
  357. string fileId;
  358. if (_rename)
  359. {
  360. fileId = fileInfo.RandomId.ToString();
  361. }
  362. else
  363. {
  364. fileId = fileName;
  365. }
  366. byte[] imageBytes = ImageToByteArray(img);
  367. string imgHashCode = HashCode.ComputeHashCode(imageBytes);
  368. string imgNewName = _dataSource + "_" + fileId + "_" + imgHashCode + extension;
  369. string imgLocalPath = Path.Combine(localSubFolder, imgNewName);
  370. try
  371. {
  372. _cropNameOriNameDict.Add(imgNewName, origFilePath);
  373. }
  374. catch
  375. {
  376. _sameImgNum++;
  377. }
  378. var segInfo = ProcessOneImage(img, _resulttype, _dstFolder, imgLocalPath, ImageFormat.Jpeg, Rectangle.Empty);
  379. _cropResults.Add(segInfo);
  380. img.Dispose();
  381. GC.Collect();
  382. GC.WaitForFullGCComplete();
  383. Interlocked.Increment(ref _processedCount);
  384. Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
  385. {
  386. ProgressBar.Value = (int)((double)_processedCount / _totalCount * 100);
  387. }));
  388. }
  389. }
  390. catch (Exception e)
  391. {
  392. System.Windows.MessageBox.Show("出错了!"+e);
  393. while (_processingFiles.Count > 0)
  394. {
  395. _processingFiles.TryDequeue(out _);
  396. }
  397. }
  398. }
  399. Thread.Sleep(1);
  400. }
  401. if (_waitThread == null || !_waitThread.IsAlive)
  402. {
  403. _waitThread = new Thread(() => DoWait())
  404. {
  405. IsBackground = true,
  406. };
  407. _waitThread.Start();
  408. }
  409. }
  410. private void SaveTxt(string txtPath)
  411. {
  412. using (StreamWriter writer = new StreamWriter(txtPath))
  413. {
  414. foreach (KeyValuePair<string, string> kvp in _cropNameOriNameDict)
  415. {
  416. writer.WriteLine($"{kvp.Key}: {kvp.Value}");
  417. }
  418. }
  419. }
  420. private void DoWait()
  421. {
  422. while (true)
  423. {
  424. bool finish = true;
  425. for (int ni = 0; ni < _threadCount; ni++)
  426. {
  427. Thread thread = _processThreads.Find(b => b.Name == "CropThread_" + ni.ToString());
  428. if (thread == null)
  429. {
  430. continue;
  431. }
  432. if (thread.IsAlive)
  433. {
  434. finish = false;
  435. break;
  436. }
  437. _processThreads.Remove(thread);
  438. }
  439. if (finish)
  440. {
  441. // 保存结果
  442. if (_saveCropInfo)
  443. {
  444. var datas = _cropResults.ToList();
  445. XmlSerializer xmls = new XmlSerializer(datas.GetType());
  446. FileInfo fileinfo = new FileInfo(_dstFolder + "\\croppeddatas_"+DateTime.Now.ToString("yyyyMMdd_HHmmss") +".xml");
  447. if (fileinfo.Exists)
  448. {
  449. fileinfo.Delete();
  450. }
  451. using (Stream s = fileinfo.OpenWrite())
  452. {
  453. xmls.Serialize(s, datas);
  454. }
  455. }
  456. System.Windows.MessageBox.Show("裁切完毕! 已过滤重复图像" + _sameImgNum.ToString() + "张!");
  457. _processing = false;
  458. _processedCount = 0;
  459. _totalCount = 0;
  460. _cropResults = new ConcurrentBag<ImgInfoForSegEntity>();
  461. if (_resulttype == EnumResultImgType.BothImgWithCropRectAndCroppedImg)
  462. {
  463. string croppedImgFolder = Path.Combine(_dstFolder, "裁切结果图");
  464. string cropRectImgFolder = Path.Combine(_dstFolder, "带裁切框原图");
  465. string txtPath = Path.Combine(croppedImgFolder, "cropNameAndOriName.txt");
  466. SaveTxt(txtPath);
  467. txtPath = Path.Combine(cropRectImgFolder, "cropNameAndOriName.txt");
  468. SaveTxt(txtPath);
  469. }
  470. else
  471. {
  472. string txtPath = Path.Combine(_dstTxtFolder, "cropNameAndOriName.txt");
  473. SaveTxt(txtPath);
  474. }
  475. System.Windows.MessageBox.Show("cropNameAndOriName.txt 保存完毕!");
  476. break;
  477. }
  478. else
  479. {
  480. Thread.Sleep(1);
  481. }
  482. }
  483. }
  484. public static bool CropImageWithOpenCVCppdll(Bitmap imagesrc, out Rectangle rectcrop)
  485. {
  486. if ((imagesrc.PixelFormat != PixelFormat.Format24bppRgb) && (imagesrc.PixelFormat != PixelFormat.Format32bppArgb) && (imagesrc.PixelFormat != PixelFormat.Format32bppPArgb) && (imagesrc.PixelFormat != PixelFormat.Format32bppRgb))
  487. {
  488. rectcrop = Rectangle.Empty;
  489. return false;
  490. }
  491. BitmapData bmData;
  492. int imgWidth = imagesrc.Width;
  493. int imgHeight = imagesrc.Height;
  494. int channels = (imagesrc.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4;
  495. Rectangle rect = new Rectangle(0, 0, imgWidth, imgHeight);
  496. bmData = imagesrc.LockBits(rect, ImageLockMode.ReadOnly, imagesrc.PixelFormat);
  497. int[] imginfo = new int[4];
  498. imginfo[0] = imgWidth;
  499. imginfo[1] = imgHeight;
  500. imginfo[2] = bmData.Stride;
  501. imginfo[3] = channels;
  502. int[] rectinfo = new int[4];
  503. if (!CropImage(bmData.Scan0, imginfo, rectinfo))
  504. {
  505. imagesrc.UnlockBits(bmData);
  506. bmData = null;
  507. rectcrop = Rectangle.Empty;
  508. return false;
  509. }
  510. imagesrc.UnlockBits(bmData);
  511. bmData = null;
  512. int rectX = rectinfo[0];
  513. int rectY = rectinfo[1];
  514. int rectWidth = rectinfo[2];
  515. int rectHeight = rectinfo[3];
  516. if ((rectX < 0) || (rectY < 0) || (rectWidth <= 0) || (rectHeight <= 0) || (rectX + rectWidth > imgWidth) || (rectY + rectHeight > imgHeight))
  517. {
  518. rectcrop = Rectangle.Empty;
  519. return false;
  520. }
  521. rectcrop = new Rectangle(rectX, rectY, rectWidth, rectHeight);
  522. return true;
  523. }
  524. public void SearchFiles(string folderName)
  525. {
  526. DirectoryInfo folder = new DirectoryInfo(folderName);
  527. string singleFolderRandomId = Guid.NewGuid().ToString();
  528. foreach (FileInfo file in folder.GetFiles())
  529. {
  530. if (file.Extension == ".png" || file.Extension == ".PNG" ||
  531. file.Extension == ".jpg" || file.Extension == ".JPG" ||
  532. file.Extension == ".jpeg" || file.Extension == ".JPEG" ||
  533. file.Extension == ".bmp" || file.Extension == ".BMP")
  534. {
  535. _imageFiles.Add(file.FullName, singleFolderRandomId);
  536. }
  537. if (file.Extension == ".avi" || file.Extension == ".AVI" ||
  538. file.Extension == ".mp4" || file.Extension == ".MP4")
  539. {
  540. // 对每个视频添加唯一的随机码,后续标注的时候就不会打乱
  541. string singleVideorRandomId = Guid.NewGuid().ToString();
  542. _videoFiles.Add(file.FullName, singleVideorRandomId);
  543. }
  544. }
  545. foreach (var subFolder in folder.GetDirectories())
  546. {
  547. SearchFiles(subFolder.FullName);
  548. }
  549. }
  550. private ImgInfoForSegEntity ProcessOneImage(Bitmap img, EnumResultImgType resulttype,
  551. string dstimgfolder, string imgLocalPath, ImageFormat dstFormat, Rectangle rectIn, bool useInputRect = false)
  552. {
  553. string dstImgPath = Path.Combine(dstimgfolder,imgLocalPath);
  554. string imgid = Path.GetFileNameWithoutExtension(imgLocalPath);
  555. bool segSucceed = true;
  556. System.Drawing.Rectangle rect = System.Drawing.Rectangle.Empty;
  557. if (!useInputRect)
  558. {
  559. if (!CropImageWithOpenCVCppdll(img, out rect))
  560. {
  561. img.Dispose();
  562. segSucceed = false;
  563. }
  564. }
  565. else
  566. {
  567. rect = rectIn;
  568. }
  569. if (segSucceed)
  570. {
  571. Bitmap dstimg = null;
  572. if (resulttype == EnumResultImgType.CroppedImg)
  573. {
  574. dstimg = new Bitmap(rect.Width, rect.Height, img.PixelFormat);
  575. using (var g = Graphics.FromImage(dstimg))
  576. {
  577. g.DrawImage(img, new System.Drawing.Rectangle(0, 0, rect.Width, rect.Height),
  578. new System.Drawing.Rectangle(rect.Left, rect.Top, rect.Width, rect.Height),
  579. GraphicsUnit.Pixel);
  580. g.Dispose();
  581. }
  582. dstimg.Save(dstImgPath, dstFormat);
  583. dstimg.Dispose();
  584. }
  585. if (resulttype == EnumResultImgType.OrigImgWithCropRect)
  586. {
  587. dstimg = img.Clone(new Rectangle(0, 0, img.Width, img.Height), img.PixelFormat);
  588. using (var g = Graphics.FromImage(dstimg))
  589. {
  590. g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.Yellow, 8), rect);
  591. g.Dispose();
  592. }
  593. dstimg.Save(dstImgPath, dstFormat);
  594. dstimg.Dispose();
  595. }
  596. if (resulttype == EnumResultImgType.BothImgWithCropRectAndCroppedImg)
  597. {
  598. Bitmap dstCroppedImg = new Bitmap(rect.Width, rect.Height, img.PixelFormat);
  599. Bitmap dstCropImgWithCropRect = img.Clone(new Rectangle(0, 0, img.Width, img.Height), img.PixelFormat);
  600. using (var g = Graphics.FromImage(dstCroppedImg))
  601. {
  602. g.DrawImage(img, new System.Drawing.Rectangle(0, 0, rect.Width, rect.Height),
  603. new System.Drawing.Rectangle(rect.Left, rect.Top, rect.Width, rect.Height),
  604. GraphicsUnit.Pixel);
  605. g.Dispose();
  606. }
  607. using (var g = Graphics.FromImage(dstCropImgWithCropRect))
  608. {
  609. g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.Yellow, 8), rect);
  610. g.Dispose();
  611. }
  612. string croppedImgFolder = Path.Combine(dstimgfolder, "裁切结果图");
  613. string cropRectImgFolder = Path.Combine(dstimgfolder, "带裁切框原图");
  614. Directory.CreateDirectory(croppedImgFolder);
  615. Directory.CreateDirectory(cropRectImgFolder);
  616. dstCroppedImg.Save(Path.Combine(croppedImgFolder, imgLocalPath), dstFormat);
  617. dstCroppedImg.Dispose();
  618. dstCropImgWithCropRect.Save(Path.Combine(cropRectImgFolder, imgLocalPath), dstFormat);
  619. dstCropImgWithCropRect.Dispose();
  620. }
  621. }
  622. var segInfo = new ImgInfoForSegEntity
  623. {
  624. ImgId = imgid,
  625. ImgLocalPath = imgLocalPath,
  626. SegSucceed = segSucceed,
  627. Left = rect.Left,
  628. Right = rect.Right,
  629. Top = rect.Top,
  630. Bottom = rect.Bottom,
  631. };
  632. return segInfo;
  633. }
  634. private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
  635. {
  636. _closing = true;
  637. while (_processing)
  638. {
  639. Thread.Sleep(1);
  640. }
  641. _closing = false;
  642. }
  643. }
  644. }