123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- using System;
- using System.Collections.Generic;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Input;
- using System.Windows.Media.Imaging;
- using Microsoft.Win32;
- using System.Drawing;
- using System.IO;
- using System.Xml.Serialization;
- using System.Threading.Tasks;
- using System.Threading;
- namespace ConstRectCropImage
- {
- enum EnumResultImgType
- {
- OrigImgWithCropRect,
- CroppedImg,
- }
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MainWindow : Window
- {
- #region private variables
- private BitmapImage _origimg;
- private volatile int _currentIndex = 0;
- private string _currentImgFolder;
- private List<ImgInfoForSegEntity> _cropdatas = new List<ImgInfoForSegEntity>();
- private System.Windows.Media.Brush _roiColor = System.Windows.Media.Brushes.Orange;
- private System.Drawing.Point _startpoint;
- private System.Drawing.Point _endpoint;
- private System.Drawing.Rectangle _drawingroi = System.Drawing.Rectangle.Empty;
- private readonly ManualResetEvent _drawFinishEvent = new ManualResetEvent(false);
- #endregion
- public MainWindow()
- {
- InitializeComponent();
- _origimg = null;
- OrigImage.Source = _origimg;
- }
- private void OnLoadMultiImagesClick(object sender, RoutedEventArgs e)
- {
- if (_cropdatas.Count > 0)
- {
- MessageBox.Show("请先完成已加载的图像.");
- return;
- }
- System.Windows.Forms.FolderBrowserDialog folderDialog = new System.Windows.Forms.FolderBrowserDialog();
- folderDialog.Description = "请选择需要裁切的文件夹";
- if (folderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
- {
- if (string.IsNullOrEmpty(folderDialog.SelectedPath))
- {
- MessageBox.Show("保存裁切后图像的文件夹不能为空!");
- return;
- }
- _currentImgFolder = folderDialog.SelectedPath;
- DirectoryInfo selectedFolder = new DirectoryInfo(folderDialog.SelectedPath);
- Queue<DirectoryInfo> foldersToSearch = new Queue<DirectoryInfo>();
- foldersToSearch.Enqueue(selectedFolder);
- while (foldersToSearch.Count > 0)
- {
- DirectoryInfo folder = foldersToSearch.Dequeue();
- if (!folder.Exists)
- {
- continue;
- }
- // 搜索子文件夹
- DirectoryInfo[] subFolders = folder.GetDirectories();
- foreach (DirectoryInfo subFolder in subFolders)
- {
- foldersToSearch.Enqueue(new DirectoryInfo(subFolder.FullName));
- }
- // 遍历当前文件夹中所有图片
- FileInfo[] files = folder.GetFiles();
- foreach (FileInfo file in files)
- {
- string fileName = file.FullName;
- string fileLocalPath = fileName.Substring(_currentImgFolder.Length + 1);
- string imgId = Path.GetFileNameWithoutExtension(fileName);
- ImgInfoForSegEntity imgInfo = new ImgInfoForSegEntity
- {
- ImgId = imgId,
- ImgLocalPath = fileLocalPath,
- };
- _cropdatas.Add(imgInfo);
- }
- }
- _currentIndex = 0;
- CurrentIndexUpdated();
- }
- }
- private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
- {
- MyCanvas.Width = GridOrigImg.ActualWidth;
- MyCanvas.Height = GridOrigImg.ActualHeight;
- ImageUpdated();
- DrawingROIUpdated();
- }
- private void Canvas_MouseLeftBtnDown(object sender, MouseButtonEventArgs e)
- {
- int x = Convert.ToInt32(e.GetPosition(OrigImage).X / OrigImage.ActualWidth * _origimg.Width);
- int y = Convert.ToInt32(e.GetPosition(OrigImage).Y / OrigImage.ActualHeight * _origimg.Height);
- _startpoint = new System.Drawing.Point(x, y);
- }
- private void Canvas_MouseMove(object sender, MouseEventArgs e)
- {
- int x = Convert.ToInt32(e.GetPosition(OrigImage).X / OrigImage.ActualWidth * _origimg.Width);
- int y = Convert.ToInt32(e.GetPosition(OrigImage).Y / OrigImage.ActualHeight * _origimg.Height);
- MousePosition.Text = x.ToString() + "," + y.ToString();
- if (e.LeftButton == MouseButtonState.Pressed)
- {
- _endpoint = new System.Drawing.Point(x, y);
- DrawingROIUpdated();
- }
- }
- private void SaveCropDatasClick(object sender, RoutedEventArgs e)
- {
- if (_cropdatas.Count <= 0)
- {
- MessageBox.Show("未找到需保存的数据");
- return;
- }
- if (!_cropdatas[_currentIndex].SegSucceed)
- {
- if (!UseCurrentRoi())
- {
- return;
- }
- }
- EnumResultImgType resulttype = EnumResultImgType.OrigImgWithCropRect;
- if (RadioBtnResultCropped.IsChecked ?? false)
- {
- resulttype = EnumResultImgType.CroppedImg;
- }
- System.Windows.Forms.FolderBrowserDialog dstFolderD = new System.Windows.Forms.FolderBrowserDialog();
- dstFolderD.Description = "请选择保存裁切后图像的文件夹";
- if (dstFolderD.ShowDialog() == System.Windows.Forms.DialogResult.OK)
- {
- if (string.IsNullOrEmpty(dstFolderD.SelectedPath))
- {
- MessageBox.Show("保存裁切后图像的文件夹不能为空!");
- return;
- }
- Task.Run(() =>
- {
- try
- {
- foreach (ImgInfoForSegEntity img in _cropdatas)
- {
- string filename = img.ImgLocalPath;
- Bitmap img_orig = new Bitmap(Bitmap.FromFile(_currentImgFolder + "\\" + filename));
- int imgWidth = img_orig.Width;
- int imgHeight = img_orig.Height;
- if (!img.SegSucceed || (img.Left == 0 && img.Right == 0 && img.Top == 0 && img.Bottom == 0))
- {
- if (imgWidth <= _drawingroi.Right || imgHeight <= _drawingroi.Height)
- {
- _drawFinishEvent.Reset();
- MessageBox.Show("请重新画框!");
- _drawFinishEvent.WaitOne();
- }
- img.Left = _drawingroi.Left;
- img.Top = _drawingroi.Top;
- img.Right = _drawingroi.Right;
- img.Bottom = _drawingroi.Bottom;
- img.SegSucceed = true;
- }
- Bitmap dstimg = null;
- if (resulttype == EnumResultImgType.CroppedImg)
- {
- dstimg = new Bitmap(_drawingroi.Width, _drawingroi.Height, img_orig.PixelFormat);
- using (var g = Graphics.FromImage(dstimg))
- {
- g.DrawImage(img_orig, new System.Drawing.Rectangle(0, 0, _drawingroi.Width, _drawingroi.Height),
- new System.Drawing.Rectangle(_drawingroi.Left, _drawingroi.Top, _drawingroi.Width, _drawingroi.Height),
- GraphicsUnit.Pixel);
- g.Dispose();
- }
- }
- if (resulttype == EnumResultImgType.OrigImgWithCropRect)
- {
- dstimg = img_orig.Clone(new Rectangle(0, 0, img_orig.Width, img_orig.Height), img_orig.PixelFormat);
- using (var g = Graphics.FromImage(dstimg))
- {
- g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.Yellow, 8), _drawingroi);
- g.Dispose();
- }
- }
- string fileRawName = Path.GetFileNameWithoutExtension(filename);
- dstimg.Save(dstFolderD.SelectedPath + "\\" + fileRawName+".jpg",System.Drawing.Imaging.ImageFormat.Jpeg);
- dstimg.Dispose();
- img_orig.Dispose();
- _currentIndex += 1;
- }
- XmlSerializer xmls = new XmlSerializer(_cropdatas.GetType());
- FileInfo fileinfo = new FileInfo(dstFolderD.SelectedPath + "\\croppeddatas.xml");
- if (fileinfo.Exists)
- {
- fileinfo.Delete();
- }
- using (Stream s = fileinfo.OpenWrite())
- {
- xmls.Serialize(s, _cropdatas);
- }
- _cropdatas.Clear();
- MessageBox.Show("完成");
- }
- catch (Exception excep)
- {
- MessageBox.Show("出错了!" + excep);
- }
- });
- }
- }
- private bool UseCurrentRoi()
- {
- if (!_startpoint.IsEmpty && !_endpoint.IsEmpty)
- {
- int roileft = Math.Min(_startpoint.X, _endpoint.X);
- int roiright = Math.Max(_startpoint.X, _endpoint.X);
- int roitop = Math.Min(_startpoint.Y, _endpoint.Y);
- int roibottom = Math.Max(_startpoint.Y, _endpoint.Y);
- if (roileft == roiright || roitop == roibottom)
- {
- MessageBox.Show("绘制的矩形框尺寸不能为0.");
- return false;
- }
- _drawingroi = new System.Drawing.Rectangle(roileft, roitop, roiright - roileft, roibottom - roitop);
- _cropdatas[_currentIndex].Left = roileft;
- _cropdatas[_currentIndex].Top = roitop;
- _cropdatas[_currentIndex].Right = roiright;
- _cropdatas[_currentIndex].Bottom = roibottom;
- _cropdatas[_currentIndex].SegSucceed = true;
- return true;
- }
- else
- {
- MessageBox.Show("请先加载待测图像并绘制有效的ROI");
- return false;
- }
- }
- private void DrawingROIUpdated()
- {
- if (null == _origimg)
- {
- return;
- }
- System.Windows.Shapes.Rectangle drawingroi = MyCanvas.FindName("drawingroi") as System.Windows.Shapes.Rectangle;
- if (drawingroi != null)
- {
- MyCanvas.Children.Remove(drawingroi);
- MyCanvas.UnregisterName("drawingroi");
- }
- if (_startpoint.IsEmpty || _endpoint.IsEmpty)
- {
- return;
- }
- // 在原始图像上的坐标
- int roileft = Math.Min(_startpoint.X, _endpoint.X);
- int roiright = Math.Max(_startpoint.X, _endpoint.X);
- int roitop = Math.Min(_startpoint.Y, _endpoint.Y);
- int roibottom = Math.Max(_startpoint.Y, _endpoint.Y);
- ROI.Text = roileft.ToString() + "," + roitop + "," + roiright.ToString() + "," + roibottom.ToString();
- // 求在画布上的坐标
- double boxTopInCanvas = roitop * OrigImgScaleTramsform.ScaleY;
- double boxLeftInCanvas = roileft * OrigImgScaleTramsform.ScaleX;
- double boxWidthInCanvas = (roiright - roileft) * OrigImgScaleTramsform.ScaleX;
- double boxHeghtInCanvas = (roibottom - roitop) * OrigImgScaleTramsform.ScaleY;
- // 在画布上画矩形
- drawingroi = new System.Windows.Shapes.Rectangle();
- drawingroi.StrokeThickness = 3;
- drawingroi.Stroke = _roiColor;
- drawingroi.Width = boxWidthInCanvas;
- drawingroi.Height = boxHeghtInCanvas;
- Canvas.SetLeft(drawingroi, boxLeftInCanvas);
- Canvas.SetTop(drawingroi, boxTopInCanvas);
- MyCanvas.Children.Add(drawingroi);
- MyCanvas.RegisterName("drawingroi", drawingroi);
- }
- private void ImageUpdated()
- {
- if (null == _origimg)
- {
- return;
- }
- // 缩放
- double ratioW = GridOrigImg.ActualWidth / _origimg.Width;
- double ratioH = GridOrigImg.ActualHeight / _origimg.Height;
- double ratio = ratioW < ratioH ? ratioW : ratioH;
- OrigImgScaleTramsform.CenterX = 0;
- OrigImgScaleTramsform.CenterY = 0;
- OrigImgScaleTramsform.ScaleX = ratio;
- OrigImgScaleTramsform.ScaleY = ratio;
- // 使图像居中,需要平移
- double translateX = 0;
- double translateY = 0;
- if (Math.Abs(ratio - ratioW) < 0.0001)
- {
- translateY = 0.5 * (ratioH - ratio) * _origimg.Height;
- }
- else
- {
- translateX = 0.5 * (ratioW - ratio) * _origimg.Width;
- }
- // 更新画布尺寸,使其刚好只覆盖图像区域
- MyCanvas.Width = ratio * _origimg.Width;
- MyCanvas.Height = ratio * _origimg.Height;
- Canvas.SetLeft(MyCanvas, translateX);
- Canvas.SetTop(MyCanvas, translateY);
- MyCanvas.ClipToBounds = true;
- OrigImage.Source = _origimg;
- }
- private void CurrentIndexUpdated()
- {
- ImgInfoForSegEntity imginfo = _cropdatas[_currentIndex];
- Bitmap image = new Bitmap(_currentImgFolder + "\\" + imginfo.ImgLocalPath);
- _origimg = ImageUtility.BitmapToBitmapImage(image);
- if (imginfo.Left != 0 || imginfo.Right != 0 || imginfo.Top != 0 || imginfo.Bottom != 0)
- {
- _startpoint = new System.Drawing.Point(imginfo.Left, imginfo.Top);
- _endpoint = new System.Drawing.Point(imginfo.Right, imginfo.Bottom);
- _drawingroi = new System.Drawing.Rectangle(imginfo.Left, imginfo.Top, imginfo.Right - imginfo.Left, imginfo.Bottom - imginfo.Top);
- }
- ImageUpdated();
- DrawingROIUpdated();
- ROI.Text = string.Empty;
- }
- private void UseCurrentRoiClick(object sender, RoutedEventArgs e)
- {
- if (UseCurrentRoi())
- {
- _drawFinishEvent.Set();
- }
- }
- }
- }
|