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, } /// /// MainWindow.xaml 的交互逻辑 /// public partial class MainWindow : Window { #region private variables private BitmapImage _origimg; private volatile int _currentIndex = 0; private string _currentImgFolder; private List _cropdatas = new List(); 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 foldersToSearch = new Queue(); 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(); } } } }