【问题标题】:Programmatically determine background of image (logos, etc) and make transparent?以编程方式确定图像(徽标等)的背景并使其透明?
【发布时间】:2011-05-20 21:16:38
【问题描述】:

我正在尝试编写一个解决方案,以便我的用户可以使用他们的公司徽标“水印”他们的图像。我已经完成了实际的水印部分并开始工作,所以现在我正在创建“上传徽标”功能,以便他们可以向我提供他们希望在他们的图像上出现水印的徽标。

我正在使用 VB.NET,这可能最终会出现在一个接受 Logo JPG 文件并返回“已更改”徽标的 Web 服务中。我需要在此 Web 服务中发生的事情是:

1) 灰度图像。感谢this article

2) 使背景透明(这样徽标在图像上加水印时看起来很干净)。这就是我卡住的地方。

我认为在大多数情况下,上传的任何徽标都将具有通用的白色背景,但我不能假设。有没有办法以某种方式检测图像的背景背景颜色,以便我可以使那些颜色透明?

我已经下载并运行了名为 Transpoint 的 this project from code.google.com,这几乎是我所需要的,但我无法将其作为独立应用程序使用。另外,我认为这是用 Python 编写的,对我来说是陌生的。

所以基本上我需要的只是一种确定图像背景的方法(如果这可能吗?),甚至只是背景颜色,以便我可以使它们透明。任何帮助/建议/建议将不胜感激!

谢谢, 劳埃德

【问题讨论】:

    标签: vb.net image background transparency watermark


    【解决方案1】:

    您可以执行类似读取左上角像素并假设该像素代表背景颜色的操作,然后遍历图像并将每个匹配像素(按颜色匹配)的 alpha 值设置为 0。

    但是,我几乎可以向您保证,结果会很糟糕。为了使透明度正常工作并看起来不错,图像需要支持部分透明度,这样一些像素是完全透明的,而一些像素只是部分透明的。任何采用不透明图像并将图像中的一种颜色设置为完全透明的算法最终都会出现锯齿状边缘。

    我接触过的大多数公司都有由专业艺术家制作的徽标版本,具有流畅、部分透明的效果。你最好只要求客户提交一个透明的标志,而不是试图用代码将不透明的图像变成透明的。抱歉,但这不起作用。

    【讨论】:

    • 这就是我害怕的。感谢您的回复!
    • 其实请不要选择这个答案。我很确定 Adob​​e 等可以进行这种转换(他们拍摄图像并将背景渲染为透明,但保持图像边缘平滑),所以如果他们能做到,我敢肯定至少有一个算法。
    【解决方案2】:

    我认为这确实可行(抱歉,这只是一个描述):

    假设左上角像素是图像的背景颜色,您可以遍历图像中的每个像素,如果像素颜色与背景颜色匹配(完全匹配或在某个阈值颜色距离内),则将 alpha 设置为 0。然后,当您在不同颜色的背景上重新绘制图像时,这将为您留下具有透明背景但边缘呈锯齿状的图像。此外,如果背景颜色出现在图像本身内部的任何位置,它将变为透明,这是您不希望的。

    要解决后一个问题,您的算法应该从左到右开始扫描图像的每一行,并在到达非背景颜色像素时停止;此时它应该从同一行开始并从右到左扫描,直到到达非 bg 像素。

    要修复边缘,您可以模糊位图的 Alpha 值。基本上,您将每个像素的 alpha 值重新计算为 9 个像素的平均值(本身及其周围的 8 个像素,只是 alpha 值 - 而不是 rgb 值)。为防止排序伪影,您将有一个临时数组来存储平均像素值,然后您将在该过程结束时将其复制回图像的 alpha 值。

    此外,可能有一个或多个第三方工具可以执行此操作(LEAD 工具还在吗?)。

    【讨论】:

      【解决方案3】:

      @MusiGenesis(以及其他任何可能感兴趣的人)这是我为(某种程度)解决我的问题所做的。我基本上遵循了你想法的前半部分。我创建了一个函数,它将接受bitmap,将每个像素与 (0,0) 处的第一个像素进行对比——对每种 RGB 颜色使用 10 的阈值。对于该阈值内的每种颜色,像素都变为透明的。这是我的代码,对于我尝试过的几张图片来说似乎没问题:

      Private Function TransparifyBackground(ByVal bmp As Bitmap) As Bitmap
      
              Dim temp As Color
      
              Dim background As Color = bmp.GetPixel(0, 0) 'top left will be assumed background color
      
              For y As Integer = 0 To bmp.Height - 1
                  For x As Integer = 0 To bmp.Width - 1
      
                      'get the pixel for this position:
                      temp = bmp.GetPixel(x, y)
      
                      If ColorsMatch(background, temp) Then
      
                          'Make the Alpha value 50 for each pixel, leaving the other colors
                          Dim newColor As New Color
                          newColor = Color.Transparent
      
                          bmp.SetPixel(x, y, newColor)
      
                      End If
      
                  Next
              Next
      
              Return bmp
      
          End Function
      
          Private Function ColorsMatch(ByVal background As Color, ByVal temp As Color) As Boolean
      
              Dim nThreshold As Integer = 10
      
              Dim temp_R As Integer = CInt(temp.R)
              Dim temp_G As Integer = CInt(temp.G)
              Dim temp_B As Integer = CInt(temp.B)
      
              Dim R As Integer = CInt(background.R)
              Dim G As Integer = CInt(background.G)
              Dim B As Integer = CInt(background.B)
      
              'check the difference of each value against our threshold:
              If ((temp_R - R) < nThreshold) AndAlso ((temp_G - G) < nThreshold) AndAlso ((temp_B < B) < nThreshold) Then
                  Return True
              Else
                  Return False
              End If
      
          End Function
      

      【讨论】:

      • 如果函数被不频繁地调用(例如,not 每秒 100 次),这可能无关紧要,但 SetPixelGetPixel 非常慢。如果您发现因此遇到性能瓶颈,您可以使用Bitmap.LockBits 方法返回的BitmapData 对象将基于像素的操作加快几个数量级。 SO上有大量关于使用LockBits的帖子。
      • 太棒了,感谢您的建议。我会记住这一点。不过目前,该函数一次只会被调用一次,所以我希望它不会成为问题。
      • 这 3 个 (temp_X - X) 语句需要包含在 Math.Abs​​() 中。否则,一个小的 temp_X 和一个大的 X 将产生一个像 -100 这样的数字,即使它是完全不同的颜色,它也会变得透明。如果您的起始颜色是黑色(或白色 - 以 (255, 255, 255) 为准),您可能没有注意到这一点。
      猜你喜欢
      • 2012-02-07
      • 2023-03-05
      • 1970-01-01
      • 2019-05-15
      • 2016-12-08
      • 2018-05-18
      • 1970-01-01
      • 1970-01-01
      • 2011-12-23
      相关资源
      最近更新 更多