Usuń tło obrazu C#

W tworzeniu i manipulacji treściami cyfrowymi usuwanie tła z obrazów jest powszechnym i niezbędnym zadaniem. Niezależnie od tego, czy pracujesz nad projektem graficznym, handlem elektronicznym, czy jakimkolwiek innym projektem wizualnym, możliwość izolowania obiektów od tła poszerza Twoją kreatywność. W tym poście na blogu przyjrzymy się, jak programowo usunąć tło z obrazów w języku C#.

Biblioteka C# do usuwania tła z obrazów

Aby usunąć tło z obrazów, użyjemy Aspose.Imaging for .NET - potężnej biblioteki, która zapewnia szeroką gamę funkcji przetwarzania obrazu dla aplikacji .NET. Obsługuje różne formaty obrazów i pozwala programistom na łatwe wykonywanie operacji, takich jak zmiana rozmiaru, kadrowanie, obracanie i oczywiście usuwanie tła.

Możesz pobrać interfejs API lub zainstalować go z poziomu narzędzia NuGet.

PM> Install-Package Aspose.Imaging

Usuwanie tła obrazu za pomocą automatycznego maskowania w C#

Aby uzyskać lepsze wyniki usuwania tła, preferowana jest metoda automatycznego maskowania. Celem jest utworzenie maski, która dokładnie identyfikuje piksele należące do pierwszego planu i te należące do tła. Aspose.Imaging zapewnia trzy techniki automatycznego maskowania w celu usunięcia tła z obrazu, jak opisano w poniższych sekcjach.

Automatyczne maskowanie wycinania wykresów z wtapianiem

W tej technice interfejs API wykonuje maskowanie obrazu z wtapianiem w oparciu o rozmiar obrazu i wykorzystuje automatycznie obliczane domyślne obrysy. Poniższy fragment kodu pokazuje, jak używać automatycznego maskowania wycinania wykresu z wtapianiem. Właściwość Args AutoMaskingGraphCutOptions można pominąć, ponieważ na końcu umieszczane są domyślne obrysy.

using Aspose.Imaging;
using Aspose.Imaging.FileFormats.Png;
using Aspose.Imaging.ImageOptions;
using Aspose.Imaging.Masking;
using Aspose.Imaging.Masking.Options;
using Aspose.Imaging.Masking.Result;
using Aspose.Imaging.Sources;
using System;
using System.IO;

string templatesFolder = @"c:\Users\USER\Downloads\templates\";
string dataDir = templatesFolder;

MaskingResult results;
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg"))
{
    // Aby użyć Graph Cut z automatycznie obliczonymi pociągnięciami, używana jest opcja AutoMaskingGraphCutOptions.
    AutoMaskingGraphCutOptions options = new AutoMaskingGraphCutOptions
    {
        // Wskazanie, że podczas dekompozycji obrazu należy wykonać nowe obliczenie domyślnych pociągnięć.
        CalculateDefaultStrokes = true,
        // Ustawianie promienia wtapiania po procesie na podstawie rozmiaru obrazu.
        FeatheringRadius = (Math.Max(image.Width, image.Height) / 500) + 1,
        Method = SegmentationMethod.GraphCut,
        Decompose = false,
        ExportOptions =
                                                        new PngOptions()
                                                        {
                                                            ColorType = PngColorType.TruecolorWithAlpha,
                                                            Source = new FileCreateSource(dataDir + "result.png")
                                                        },
        BackgroundReplacementColor = Color.Transparent
    };

    results = new ImageMasking(image).Decompose(options);

    using (RasterImage resultImage = (RasterImage)results[1].GetImage())
    {
        resultImage.Save(dataDir + "result2.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha });
    }
}



File.Delete(dataDir + "result.png");
File.Delete(dataDir + "result2.png");

Poniższy zrzut ekranu przedstawia obrazy wejściowe i wyjściowe.

usuwanie tła obrazu w C#

Ponowne użycie domyślnych pociągnięć w powtarzanym automatycznym maskowaniu

W tej technice maskowanie obrazu odbywa się przy użyciu automatycznie obliczonych domyślnych pociągnięć, jednakże interfejs API ponownie wykorzystuje opcje maskowania w nowej iteracji maskowania. W poniższym fragmencie kodu można zauważyć, że dane dwóch założonych obiektów są również określone we właściwości AssumedObjects opcji AutoMaskingGraphCutOptions. Po uzyskaniu wstępnych wyników maskowania wprowadzane są korekty zastosowanych pociągnięć tła/pierwszego planu i przeprowadzana jest kolejna iteracja maskowania.

using Aspose.Imaging;
using Aspose.Imaging.FileFormats.Png;
using Aspose.Imaging.ImageOptions;
using Aspose.Imaging.Masking;
using Aspose.Imaging.Masking.Options;
using Aspose.Imaging.Masking.Result;
using Aspose.Imaging.Sources;
using System;
using System.Collections.Generic;
using System.IO;

string templatesFolder = @"c:\Users\USER\Downloads\templates\";
string dataDir = templatesFolder;

// Aby poprawić wyniki maskowania, można podać dane dotyczące konkretnych obiektów, które powinny zostać uwzględnione w wyniku maskowania pierwszego planu.
List<AssumedObjectData> assumedObjects = new List<AssumedObjectData>();
// Należy określić typ obiektu oraz obszar, w którym znajduje się ten obiekt.
assumedObjects.Add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(0, 0, 300, 300)));

MaskingResult results;
AutoMaskingGraphCutOptions options;
Point[] appliedBackgroundStrokes;
Point[] appliedForegroundStrokes;
Rectangle[] appliedObjectRectangles;

using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg"))
{
    // Aby użyć Graph Cut z automatycznie obliczonymi pociągnięciami, używana jest opcja AutoMaskingGraphCutOptions.
    options = new AutoMaskingGraphCutOptions
    {
        AssumedObjects = assumedObjects,
        // Wskazanie, że podczas dekompozycji obrazu należy wykonać nowe obliczenia domyślnych pociągnięć.
        CalculateDefaultStrokes = true,
        // Ustawianie promienia wtapiania po procesie na podstawie rozmiaru obrazu.
        FeatheringRadius = (Math.Max(image.Width, image.Height) / 500) + 1,
        Method = SegmentationMethod.GraphCut,
        Decompose = false,
        ExportOptions = new PngOptions()
        {
            ColorType = PngColorType.TruecolorWithAlpha,
            Source = new FileCreateSource(dataDir + "result.png")
        },
        BackgroundReplacementColor = Color.Transparent
    };

    using (IMaskingSession maskingSession = new ImageMasking(image).CreateSession(options))
    {
        results = maskingSession.Decompose();

        // Zapisywanie wyniku maskowania pośredniego.
        using (RasterImage resultImage = results[1].GetImage())
        {
            resultImage.Save(dataDir + "result2.png",
                new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha });
        }

        // W tym momencie można przeanalizować zastosowane pociągnięcia pierwszego planu/tła i na ich podstawie dodać dodatkowe 
        // obrysy pierwszego planu/tła można wprowadzić ręcznie.
        appliedBackgroundStrokes = options.DefaultBackgroundStrokes;
        appliedForegroundStrokes = options.DefaultForegroundStrokes;
        appliedObjectRectangles = options.DefaultObjectsRectangles;

        // Ponowne użycie opcji AutoMaskingGraphCutOptions nie wymaga wykonywania domyślnych obliczeń obrysu po raz drugi.
        // Gdy podane są zarówno domyślne obrysy, jak i obiekty ObjectsPoints we właściwości Args AutoMaskingArgs, tablice Point są ostatecznie łączone.
        // Pierwsza tablica ObjectsPoints jest uważana za tablicę punktów tła i 
        // druga tablica ObjectsPoints jest uważana za tablicę punktów pierwszego planu.
        // Jeśli we właściwości Args właściwości AutoMaskingArgs podano zarówno DefaultObjectsRectangles, jak i ObjectsRectangles, 
        // używana jest tylko tablica z Args.
        AutoMaskingArgs newAutoMaskingArgs = new AutoMaskingArgs()
        {
            ObjectsPoints = new Point[][]
            {
                // Dodatkowo określając obszary, które chcemy usunąć.
                GetRectanglePoints(
                    new Rectangle(100, 100, 35, 90),
                    new Rectangle(300, 140, 95, 50)
                )
            },
        };

        results = maskingSession.ImproveDecomposition(newAutoMaskingArgs);

        using (RasterImage resultImage = results[1].GetImage())
        {
            resultImage.Save(dataDir +
                "result3.png",
                new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha });
        }
    }
}
//Przykłady - wykres - wycięcie - powtórzenie - maskowanie - za pomocą - nowych punktów.cs
// Aby poprawić wyniki maskowania, można podać dane dotyczące konkretnych obiektów, które powinny zostać uwzględnione w wyniku maskowania pierwszego planu.
assumedObjects = new List<AssumedObjectData>();
// Należy określić typ obiektu oraz obszar, w którym znajduje się ten obiekt.
assumedObjects.Add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(100, 100, 150, 300)));

// Pierwsza iteracja maskowania jest wykonywana w celu uzyskania automatycznie obliczonych pociągnięć pędzla pierwszego planu/tła.
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg"))
{
    // Aby użyć Graph Cut z automatycznie obliczonymi pociągnięciami, używana jest opcja AutoMaskingGraphCutOptions.
    options = new AutoMaskingGraphCutOptions
    {
        AssumedObjects = assumedObjects,
        // Wskazanie, że podczas dekompozycji obrazu należy wykonać nowe obliczenia domyślnych pociągnięć.
        CalculateDefaultStrokes = true,
        // Ustawianie promienia wtapiania po procesie.
        FeatheringRadius = 3,
        Method = SegmentationMethod.GraphCut,
        Decompose = false,
        ExportOptions =
                            new PngOptions()
                            {
                                ColorType = PngColorType.TruecolorWithAlpha,
                                Source = new FileCreateSource(dataDir + "result4.png")
                            },
        BackgroundReplacementColor = Color.Transparent
    };

    results = new ImageMasking(image).Decompose(options);

    // W tym momencie można przeanalizować zastosowane pociągnięcia pierwszego planu/tła i na ich podstawie dodać dodatkowe 
    // obrysy pierwszego planu/tła można wprowadzić ręcznie.
    appliedBackgroundStrokes = options.DefaultBackgroundStrokes;
    appliedForegroundStrokes = options.DefaultForegroundStrokes;
    appliedObjectRectangles = options.DefaultObjectsRectangles;
    using (RasterImage resultImage = (RasterImage)results[1].GetImage())
    {
        resultImage.Save(dataDir + "result5.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha });
    }
}



// Wykonywana jest druga iteracja maskowania w celu dalszej poprawy jakości maskowania poprzez dodanie nowych, ręcznie wybranych punktów pierwszego planu/tła.
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg"))
{
    // Ponowne użycie opcji AutoMaskingGraphCutOptions nie wymaga wykonywania domyślnych obliczeń obrysu po raz drugi.
    options.CalculateDefaultStrokes = false;
    // Gdy podane są zarówno domyślne obrysy, jak i obiekty ObjectsPoints we właściwości Args AutoMaskingArgs, tablice Point są ostatecznie łączone.
    // Pierwsza tablica ObjectsPoints jest uważana za tablicę punktów tła i 
    // druga tablica ObjectsPoints jest uważana za tablicę punktów pierwszego planu.
    // Jeśli we właściwości Args właściwości AutoMaskingArgs podano zarówno DefaultObjectsRectangles, jak i ObjectsRectangles, 
    // używana jest tylko tablica z Args.
    options.Args = new AutoMaskingArgs()
    {
        ObjectsPoints = new Point[][]
                                                {
                                                    new Point[] { new Point(100, 100), new Point(150, 100) },
                                                    new Point[] { new Point(300, 200) },
                                                },
        ObjectsRectangles = new Rectangle[]
                                                    {
                                                        new Rectangle(100, 100, 300, 300),
                                                    }
    };

    results = new ImageMasking(image).Decompose(options);

    // Zapisywanie końcowego wyniku maskowania.
    using (RasterImage resultImage = (RasterImage)results[1].GetImage())
    {
        resultImage.Save(dataDir + "result6.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha });
    }
}



///<summary>
/// Zwraca wszystkie punkty należące do określonych prostokątów.
///</summary>
///<param name="rectangles"> Tablica prostokątów.</param>
///<returns> Wszystkie punkty prostokątne.</returns>
static Point[] GetRectanglePoints(params Rectangle[] rectangles)
{
    int arraySize = 0;
    foreach (Rectangle rectangle in rectangles)
    {
        arraySize += rectangle.Width * rectangle.Height;
    }

    Point[] pointArray = new Point[arraySize];
    int arrayIndex = 0;
    foreach (Rectangle rectangle in rectangles)
    {
       for (int x = rectangle.Left; x < rectangle.Right; x++)
        {
           for (int y = rectangle.Top; y < rectangle.Bottom; y++)
            {
                pointArray[arrayIndex++] = new Point(x, y);
            }
        }
    }

    return pointArray;
}


File.Delete(dataDir + "result.png");
File.Delete(dataDir + "result2.png");
File.Delete(dataDir + "result3.png");
File.Delete(dataDir + "result4.png");
File.Delete(dataDir + "result5.png");
File.Delete(dataDir + "result6.png");

Poniższy zrzut ekranu przedstawia obrazy wejściowe i wyjściowe.

Powtarzane automatyczne maskowanie w celu usunięcia tła

Automatyczne maskowanie cięcia wykresu z określonymi założonymi danymi obiektu

W tej technice dane konkretnego założonego obiektu wykorzystywane są we właściwości AssumedObjects opcji AutoMaskingGraphCutOptions, która jest wykorzystywana w kolejnych iteracjach maskowania. Poniższy fragment kodu pokazuje, jak użyć automatycznego maskowania wycinanego wykresu z jednym założonym obiektem, aby usunąć tło obrazu.

using Aspose.Imaging;
using Aspose.Imaging.FileFormats.Png;
using Aspose.Imaging.ImageOptions;
using Aspose.Imaging.Masking;
using Aspose.Imaging.Masking.Options;
using Aspose.Imaging.Masking.Result;
using Aspose.Imaging.Sources;
using System;
using System.Collections.Generic;
using System.IO;

string templatesFolder = @"c:\Users\USER\Downloads\templates\";
string dataDir = templatesFolder;

// Aby poprawić wyniki maskowania, można podać dane dotyczące konkretnych obiektów, które powinny zostać uwzględnione w wyniku maskowania pierwszego planu.
List<AssumedObjectData> assumedObjects = new List<AssumedObjectData>();
// Należy określić typ obiektu oraz obszar, w którym znajduje się ten obiekt.
assumedObjects.Add(new AssumedObjectData(DetectedObjectType.Human, new Rectangle(0, 0, 256, 365)));

MaskingResult results;
using (RasterImage image = (RasterImage)Image.Load(dataDir + "couple.jpg"))
{
    // Aby użyć Graph Cut z automatycznie obliczonymi pociągnięciami, używana jest opcja AutoMaskingGraphCutOptions.
    AutoMaskingGraphCutOptions options = new AutoMaskingGraphCutOptions
    {
        AssumedObjects = assumedObjects,
        // Wskazanie, że podczas dekompozycji obrazu należy wykonać nowe obliczenie domyślnych pociągnięć.
        CalculateDefaultStrokes = true,
        // Ustawianie promienia wtapiania po procesie na podstawie rozmiaru obrazu.
        FeatheringRadius = (Math.Max(image.Width, image.Height) / 500) + 1,
        Method = SegmentationMethod.GraphCut,
        Decompose = false,
        ExportOptions =
                                                        new PngOptions()
                                                        {
                                                            ColorType = PngColorType.TruecolorWithAlpha,
                                                            Source = new FileCreateSource(dataDir + "result.png")
                                                        },
        BackgroundReplacementColor = Color.Transparent
    };

    results = new ImageMasking(image).Decompose(options);

    // Zapisywanie końcowego wyniku maskowania.
    using (RasterImage resultImage = (RasterImage)results[1].GetImage())
    {
        resultImage.Save(dataDir + "result2.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha });
    }
}



File.Delete(dataDir + "result.png");
File.Delete(dataDir + "result2.png");

Poniższy zrzut ekranu przedstawia obrazy wejściowe i wyjściowe.

Automatyczne maskowanie cięcia wykresu z założonym obiektem

Usuwanie tła obrazu za pomocą ręcznego maskowania

Jeśli nie interesuje Cię automatyczne maskowanie, możesz użyć ręcznej metody maskowania, aby usunąć tło z obrazów. Poniższy fragment kodu pokazuje, jak zastosować ręczne maskowanie obrazu rastrowego w celu usunięcia jego tła.

using Aspose.Imaging;
using Aspose.Imaging.FileFormats.Png;
using Aspose.Imaging.ImageOptions;
using Aspose.Imaging.Masking;
using Aspose.Imaging.Masking.Options;
using Aspose.Imaging.Masking.Result;
using Aspose.Imaging.Shapes;
using Aspose.Imaging.Sources;
using System.IO;

string templatesFolder = @"c:\Users\USER\Downloads\templates\";
string dataDir = templatesFolder;

string sourceFileName = dataDir + "couple.png";
GraphicsPath manualMask = new GraphicsPath();
Figure firstFigure = new Figure();
firstFigure.AddShape(new EllipseShape(new RectangleF(100, 30, 40, 40)));
firstFigure.AddShape(new RectangleShape(new RectangleF(10, 200, 50, 30)));
manualMask.AddFigure(firstFigure);
GraphicsPath subPath = new GraphicsPath();
Figure secondFigure = new Figure();
secondFigure.AddShape(
    new PolygonShape(
     new PointF[]
     {
         new PointF(310, 100), new PointF(350, 200), new PointF(250, 200)

     }, true));

secondFigure.AddShape(new PieShape(new RectangleF(10, 10, 80, 80), 30, 120));
subPath.AddFigure(secondFigure);
manualMask.AddPath(subPath);
using (RasterImage image = (RasterImage)Image.Load(sourceFileName))
{
    MaskingOptions maskingOptions = new MaskingOptions()
    {
        Method = SegmentationMethod.Manual,
        Args = new ManualMaskingArgs
        {
            Mask = manualMask
        },
        Decompose = false,
        ExportOptions =
      new PngOptions()
      {
          ColorType = PngColorType.TruecolorWithAlpha,
          Source = new StreamSource(new MemoryStream())
      },
    };
    MaskingResult results = new ImageMasking(image).Decompose(maskingOptions);
    // Zapisywanie końcowego wyniku maskowania.
    using (RasterImage resultImage = (RasterImage)results[1].GetImage())
    {
        resultImage.Save(dataDir + "result.png", new PngOptions() { ColorType = PngColorType.TruecolorWithAlpha });
    }
}       

File.Delete(dataDir + "result.png");

Poniższy zrzut ekranu przedstawia obrazy wejściowe i wyjściowe.

Ręczne maskowanie w celu usunięcia tła

Pobierz interfejs API usuwania tła obrazu w języku C#

Możesz uzyskać bezpłatną licencję tymczasową i korzystać z naszej biblioteki do edycji obrazów i usuwania tła bez żadnych ograniczeń.

Wniosek

Usuwanie tła z obrazów to kluczowa umiejętność w edycji i projektowaniu obrazów. Aspose.Imaging for .NET umożliwia programistom precyzyjne usuwanie tła z obrazów w aplikacjach C#. W tym poście na blogu omówiono podstawy ładowania obrazów, usuwanie tła przy użyciu różnych metod automatycznego i ręcznego maskowania oraz zapisywanie obrazu wyjściowego.

Integrując Aspose.Imaging z projektami C#, możesz usprawnić przepływ pracy przetwarzania obrazu i odblokować nowy poziom kreatywności w swoich aplikacjach. Eksperymentuj z różnymi funkcjami i technikami, aby odkryć pełny potencjał Aspose.Imaging for .NET. Podziel się z nami swoimi pytaniami również za pośrednictwem naszego forum.

Zobacz też