目的:提取图片的感兴趣区域。
<Window x:Class="ImageProcess_GetROI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ImageProcess_GetROI"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Name="imgOrigin" Stretch="Uniform"/>
<InkCanvas Name="inkCanvasOrigin" EditingMode="None" Background="Transparent"
Width="{Binding ElementName=imgOrigin, Path=ActualWidth}" Height="{Binding ElementName=imgOrigin,Path=ActualHeight}"
MouseDown="InkCanvasImg_MouseDown" MouseMove="InkCanvasImg_MouseMove" MouseUp="InkCanvasImg_MouseUp"/>
<Image Grid.Column="1" Name="imgMapping" Stretch="Uniform"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ImageProcess_GetROI
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
private System.Windows.Point iniP;
public MainWindow()
{
InitializeComponent();
DrawingAttributes drawingAttributes = new DrawingAttributes
{
Color = Colors.Red,
Width = 2,
Height = 2,
StylusTip = StylusTip.Rectangle,
//FitToCurve = true,
IsHighlighter = false,
IgnorePressure = true,
};
inkCanvasOrigin.DefaultDrawingAttributes = drawingAttributes;
imgOrigin.Source = new BitmapImage(new Uri(@"D:\程序项目目录\ImgList\头像.png", UriKind.RelativeOrAbsolute));
imgMapping.Source = new BitmapImage(new Uri(@"D:\程序项目目录\ImgList\头像.png", UriKind.RelativeOrAbsolute));
}
private void InkCanvasImg_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
iniP = e.GetPosition(inkCanvasOrigin);
}
}
private List<System.Windows.Point> GenerateEclipseGeometry(System.Windows.Point st, System.Windows.Point ed)
{
double a = 0.5 * (ed.X - st.X);
double b = 0.5 * (ed.Y - st.Y);
List<System.Windows.Point> pointList = new List<System.Windows.Point>();
for (double r = 0; r <= 2 * Math.PI; r = r + 0.01)
{
pointList.Add(new System.Windows.Point(0.5 * (st.X + ed.X) + a * Math.Cos(r), 0.5 * (st.Y + ed.Y) + b * Math.Sin(r)));
}
return pointList;
}
private void InkCanvasImg_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
System.Windows.Point endP = e.GetPosition(inkCanvasOrigin);
List<System.Windows.Point> pointList = GenerateEclipseGeometry(iniP, endP);
StylusPointCollection point = new StylusPointCollection(pointList);
Stroke stroke = new Stroke(point)
{
DrawingAttributes = inkCanvasOrigin.DefaultDrawingAttributes.Clone()
};
if (inkCanvasOrigin.Strokes.Count > 0)
{
inkCanvasOrigin.Strokes.Clear();
}
inkCanvasOrigin.Strokes.Add(stroke);
}
}
private Rect GetStrokeArea(Stroke s)
{
Double xMin = Double.MaxValue;
Double xMax = Double.MinValue;
Double yMin = Double.MaxValue;
Double yMax = Double.MinValue;
foreach (StylusPoint sp in s.StylusPoints)
{
if (sp.X < xMin)
{
xMin = sp.X;
}
else if (sp.X > xMax)
{
xMax = sp.X;
}
if (sp.Y < yMin)
{
yMin = sp.Y;
}
else if (sp.Y > yMax)
{
yMax = sp.Y;
}
}
return new Rect { X = xMin, Y = yMin, Width = xMax - xMin, Height = yMax - yMin };
}
private int[,] GetDataROI(Bitmap bmp)
{
int row = bmp.Height;
int col = bmp.Width;
int[,] flag = new int[col, row];
double rEx = imgOrigin.ActualHeight / row;
double cEx = imgOrigin.ActualWidth / col;
Rect rect = GetStrokeArea(inkCanvasOrigin.Strokes[0]);
double pX = rect.X + 0.5 * rect.Width;
double pY = rect.Y + 0.5 * rect.Height;
for (double i = rect.Y; i <= rect.Y + rect.Height; i = i + 0.1)
{
for (double j = rect.X; j < rect.X + rect.Width; j = j + 0.1)
{
if ((i - pY) * (i - pY) / (0.5 * rect.Height * 0.5 * rect.Height) + (j - pX) * (j - pX) / (0.5 * rect.Width * 0.5 * rect.Width) <= 1)
{
flag[(int)Math.Floor(j / cEx), (int)Math.Floor(i / rEx)] = 1;
}
}
}
return flag;
}
private Bitmap GetROIImage(Bitmap bmp, int[,] colorFlag)
{
for (int i = 0; i < bmp.Height; i++)
{
for (int j = 0; j < bmp.Width; j++)
{
if (colorFlag[j, i] == 0)
{
bmp.SetPixel(j, i, System.Drawing.Color.FromArgb(255, 0, 0, 0));
}
}
}
return bmp;
}
private Bitmap ImageSourceToBitmap(ImageSource imageSource)
{
BitmapSource bitmapSource = (BitmapSource)imageSource;
Bitmap bmp = new Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
BitmapData data = bmp.LockBits(
new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
bitmapSource.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
bmp.UnlockBits(data);
return bmp;
}
private BitmapImage BitmapToBitmapImage(Bitmap bitmap)
{
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
stream.Position = 0;
BitmapImage result = new BitmapImage();
result.BeginInit();
result.CacheOption = BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze();
return result;
}
}
private void InkCanvasImg_MouseUp(object sender, MouseButtonEventArgs e)
{
Bitmap bmp = ImageSourceToBitmap(imgOrigin.Source);
bmp = GetROIImage(bmp, GetDataROI(bmp));
imgMapping.Source = BitmapToBitmapImage(bmp);
}
}
}
技术要领:利用InkCanvas的绘制功能选择ROI,然后提取ROI的坐标,换算到图像序号;绘制椭圆采用极坐标方式,确定ROI遍历InkCanvas区间即可。