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();
}
}
}
}