我正在GDI + WinForms中制作一个绘图应用程序,我有一个我想添加的功能,并试图添加,我在网上找不到任何关于它的内容。
我想拍摄一张图片(或位图,并不重要)并将其裁剪到其中所有内容的位置。
让我举个例子:
我这里有一张图片 它周围有相当多的白色(将图像保存到计算机上,看它周围有白色。)我想将图像裁剪到火柴人所在的区域,我希望它看起来像像这样:
(将其保存到您的计算机上,您可以比较两者)
如果你看第二个,这是我想要制作的,它已经将图像切割成了火柴人!
但是,当然,我自己也做过。
我在网上看了很多寻找解决方案但找不到一个,所以我决定尝试自己做,但是没有用。
这是我试过的:
我有一个带有图片框和按钮的简单表单 - 点击按钮后,它应该将图像裁剪下来。我将图片框的BackColor设为黑色,使图像居中,使图像中不再存在的区域为黑色。
图像存储在名为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);
}
如您所见,它使用我之前提到的CropImage
函数!
此函数有一个矩形,用于裁剪图像的位置 - 随着函数的进行,它会被修改。
该函数循环遍历位图中的所有像素,如果它不是白色,则忽略它 - 如果它是其他任何东西,但它会根据矩形周围的位置做某事,
如果它在矩形的左边,它将移动矩形的X并改变宽度,使矩形的右边仍然相同
如果它在矩形的顶部,它将向上移动矩形的Y并改变高度......
如果它在矩形的右侧,它将改变宽度以匹配。
如果它在矩形的底部,它将改变高度以匹配。
如果它在矩形内部,它根本不在乎。
我不明白为什么这个功能不起作用。
在表单Load
后运行此代码:
ImageToChange = Properties.Resources.stickman;
pictureBox1.Image = ImageToChange;
我将未触动的火柴人放入Properties.Resources.stickman
。
然后点击它运行的按钮:
ImageToChange = CropToContent(ImageToChange);
pictureBox1.Image = ImageToChange;
我不明白为什么这不起作用,非常感谢你,如果你读了整篇文章。
答案 0 :(得分:1)
我对你的意思有点了解并且没有工作&#34;但我认为我发现了这个问题。
错误在您的逻辑中,例如修改矩形右侧的代码行:
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;
您需要对逻辑的其余部分进行类似的更改。
答案 1 :(得分:0)
所以,答案终于来了,感谢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);
}
我想通过使用较小的图像进行调试时,我必须在第一个像素上设置矩形的起点 - 默认为0,0,如果第一个像素为2,则它将在右侧当然。
矩形延伸一个,现在位于0,0的位置,宽度为1 ...是的......这不正确 - 它需要从第一个像素的位置开始,所以我添加了这一点。
我当然修复了Robin Krom的逻辑,并且该功能在火柴人身上运行得非常好!
结果如下:
还值得注意的是,由于某种原因,if (oldBmp.GetPixel(x, y) != Color.FromArgb(255, 255, 255, 255))
行if (oldBmp.GetPixel(x, y) != Color.White)
曾经是@shared_task(name="analyze_atom", queue="atom")
def analyze_atom(image_urls, targetdir=target_path, studentuid=None):
return {}
@shared_task(name="summary_up", queue="summary")
def summary_up(rets, studentuid, images):
return {}
chord(analyze_atom.s([image]) for image in images)(summary_up.s(studentuid, images))
无效。