[C#] 이미지에서 주변 공백을 제거하십시오.


Answers

Dmitri의 답변을 조정해야한다는 사실을 발견했습니다. 실제로는 자르기 (수평, 수직 또는 양쪽 모두)가 필요하지 않은 이미지와 함께 작동합니다.

    public static Bitmap Crop(Bitmap bmp)
    {
        int w = bmp.Width;
        int h = bmp.Height;

        Func<int, bool> allWhiteRow = row =>
        {
            for (int i = 0; i < w; ++i)
                if (bmp.GetPixel(i, row).R != 255)
                    return false;
            return true;
        };

        Func<int, bool> allWhiteColumn = col =>
        {
            for (int i = 0; i < h; ++i)
                if (bmp.GetPixel(col, i).R != 255)
                    return false;
            return true;
        };

        int topmost = 0;
        for (int row = 0; row < h; ++row)
        {
            if (allWhiteRow(row))
                topmost = row;
            else break;
        }

        int bottommost = 0;
        for (int row = h - 1; row >= 0; --row)
        {
            if (allWhiteRow(row))
                bottommost = row;
            else break;
        }

        int leftmost = 0, rightmost = 0;
        for (int col = 0; col < w; ++col)
        {
            if (allWhiteColumn(col))
                leftmost = col;
            else
                break;
        }

        for (int col = w - 1; col >= 0; --col)
        {
            if (allWhiteColumn(col))
                rightmost = col;
            else
                break;
        }

        if (rightmost == 0) rightmost = w; // As reached left
        if (bottommost == 0) bottommost = h; // As reached top.

        int croppedWidth = rightmost - leftmost;
        int croppedHeight = bottommost - topmost;

        if (croppedWidth == 0) // No border on left or right
        {
            leftmost = 0;
            croppedWidth = w;
        }

        if (croppedHeight == 0) // No border on top or bottom
        {
            topmost = 0;
            croppedHeight = h;
        }

        try
        {
            var target = new Bitmap(croppedWidth, croppedHeight);
            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(bmp,
                  new RectangleF(0, 0, croppedWidth, croppedHeight),
                  new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
                  GraphicsUnit.Pixel);
            }
            return target;
        }
        catch (Exception ex)
        {
            throw new Exception(
              string.Format("Values are topmost={0} btm={1} left={2} right={3} croppedWidth={4} croppedHeight={5}", topmost, bottommost, leftmost, rightmost, croppedWidth, croppedHeight),
              ex);
        }
    }
Question

고객으로부터받은 제품 이미지 블록이 있습니다. 각 제품 이미지는 무언가의 그림이며 흰색 배경으로 찍은 것입니다. 이미지의 모든 주변 부분을 자르고 싶지만 제품은 중간에 두십시오. 이것이 가능한가?

예를 들면 다음과 같습니다 [ http://www.5dnet.de/media/catalog/product/d/r/dress_shoes_5.jpg][1] [1 http://www.5dnet.de/media/catalog/product/d/r/dress_shoes_5.jpg][1]

모든 흰색 픽셀을 제거하고 싶지는 않지만 가장 위의 픽셀 행에 하나의 흰색이 아닌 픽셀이 포함되도록 이미지를 잘라 내고 싶습니다. 가장 왼쪽의 픽셀 행에는 흰색이 아닌 픽셀 하나가 포함되어 있습니다. 대부분의 수평 픽셀 행은 하나의 비 - 백색 픽셀 등을 포함한다.

C # 또는 VB.net의 코드는 인정 될 것입니다.




나는 큰 이미지 (GetPixel은 느리다)에서 작업 한 솔루션이 필요했기 때문에 아래의 확장 메소드를 작성했다. 제한된 테스트에서 잘 작동하는 것 같습니다. 단점은 프로젝트에서 "안전하지 않은 코드 허용"을 확인해야한다는 것입니다.

public static Image AutoCrop(this Bitmap bmp)
{
    if (Image.GetPixelFormatSize(bmp.PixelFormat) != 32)
        throw new InvalidOperationException("Autocrop currently only supports 32 bits per pixel images.");

    // Initialize variables
    var cropColor = Color.White;

    var bottom = 0;
    var left = bmp.Width; // Set the left crop point to the width so that the logic below will set the left value to the first non crop color pixel it comes across.
    var right = 0;
    var top = bmp.Height; // Set the top crop point to the height so that the logic below will set the top value to the first non crop color pixel it comes across.

    var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

    unsafe
    {
        var dataPtr = (byte*)bmpData.Scan0;

        for (var y = 0; y < bmp.Height; y++)
        {
            for (var x = 0; x < bmp.Width; x++)
            {
                var rgbPtr = dataPtr + (x * 4);

                var b = rgbPtr[0];
                var g = rgbPtr[1];
                var r = rgbPtr[2];
                var a = rgbPtr[3];

                // If any of the pixel RGBA values don't match and the crop color is not transparent, or if the crop color is transparent and the pixel A value is not transparent
                if ((cropColor.A > 0 && (b != cropColor.B || g != cropColor.G || r != cropColor.R || a != cropColor.A)) || (cropColor.A == 0 && a != 0))
                {
                    if (x < left)
                        left = x;

                    if (x >= right)
                        right = x + 1;

                    if (y < top)
                        top = y;

                    if (y >= bottom)
                        bottom = y + 1;
                }
            }

            dataPtr += bmpData.Stride;
        }
    }

    bmp.UnlockBits(bmpData);

    if (left < right && top < bottom)
        return bmp.Clone(new Rectangle(left, top, right - left, bottom - top), bmp.PixelFormat);

    return null; // Entire image should be cropped, so just return null
}



위쪽과 왼쪽에 나머지 1px 공백을 수정하십시오.

    public Bitmap Crop(Bitmap bitmap)
    {
        int w = bitmap.Width;
        int h = bitmap.Height;

        Func<int, bool> IsAllWhiteRow = row =>
        {
            for (int i = 0; i < w; i++)
            {
                if (bitmap.GetPixel(i, row).R != 255)
                {
                    return false;
                }
            }
            return true;
        };

        Func<int, bool> IsAllWhiteColumn = col =>
        {
            for (int i = 0; i < h; i++)
            {
                if (bitmap.GetPixel(col, i).R != 255)
                {
                    return false;
                }
            }
            return true;
        };

        int leftMost = 0;
        for (int col = 0; col < w; col++)
        {
            if (IsAllWhiteColumn(col)) leftMost = col + 1;
            else break;
        }

        int rightMost = w - 1;
        for (int col = rightMost; col > 0; col--)
        {
            if (IsAllWhiteColumn(col)) rightMost = col - 1;
            else break;
        }

        int topMost = 0;
        for (int row = 0; row < h; row++)
        {
            if (IsAllWhiteRow(row)) topMost = row + 1;
            else break;
        }

        int bottomMost = h - 1;
        for (int row = bottomMost; row > 0; row--)
        {
            if (IsAllWhiteRow(row)) bottomMost = row - 1;
            else break;
        }

        if (rightMost == 0 && bottomMost == 0 && leftMost == w && topMost == h)
        {
            return bitmap;
        }

        int croppedWidth = rightMost - leftMost + 1;
        int croppedHeight = bottomMost - topMost + 1;

        try
        {
            Bitmap target = new Bitmap(croppedWidth, croppedHeight);
            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(bitmap,
                    new RectangleF(0, 0, croppedWidth, croppedHeight),
                    new RectangleF(leftMost, topMost, croppedWidth, croppedHeight),
                    GraphicsUnit.Pixel);
            }
            return target;
        }
        catch (Exception ex)
        {
            throw new Exception(string.Format("Values are top={0} bottom={1} left={2} right={3}", topMost, bottomMost, leftMost, rightMost), ex);
        }
    }



Links