OpenCV:最大连通域抠图

演示效果

源代码
MainWindow.xaml.cs

/* ----------------------------------------------------------
 * 文件名称: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>

Comments are closed.