【问题标题】:C# - Crop Transparent/White spaceC# - 裁剪透明/空白区域
【发布时间】:2011-03-17 07:52:09
【问题描述】:

我正在尝试从图像中删除所有白色或透明像素,留下实际图像(裁剪)。我尝试了一些解决方案,但似乎都没有奏效。有什么建议吗?还是我要花一晚上写图像裁剪代码?

【问题讨论】:

  • 那么还有其他人梦想着一遍又一遍地编写同一行代码吗?我以为我是唯一的一个:-)
  • 如果你至少详细说明你的一种方法并解释它是如何不起作用的,这将对社区有所帮助。

标签: c# asp.net image-processing gdi+ crop


【解决方案1】:

因此,您要做的是找到顶部、最左侧的非白色/透明像素和底部、最右侧的非白色/透明像素。这两个坐标会给你一个矩形,然后你可以提取它。

  // Load the bitmap
  Bitmap originalBitmap = Bitmap.FromFile("d:\\temp\\test.bmp") as Bitmap;

  // Find the min/max non-white/transparent pixels
  Point min = new Point(int.MaxValue, int.MaxValue);
  Point max = new Point(int.MinValue, int.MinValue);

  for (int x = 0; x < originalBitmap.Width; ++x)
  {
    for (int y = 0; y < originalBitmap.Height; ++y)
    {
      Color pixelColor = originalBitmap.GetPixel(x, y);
      if (!(pixelColor.R == 255 && pixelColor.G == 255 && pixelColor.B == 255)
        || pixelColor.A < 255)
      {
        if (x < min.X) min.X = x;
        if (y < min.Y) min.Y = y;

        if (x > max.X) max.X = x;
        if (y > max.Y) max.Y = y;
      }
    }
  }

  // Create a new bitmap from the crop rectangle
  Rectangle cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X, max.Y - min.Y);
  Bitmap newBitmap = new Bitmap(cropRectangle.Width, cropRectangle.Height);
  using (Graphics g = Graphics.FromImage(newBitmap))
  {
    g.DrawImage(originalBitmap, 0, 0, cropRectangle, GraphicsUnit.Pixel);
  }

【讨论】:

  • 很好的解决方案!我删除了|| pixelColor.A &lt; 255 以使其正常工作。
【解决方案2】:
public Bitmap CropBitmap(Bitmap original)
{
    // determine new left
    int newLeft = -1;
    for (int x = 0; x < original.Width; x++)
    {
        for (int y = 0; y < original.Height; y++)
        {
            Color color = original.GetPixel(x, y);
            if ((color.R != 255) || (color.G != 255) || (color.B != 255) || 
                (color.A != 0))
            {
                // this pixel is either not white or not fully transparent
                newLeft = x;
                break;
            }
        }
        if (newLeft != -1)
        {
            break;
        }

        // repeat logic for new right, top and bottom

    }

    Bitmap ret = new Bitmap(newRight - newLeft, newTop - newBottom);
    using (Graphics g = Graphics.FromImage(ret)
    {
        // copy from the original onto the new, using the new coordinates as
        // source coordinates for the original
        g.DrawImage(...);
    }

    return ret
}

请注意,此功能会像泥土一样缓慢。 GetPixel() 非常慢,在循环中访问 BitmapWidthHeight 属性也很慢。 LockBits 是这样做的正确方法 - StackOverflow 上有大量示例。

【讨论】:

  • 谢谢,这让我成功了一半。唯一的问题是,如果图像大于指定大小,我还想调整图像大小。有比 cmets 框容纳的更多代码,但原始图像只占最终图像的一半左右。代码在pastebin.com/He3S8aCH
  • 我转置了两个变量:P。问题已解决,期待很快的博文(将在此处链接)。
  • 我想我也搞砸了。表示color.R != 0 等的位实际上应该表示color.R != 255,因为白色像素的 R、G 和 B 值分别为 255(0,0,0 的 RGB 为黑色)。如果原始版本适合您,那么它可能只裁剪了透明(和黑色)像素。
  • 另外,代码可能应该首先检查 A 值以查看像素是否透明,然后仅在像素 透明时检查 RGB 值。否则,检查将停止在任何完全透明 (A = 0) 的非白色像素上(尽管我怀疑这在位图中很常见)。
【解决方案3】:

在 WPF 中,我们有一个 WriteableBitmap 类。这是你要找的吗?如果是这样,请查看http://blogs.msdn.com/b/jgalasyn/archive/2008/04/17/using-writeablebitmap-to-display-a-procedural-texture.aspx

【讨论】:

    【解决方案4】:

    每像素检查应该可以解决问题。扫描每一行以从顶部和底部查找空行,扫描每一行以查找左右约束(这可以通过行或列一次性完成)。当找到约束时 - 将图像的一部分复制到另一个缓冲区。

    【讨论】:

      【解决方案5】:

      我找到了一种在大约 10 分钟内批量修剪几千个 .jpg 文件的方法,但我没有在代码中执行此操作。我使用了 Snag-It Editor 的转换功能。我不知道这是否适合您,如果您需要进行一次修剪或您的需求仍在持续,但对于软件的价格,这不是很多,我认为这是一个不错的解决方法。 (我不为 Techsmith 工作或代表 Techsmith。)

      乔伊

      【讨论】:

        猜你喜欢
        • 2013-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多