C#에서 이미지 처리: 투명 영역을 잘라내기

12896 단어 이미지 처리C#.NET

원하는 것



물체 주위에 투명한 영역이 있는 이미지에서

물체가 그려진 영역만

잘라서 파일에 저장하고 싶습니다.


※ 이미지는 이라 스토 야의 검은 한판

할 일


  • 이미지 파일로드
  • 투명하지 않은 영역 감지
  • 이미지의 일부를 잘라냅니다
  • 이미지 저장

  • 0. 준비



    이미지 처리에는 System.Drawing 네임스페이스의 API 를 사용하므로 using 해 둔다.
    using System.Drawing;
    

    .NET Framework의 경우 System.Drawing 어셈블리에 대한 참조를 추가해야 합니다.

    .NET Core의 경우 System.Drawing.Common NuGet 패키지를 설치해야 합니다.
    dotnet add package System.Drawing.Common
    

    Linux의 경우 libgdiplus도 필요하므로 설치하십시오.
    sudo apt install libgdiplus
    

    1. 이미지 파일 불러오기



    이미지 파일을 읽으려면 System.Drawing.Bitmap 클래스를 사용하십시오.
    var bmp = new Bitmap(filename);
    

    Bitmap 클래스는 BMP, GIF, EXIF, JPG, PNG, TIFF 형식을 지원하고 있다.

    다만 이번에는 색에 투명(알파치:불투명도)을 포함한 화상이 필요하므로, 아래와 같은 체크를 넣어 둔다.
    if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
    {
        Console.WriteLine($"Not Format32bppArgb: {bmp.PixelFormat}");
        return;
    }
    

    2. 투명하지 않은 영역 감지



    Bitmap 객체의 투명하지 않은 영역의 직사각형을 검출한다.



    픽셀의 색의 검출은 이미지를 바이트 열로 변환하여 값을 참조함으로써 가능하다.
    PixelFormat.Format32bppArgb 포맷에서는 1픽셀 4바이트, BGRA의 순서에 1바이트씩 들어간다. ※리틀 엔디안의 경우

    예를 들어 다음과 같은 크기 2x2의 이미지가있는 경우,

    이런 바이트열이 된다.


    투명하지 않은 픽셀의 위, 아래, 왼쪽, 오른쪽(y0, y1, x0, x1)의 좌표를 검출해, Rectangle 객체를 돌려주는 메소드.
    static Rectangle GetRect(Bitmap bmp)
    {
        // 画像のピクセルを byte[] にコピーする
        var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        var bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
        var bytes = Math.Abs(bmpData.Stride) * bmp.Height;
        var rgbValues = new byte[bytes];
        System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, rgbValues, 0, bytes);
        bmp.UnlockBits(bmpData);
    
        int x0 = bmp.Width;
        int y0 = bmp.Height;
        int x1 = 0;
        int y1 = 0;
    
        // 透明でないピクセルを探す
        for (int i = 3; i < rgbValues.Length; i += 4)
        {
            // Aの値が0なら透明ピクセル
            if (rgbValues[i] != 0)
            {
                int x = i / 4 % bmp.Width;
                int y = i / 4 / bmp.Width;
    
                if (x0 > x) x0 = x;
                if (y0 > y) y0 = y;
                if (x1 < x) x1 = x;
                if (y1 < y) y1 = y;
            }
        }
    
        return new Rectangle(x0, y0, x1 - x0, y1 - y0);
    }
    
    

    덧붙여서, Bitmap 클래스에는 픽셀의 색을 취득한다.

    3. 이미지의 일부를 잘라내기



    Bitmap 객체로부터 Rectangle 로 지정한 영역을 잘라내, 새로운 Bitmap 객체를 생성하는 메소드.
    Bitmap Crop(Bitmap bmp, Rectangle rect)
    {
        var newbmp = new Bitmap(rect.Width, rect.Height);
        using (var g = Graphics.FromImage(newbmp))
        {
            g.DrawImage(bmp, 0, 0, rect, GraphicsUnit.Pixel);
        }
        return newbmp;
    }
    

    4. 이미지 저장


    newbmp.Save(filename);
    

    조금 이해하기 어려운데, 한판 주위의 영역이 좁아지고 있는 food_kuro_hanpen2.png 가 생성되었다.


    소스 코드 전체



    GitHub

    참고


  • .NET을 통한 이미지 처리 가속화 Tips: 비unsafe편
  • Bitmap.LockBits 메서드
  • 좋은 웹페이지 즐겨찾기