/* ---------------------------------------------------------- * 文件名称:MainWindow.xaml.cs * * 作者:秦建辉 * * 微信:splashcn * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * Visual Studio V2019 * .NET Framework 4.8 * * 版本历史: * V1.0 2020年01月28日 * OpenCV最大连通域抠图 * * 参考资料: * http://www.pinvoke.net/default.aspx/Interfaces/IObjectSafety.html * https://wenku.baidu.com/view/b1a476c855270722182ef784.html ------------------------------------------------------------ */ using OpenCvSharp; using OpenCvSharp.Extensions; using System.Windows; namespace Contour { public partial class MainWindow : System.Windows.Window { public MainWindow() { InitializeComponent(); } private void ButtonSelectFile_Click(object sender, RoutedEventArgs e) { try { Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog { Filter = "Image|*.jpg;*.bmp;*.png;*.tif;*.tga;*.ras;*.jp2;*.j2k;*.jpe", DereferenceLinks = true }; if (dlg.ShowDialog(Owner).Value == true) { // 读取图像 using (Mat src = Cv2.ImRead(dlg.FileName, ImreadModes.Color)) // BGR格式 { // 抠图 GetCutout(src); } } } catch (System.Exception exception) { MessageBox.Show(exception.Message, "文件异常", MessageBoxButton.OK, MessageBoxImage.Error); } } // 抠取最大连通域图像 private void GetCutout(Mat src) { using (Mat gray = new Mat(src.Size(), MatType.CV_8UC1)) { // 转换为灰度图像 Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); using (Mat mono = new Mat(gray.Size(), gray.Type())) { // 中值滤波 Cv2.MedianBlur(gray, mono, 5); // 大津法转化为二值图像 Cv2.Threshold(mono, mono, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu); // 膨胀 Cv2.Dilate(mono, mono, new Mat()); // 腐蚀 Cv2.Erode(mono, mono, new Mat()); // 查找轮廓 Cv2.FindContours(mono, out OpenCvSharp.Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple); // 查找最大连通域 double maxArea = double.MinValue; int index = -1; for (int i = 0; i < hierarchy.Length; i++) { double area = Cv2.ContourArea(contours[i]); if (area > maxArea) { maxArea = area; index = i; } } // 显示原图 ImageSource.Source = BitmapSourceConverter.ToBitmapSource(src); // 显示最大连通域 using (Mat maxdomain = src.Clone()) { // 对最大连通域用红色染色 Cv2.DrawContours(maxdomain, contours, index, Scalar.Red, Cv2.FILLED); ImageContour.Source = BitmapSourceConverter.ToBitmapSource(maxdomain); // 抠图 using (Mat mask = new Mat()) { Cv2.InRange(maxdomain, Scalar.Red, Scalar.Red, mask); // 生成最大连通域掩码 OpenCvSharp.Rect r = Cv2.BoundingRect(contours[index]); // 抠图区域 using (Mat cutout = new Mat()) { src[r].CopyTo(cutout, mask[r]); ImageCutout.Source = BitmapSourceConverter.ToBitmapSource(cutout); } } } } } } } }
MainWindow.xaml
<Window x:Class="Contour.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="最大连通域抠图" FontSize="16" MinHeight="600" MinWidth="800" WindowStartupLocation="CenterScreen" WindowState="Maximized" Icon="Cutout.ico"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Button Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" Margin="4" Padding="16,4" Content="选择图像" Name="ButtonSelectFile" Click="ButtonSelectFile_Click"/> <TextBlock Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="4" Text="最大连通域" /> <TextBlock Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="4" Text="抠图"/> <Border Grid.Row="1" Grid.Column="0" BorderBrush="LightGray" BorderThickness="1" Margin="4"> <Image Name="ImageSource"/> </Border> <Border Grid.Row="1" Grid.Column="1" BorderBrush="LightGray" BorderThickness="1" Margin="4"> <Image Name="ImageContour"/> </Border> <Border Grid.Row="1" Grid.Column="2" BorderBrush="LightGray" BorderThickness="1" Margin="4"> <Image Name="ImageCutout"/> </Border> </Grid> </Window>