c# - 如何避免在具有透明背景的调整大小的 PNG 中出现无用的白色边框?

标签 c# image-processing resize transparency system.drawing.imaging

我有一个包含大约 2500 张 PNG 图像的文件夹,没有透明度。每张图片大约为 500 x 500(有些是 491 x 433,有些是 511 x 499 等)。

我想以编程方式将每个图像缩小到其原始大小的 10%,并将每个图像的白色背景设置为透明色。

为了在每次不调整 2500 张图片的情况下测试我的应用程序的功能,我使用了 15 张台球图片作为“测试”文件夹。

现在我的问题是以下代码,我得到一个调整大小和裁剪的 PNG,具有几乎透明背景。问题是在每个图像查看器(Irfan View、Paint.Net 和 GIMP)中左侧和顶部出现白色边框

我怎样才能避免这个边界?

这是我为此使用的代码:

void ResizeI(string[] Paths, string OutPut, Methods m, PointF Values, bool TwoCheck, bool Overwrite, float[] CropVals)
    {
        for (int i = 0; i < Paths.Length; i++)//Paths is the array of all images
        {
            string Path = Paths[i];//current image
            Bitmap Oimg = (Bitmap)Bitmap.FromFile(Path);//original image
            Bitmap img = new Bitmap((int)(Oimg.Width - CropVals[0] - CropVals[1]), (int)(Oimg.Height - CropVals[2] - CropVals[3]));//cropped image
            Graphics ggg = Graphics.FromImage(img);
            ggg.DrawImage(Oimg, new RectangleF(((float)-CropVals[0]), ((float)-CropVals[2]), Oimg.Width - CropVals[1], Oimg.Height - CropVals[3]));
            ggg.Flush(System.Drawing.Drawing2D.FlushIntention.Flush);
            ggg.Dispose();
            PointF scalefactor = GetScaleFactor(img, Values, TwoCheck);//the scale factor equals 0.1 for 10%
            Bitmap newimg = new Bitmap((int)(Math.Ceiling(((float)img.Width) * scalefactor.X)), (int)(Math.Ceiling(((float)img.Height) * scalefactor.Y)));
            System.Drawing.Imaging.ImageFormat curform = img.RawFormat;
            string OutPath = System.IO.Path.Combine(OutPut, System.IO.Path.GetFileName(Path));
            OutPath = CheckPath(OutPath, Overwrite);//Delete if exsits
            Graphics g = Graphics.FromImage(newimg);
            g.InterpolationMode = GetModeFromMethod(m);//Bicubic interpolation
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.ScaleTransform(scalefactor.X, scalefactor.Y);
            g.DrawImage(img, new Rectangle(0, 0, (int)Math.Ceiling(((float)newimg.Width) / scalefactor.X) + 1, (int)Math.Ceiling(((float)newimg.Height) / scalefactor.Y) + 1));
            //g.Flush(System.Drawing.Drawing2D.FlushIntention.Flush);
            newimg.MakeTransparent(Color.White);
            newimg.Save(OutPath, curform);
            g.Dispose();
            img.Dispose();
        }
    }

这是我提到的白色边框的示例。下载图片或四处拖动并在其下方放置黑色背景以查看边框:

The resized Image and the white border

-- 编辑--

我设法编写了这个函数而不是 newimg.MakeTransparent(...):

 void SetTransparent(ref Bitmap b)
    {
        for (int i = 0; i < b.Width; i++)
        {
            for (int ii = 0; ii < b.Height; ii++)
            {
                Color cc = b.GetPixel(i, ii);
                int tog = cc.R + cc.G + cc.B;
                float durch = 255f - (((float)tog) / 3f);
                b.SetPixel(i, ii, Color.FromArgb((int)durch, cc.R, cc.G, cc.B));
            }
        }
    }

问题是我的台球现在看起来像这样:

Second version of the billiard ball

最佳答案

我无法提供具体代码,但也许可以解释发生了什么。

newimg.MakeTransparent(Color.White);

这将采用一种颜色,并使其透明。要注意的是,台球边缘(橙色)和纯白色背景之间存在一系列颜色。这是边缘的抗锯齿(它将混合从球的纯橙色到背景的纯白色的颜色)。

通过仅将纯白色变为透明,您仍然会在对象周围留下这种白色的“光环”。

使用白色值作为 alpha 掩码也许有更好的方法来处理这个问题,但我不确定 .net 的图像库是否可以处理这个问题(我将不得不向具有更多 .net 经验的人求助)。

不过,在此期间,如果您在调整大小之前设置透明度,可能会有帮助。这不是真正的修复,但可能会减少一些光环效果。

更新:

所以,我一直在考虑这个问题,但我不完全确定是否有自动创建 alpha channel 透明度的编程解决方案,因为我有一种预感,其中涉及很多主观因素。

在我的脑海中,这就是我想出的:

  • 假设左上角的像素是 100% 透明的颜色(我们称像素 X)。
  • 假设您想要透明的背景是一种纯色(相对于图案)
  • 假设大约 3px 抗锯齿

然后你可以...

  • 检查 X 的相邻像素。对于 X 的每个与 X 颜色匹配的相邻像素,我们将其设置为 100% 透明。
  • 如果 x 旁边的像素不相同,我们可以检查它的相对色调。
  • 从该像素分支并检查它周围的像素。
  • 标记每个像素(a、b、c 等),直到相对色调改变一定百分比和/或像素颜色与其相邻像素相同(具有一定的可变范围)。如果确实如此,我们将假设我们已经进入了物体的内部。
  • 现在通过您标记的像素向后退一步,调整透明度...比如 c=0% b=33% a=66%

但是,这仍然是对真正必须发生的事情的过度简化。它做出了很多假设,没有考虑带图案的背景,并且完全忽略了也需要透明的内部区域(例如 donut 洞)。

通常在图形编辑应用程序中,这是通过选择背景色 block 、羽化所述选择的边缘,然后将其转换为最大 alpha 来完成的。

这是一个非常有趣的问题。唉,我没有给你答案,但我会好奇地看着这个话题!

关于c# - 如何避免在具有透明背景的调整大小的 PNG 中出现无用的白色边框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6236391/

相关文章:

c# - 引用的.NET程序集中的解析类型

c# - MVC 4 下拉列表格式化移动应用程序

c# - 使用 C# 和 Xamarin 防止按 F8(播放)按钮后启动 iTunes/Music.app

java - 使用 marvin 框架使用 java 代码进行图像/视频处理

java - 带有 BufferedImage 的 JPEG 图像质量会降低(变红)

forms - 在表单编辑器中调整字体大小后调整 Delphi 表单的大小

c# - ASP MVC : Index action with optional string parameter

c - 使用平方奇数窗口大小的均匀平滑滤波器操作(数字图像处理)

c# - 如何创建一个在 WPF 中拖动时调整窗口大小的按钮?

jquery - 删除特定的调整大小处理程序 jQuery