我正在寻找c#managed GDI +库中检测c#位图的边缘空白的解决方案。
图像可以是透明或白色,大部分400x图片都是8000x8000px,边缘周围有大约2000px的空白。
找出边缘的最有效方法是什么, x,y,高度和宽度坐标?我尝试逐像素,但发现它很慢。
更新解决方案 - 增加左/右/上/下边界
图像细节中心图像出现问题,现在裁剪任何透明(0%)或白色(#FFFFFF)像素。
var top = bitmap.Height;
var left = bitmap.Width;
var right = 0;
var bottom = 0;
...
var pData = pData0 + (y * data.Stride) + (x * 4);
var xyAlpha = pData[3];
var xyBlue = pData[0];
var xyGreen = pData[1];
var xyRed = pData[2];
if ((xyAlpha > 0) || (xyRed != 255 && xyGreen != 255 && xyBlue != 255)) {
if (y < top)
top = y;
if (y > bottom)
bottom = y;
if (x < left)
left = x;
if (x > right)
right = x;
}
...
var cropWidth = right - left;
var cropHeight = bottom - top;
var cropX = top;
var cropY = left;
var cacheBitmap = new Bitmap(cropWidth, cropHeight, PixelFormat.Format32bppArgb);
using (var cacheGraphics = Graphics.FromImage(cacheBitmap)) {
cacheGraphics.DrawImage(context.Image, new Rectangle(0, 0, cropWidth, cropHeight), cropX, cropY, cropWidth, cropHeight, GraphicsUnit.Pixel);
}
答案 0 :(得分:9)
一个很棒的GDI +资源是Bob Powells GDI+ FAQ!
您没有说明如何访问图像中的像素,因此我假设您使用了慢速GetPixel方法。您可以使用指针和LockBits以更快的方式访问像素:see Bob Powells explanation of LockBits - 这将需要一个不安全的代码块 - 如果你不想要这个或你没有FullTrust,你可以使用这里解释的技巧:Pointerless Image Processing in .NET by J. Dunlap
下面的代码使用LockBits方法(对于PixelFormat.Format32bppArgb),并将使用发现图像中第一个和最后一个像素的值填充起点和终点,这些像素没有参数颜色中描述的颜色。该方法还忽略了完全透明的像素,如果您想要检测可见“内容”开始的图像区域,这种方法非常有用。
Point start = Point.Empty;
Point end = Point.Empty;
int bitmapWidth = bmp.Width;
int bitmapHeight = bmp.Height;
#region find start and end point
BitmapData data = bmp.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
try
{
unsafe
{
byte* pData0 = (byte*)data.Scan0;
for (int y = 0; y < bitmapHeight; y++)
{
for (int x = 0; x < bitmapWidth; x++)
{
byte* pData = pData0 + (y * data.Stride) + (x * 4);
byte xyBlue = pData[0];
byte xyGreen = pData[1];
byte xyRed = pData[2];
byte xyAlpha = pData[3];
if (color.A != xyAlpha
|| color.B != xyBlue
|| color.R != xyRed
|| color.G != xyGreen)
{
//ignore transparent pixels
if (xyAlpha == 0)
continue;
if (start.IsEmpty)
{
start = new Point(x, y);
}
else if (start.Y > y)
{
start.Y = y;
}
if (end.IsEmpty)
{
end = new Point(x, y);
}
else if (end.X < x)
{
end.X = x;
}
else if (end.Y < y)
{
end.Y = y;
}
}
}
}
}
}
finally
{
bmp.UnlockBits(data);
}
#endregion
答案 1 :(得分:2)
我首先要确保使用Patrick描述的LockBits方法。其次,我检查中间线上的像素以快速确定边缘。中间线我的意思是,如果你说例如2000x1000图像,你首先沿水平线500(1000个)查找左边和右边限制,然后沿垂直线编号1000(2000年)找到顶部和底部限制。这种方式应该非常快。