Temel fikir, görüntünün her bir pikseli için görüntünün üst, sol, sağ ve alt sınırlarını bulmaktır. Bunu verimli bir şekilde yapmak için, oldukça yavaş olan GetPixel
yöntemini kullanmayın. Bunun yerine LockBits
kullanın. İşte
ben ile geldi uygulama görebilirsiniz: ... Muhtemelen optimize edilebilir
static Bitmap TrimBitmap(Bitmap source)
{
Rectangle srcRect = default(Rectangle);
BitmapData data = null;
try
{
data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] buffer = new byte[data.Height * data.Stride];
Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);
int xMin = int.MaxValue;
int xMax = 0;
int yMin = int.MaxValue;
int yMax = 0;
for (int y = 0; y < data.Height; y++)
{
for (int x = 0; x < data.Width; x++)
{
byte alpha = buffer[y * data.Stride + 4 * x + 3];
if (alpha != 0)
{
if (x < xMin) xMin = x;
if (x > xMax) xMax = x;
if (y < yMin) yMin = y;
if (y > yMax) yMax = y;
}
}
}
if (xMax < xMin || yMax < yMin)
{
// Image is empty...
return null;
}
srcRect = Rectangle.FromLTRB(xMin, yMin, xMax, yMax);
}
finally
{
if (data != null)
source.UnlockBits(data);
}
Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height);
Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height);
using (Graphics graphics = Graphics.FromImage(dest))
{
graphics.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel);
}
return dest;
}
, ama GDI + uzmanı değilim, bu yüzden ben daha fazla araştırma yapmadan gelenin en iyisi
DÜZENLEME:
- tarama righ soldan: aslında resmin bazı bölümlerini tarayarak vermeyerek, bunu optimize etmek için basit bir yol var saydam olmayan bir piksel bulana kadar; saydam olmayan bir piksel bulana kadar yukarıya doğru tara (x, y) (xMin, yMin)
- (x> = xMin için); Saydam olmayan bir piksel bulana kadar sağa sola tarama yapın (yalnızca y> = yMin için); xMax
- 'u şeffaf olmayan bir piksel bulana kadar aşağıdan yukarıya tarayın (yalnızca xMin için < = x < = xMax); Şeffaf olmayan kısmı elbette küçükse beri
static Bitmap TrimBitmap(Bitmap source)
{
Rectangle srcRect = default(Rectangle);
BitmapData data = null;
try
{
data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] buffer = new byte[data.Height * data.Stride];
Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);
int xMin = int.MaxValue,
xMax = int.MinValue,
yMin = int.MaxValue,
yMax = int.MinValue;
bool foundPixel = false;
// Find xMin
for (int x = 0; x < data.Width; x++)
{
bool stop = false;
for (int y = 0; y < data.Height; y++)
{
byte alpha = buffer[y * data.Stride + 4 * x + 3];
if (alpha != 0)
{
xMin = x;
stop = true;
foundPixel = true;
break;
}
}
if (stop)
break;
}
// Image is empty...
if (!foundPixel)
return null;
// Find yMin
for (int y = 0; y < data.Height; y++)
{
bool stop = false;
for (int x = xMin; x < data.Width; x++)
{
byte alpha = buffer[y * data.Stride + 4 * x + 3];
if (alpha != 0)
{
yMin = y;
stop = true;
break;
}
}
if (stop)
break;
}
// Find xMax
for (int x = data.Width - 1; x >= xMin; x--)
{
bool stop = false;
for (int y = yMin; y < data.Height; y++)
{
byte alpha = buffer[y * data.Stride + 4 * x + 3];
if (alpha != 0)
{
xMax = x;
stop = true;
break;
}
}
if (stop)
break;
}
// Find yMax
for (int y = data.Height - 1; y >= yMin; y--)
{
bool stop = false;
for (int x = xMin; x <= xMax; x++)
{
byte alpha = buffer[y * data.Stride + 4 * x + 3];
if (alpha != 0)
{
yMax = y;
stop = true;
break;
}
}
if (stop)
break;
}
srcRect = Rectangle.FromLTRB(xMin, yMin, xMax, yMax);
}
finally
{
if (data != null)
source.UnlockBits(data);
}
Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height);
Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height);
using (Graphics graphics = Graphics.FromImage(dest))
{
graphics.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel);
}
return dest;
}
önemli kazanım olmayacak: yMax
EDIT2 içine mağaza y: Burada yukarıdaki yaklaşımın bir uygulama var hala piksellerin çoğunu tarayacak. Ama büyükse, sadece şeffaf olmayan kısımdaki dikdörtgenler taranacaktır.
Kesinti düzgün mü? öyleyse, L-> R ve T-> B piksellerini okumak çok çabuk çalışırdı. –
Kare kare ise, daha da fazla zaman kazandırabilir ve ikili aramaları 4 kenardan merkezden uzaklaştırabilirsiniz (en azından piksel sorgularını kesme) –
Küçük, gömülü görüntüde ayrıca saydam pikseller bulunabilir mi? –