c#winforms gdi+;-将图像裁剪到它';内容

c#winforms gdi+;-将图像裁剪到它';内容,c#,winforms,bitmap,gdi+,crop,C#,Winforms,Bitmap,Gdi+,Crop,我正在GDI+WinForms中制作一个绘画应用程序,我想添加一个功能,并且已经尝试添加,但我在网上没有找到任何关于它的内容 我想拍摄一张图像(或位图,其实并不重要),并将其裁剪到所有内容所在的位置 让我举一个例子: 我这里有一个图像 它周围有很多白色(将图像保存到您的计算机以查看它周围有白色)。我想将图像裁剪到stickman所在的区域,我希望它看起来像这样: 。 (将其保存到您的计算机中,您可以对两者进行比较) 如果你看第二个,这是我想制作的,它已经把图像削减到只有粘贴人 但是,当然,我自

我正在GDI+WinForms中制作一个绘画应用程序,我想添加一个功能,并且已经尝试添加,但我在网上没有找到任何关于它的内容

我想拍摄一张图像(或位图,其实并不重要),并将其裁剪到所有内容所在的位置

让我举一个例子:

我这里有一个图像 它周围有很多白色(将图像保存到您的计算机以查看它周围有白色)。我想将图像裁剪到stickman所在的区域,我希望它看起来像这样:

(将其保存到您的计算机中,您可以对两者进行比较)

如果你看第二个,这是我想制作的,它已经把图像削减到只有粘贴人

但是,当然,我自己也做过

我在网上找了很多解决方案,但都找不到,所以我决定自己试试,但没用

以下是我尝试过的:

我有一个简单的表单,有一个图片框和一个按钮——点击按钮后,它会向下裁剪图像。我将图片框的背景颜色设为黑色,并将其置于图像中心,这样图像中不再存在的区域就变成了黑色

图像存储在名为
ImageToChange
的位图中

在点击按钮时,它会裁剪图像-所以我做了一个函数,我将从按钮调用它

此函数依赖于我在网上找到的另一个裁剪图像的函数:

public Bitmap CropImage(Image source, int x, int y, int width, int height)
    {
        Rectangle crop = new Rectangle(x, y, width, height);

        var bmp = new Bitmap(crop.Width, crop.Height);
        using (var gr = Graphics.FromImage(bmp))
        {
            gr.DrawImage(source, new Rectangle(0, 0, bmp.Width, bmp.Height), crop, GraphicsUnit.Pixel);
        }
        return bmp;
    }
上面的函数应该只是裁剪和图像的x,y,宽度和高度给它-我没有做的代码,但我可以看到它做什么

我的
CropToContent
功能最终取决于此

下面是我创建的用于裁剪图像的函数:

public Bitmap CropToContent(Bitmap oldBmp)
    {
        Rectangle currentRect = new Rectangle();

        // Get a base color

        for (int y = 0; y < oldBmp.Height; y++)
        {
            for (int x = 0; x < oldBmp.Width; x++)
            {
                if (oldBmp.GetPixel(x, y) != Color.White)
                {
                    // We need to interpret this!

                    if (!currentRect.Contains(new Point(x, y)))
                    {
                        // This will run if this is out of the current rectangle

                        if (x > (currentRect.X + currentRect.Width)) currentRect.Width += ((currentRect.X + currentRect.Width) + x);
                        if (x < (currentRect.X))
                        {
                            // Move the rectangle over there and extend it's width to make the right the same!
                            int oldRectLeft = currentRect.Left;

                            currentRect.X = x;
                            currentRect.Width += oldRectLeft - x;
                        }

                        if (y > (currentRect.Y + currentRect.Height)) currentRect.Height += ((currentRect.Y + currentRect.Height) + y);

                        if (y < (currentRect.Y + currentRect.Height))
                        {
                            int oldRectTop = currentRect.Top;

                            currentRect.Y = y;
                            currentRect.Height += oldRectTop - y;
                        }
                    }
                }
            }
        }
        return CropImage(oldBmp, currentRect.X, currentRect.Y, currentRect.Width, currentRect.Height);
    }
我将未触及的stickman放入
Properties.Resources.stickman

然后单击按钮运行:

ImageToChange = CropToContent(ImageToChange);

        pictureBox1.Image = ImageToChange;

我不明白这为什么行不通,如果你通读了整件事,我会非常感谢你。

我对你所说的“行不通”的意思有点理解,但我想我找到了问题所在

错误在您的逻辑中,例如修改矩形右侧的代码行:

if (x > (currentRect.X + currentRect.Width)) currentRect.Width += ((currentRect.X + currentRect.Width) + x);
这将通过添加错误的x、rectangle.x和rectangle.width来修改检测到的矩形的宽度。您想要的可能是:

if (x > (currentRect.X + currentRect.Width)) currentRect.Width = x - currentRect.X;

你需要对逻辑的其余部分进行类似的更改。

因此,答案终于出来了,这要感谢Hans Passant指出,我应该仔细检查一下,并密切关注它,因为它是一个非常小的图像

罗宾·克罗姆说有些逻辑是错误的

这就是最终结果:

public Bitmap CropToContent(Bitmap oldBmp)
    {
        Rectangle currentRect = new Rectangle();
        bool IsFirstOne = true;

        // Get a base color

        for (int y = 0; y < oldBmp.Height; y++)
        {
            for (int x = 0; x < oldBmp.Width; x++)
            {
                Color debug = oldBmp.GetPixel(x, y);
                if (oldBmp.GetPixel(x, y) != Color.FromArgb(255, 255, 255, 255))
                {
                    // We need to interpret this!

                    // Check if it is the first one!

                    if (IsFirstOne)
                    {
                        currentRect.X = x;
                        currentRect.Y = y;
                        currentRect.Width = 1;
                        currentRect.Height = 1;
                        IsFirstOne = false;
                    }
                    else
                    {

                        if (!currentRect.Contains(new Point(x, y)))
                        {
                            // This will run if this is out of the current rectangle

                            if (x > (currentRect.X + currentRect.Width)) currentRect.Width = x - currentRect.X;
                            if (x < (currentRect.X))
                            {
                                // Move the rectangle over there and extend it's width to make the right the same!
                                int oldRectLeft = currentRect.Left;

                                currentRect.X = x;
                                currentRect.Width += oldRectLeft - x;
                            }

                            if (y > (currentRect.Y + currentRect.Height)) currentRect.Height = y - currentRect.Y;

                            if (y < (currentRect.Y + currentRect.Height))
                            {
                                int oldRectTop = currentRect.Top;

                                currentRect.Y = y;
                                currentRect.Height += oldRectTop - y;
                            }
                        }
                    }
                }
            }
        }
        return CropImage(oldBmp, currentRect.X, currentRect.Y, currentRect.Width, currentRect.Height);
    }
公共位图内容(位图oldBmp)
{
矩形currentRect=新矩形();
bool IsFirstOne=true;
//获得底色
对于(int y=0;y(currentRect.x+currentRect.Width))currentRect.Width=x-currentRect.x;
如果(x<(currentRect.x))
{
//将矩形移动到那里,并扩展其宽度,使右侧相同!
int oldRectLeft=currentRect.Left;
currentRect.X=X;
currentRect.Width+=oldRectLeft-x;
}
如果(y>(currentRect.y+currentRect.Height))currentRect.Height=y-currentRect.y;
如果(y<(当前矩形y+当前矩形高度))
{
int oldRectTop=currentRect.Top;
currentRect.Y=Y;
currentRect.Height+=oldRectTop-y;
}
}
}
}
}
}
返回CropImage(oldBmp、currentRect.X、currentRect.Y、currentRect.Width、currentRect.Height);
}
我发现在调试较小的图像时,在第一个像素上,我必须设置矩形的起点-它默认为0,0,如果第一个像素为2,2,它当然将位于右侧

矩形延伸一个,现在位于0的位置,0的宽度为1。。。是 啊这不正确-它需要从第一个像素的位置开始,所以我添加了这个

当然,多亏了罗宾·克罗姆,我修正了逻辑,这个函数在斯蒂克曼身上运行得非常完美

所以它是这样开始的:

结果是:


还值得注意的是,
if(oldBmp.GetPixel(x,y)!=Color.FromArgb(255,255,255,255))
行过去是
if(oldBmp.GetPixel(x,y)!=Color.White)
行,但由于某些原因,它不起作用。

调试代码时总是从小开始,此图像的像素太多,您很容易失去耐心。从1x1位图开始,很好地检查边界条件。
public Bitmap CropToContent(Bitmap oldBmp)
    {
        Rectangle currentRect = new Rectangle();
        bool IsFirstOne = true;

        // Get a base color

        for (int y = 0; y < oldBmp.Height; y++)
        {
            for (int x = 0; x < oldBmp.Width; x++)
            {
                Color debug = oldBmp.GetPixel(x, y);
                if (oldBmp.GetPixel(x, y) != Color.FromArgb(255, 255, 255, 255))
                {
                    // We need to interpret this!

                    // Check if it is the first one!

                    if (IsFirstOne)
                    {
                        currentRect.X = x;
                        currentRect.Y = y;
                        currentRect.Width = 1;
                        currentRect.Height = 1;
                        IsFirstOne = false;
                    }
                    else
                    {

                        if (!currentRect.Contains(new Point(x, y)))
                        {
                            // This will run if this is out of the current rectangle

                            if (x > (currentRect.X + currentRect.Width)) currentRect.Width = x - currentRect.X;
                            if (x < (currentRect.X))
                            {
                                // Move the rectangle over there and extend it's width to make the right the same!
                                int oldRectLeft = currentRect.Left;

                                currentRect.X = x;
                                currentRect.Width += oldRectLeft - x;
                            }

                            if (y > (currentRect.Y + currentRect.Height)) currentRect.Height = y - currentRect.Y;

                            if (y < (currentRect.Y + currentRect.Height))
                            {
                                int oldRectTop = currentRect.Top;

                                currentRect.Y = y;
                                currentRect.Height += oldRectTop - y;
                            }
                        }
                    }
                }
            }
        }
        return CropImage(oldBmp, currentRect.X, currentRect.Y, currentRect.Width, currentRect.Height);
    }