WPF提取图片感兴趣区域

目的:提取图片的刚兴趣区域。

  •  xaml代码
<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区间即可。

猜你喜欢

转载自blog.csdn.net/u012366767/article/details/81507305