2014-09-10 91 views
1

我試圖獲得一個有效的代碼,可以打開現有圖像並使其透明。問題是,我想所有可能的顏色是漸變到白色漸變到透明。我用Color Matrix玩了一下,但是失敗了...所以我做了很多可能完全沒必要的東西。我的解決方案如下。使所有漸變爲白色漸變爲透明

1)打開現有文件。

2)使一個新的圖像作爲灰度從源

3)反轉graysscale

4)應用的紅色值作爲從反相灰度圖像α,每像素的像素到新的圖像。其他RGB值是從原始文件extraxted。 (對不起,我的馬虎功能...只需要做一個快速測試,看看是否有可能)

這工作以某種方式好,除了處理較大的圖像需要大量的時間(約3500x2000像素)是否有點可能要直接與ColorMatrix做這個,以便跳過每像素過程中的像素?或者還有其他方法嗎?我一直在想掩蓋等,但沒有任何經驗。

由於使用灰度作爲輸入,當前的代碼也會使黑色以外的其他顏色略微透明(不太亮)。

'VB.NET 
Imports System.Drawing 
Imports System.Drawing.Imaging 

Module Module1 

Sub Main() 
    Dim args() As String = Environment.GetCommandLineArgs 
    Dim Path As String = String.Empty 

    If args.Count = 2 Then 
     Path = args(1) 
    End If 

    Try 
     Dim image1 As Bitmap = CType(Image.FromFile(Path, True), Bitmap) 
     Dim image2 As New Bitmap(image1.Width, image1.Height) 

     Dim g As Graphics = Graphics.FromImage(image2) 

     Dim myColorMatrix As New ColorMatrix 
     Dim invColor As New ColorMatrix 

     Dim imageAttr As New ImageAttributes 

     myColorMatrix.Matrix00 = 0.3F 
     myColorMatrix.Matrix01 = 0.3F 
     myColorMatrix.Matrix02 = 0.3F 

     myColorMatrix.Matrix10 = 0.59F 
     myColorMatrix.Matrix11 = 0.59F 
     myColorMatrix.Matrix12 = 0.59F 

     myColorMatrix.Matrix20 = 0.11F 
     myColorMatrix.Matrix21 = 0.11F 
     myColorMatrix.Matrix22 = 0.11F 

     myColorMatrix.Matrix33 = 1.0 
     myColorMatrix.Matrix44 = 1.0 

     imageAttr.SetColorMatrix(myColorMatrix, ColorAdjustType.Default, ColorAdjustType.Default) 
     g.DrawImage(image1, New Rectangle(0, 0, image1.Width, image1.Height), 0, 0, image1.Width, image1.Height, GraphicsUnit.Pixel, imageAttr) 

     invColor.Matrix00 = -1 
     invColor.Matrix11 = -1 
     invColor.Matrix22 = -1 
     invColor.Matrix33 = 1 
     invColor.Matrix44 = 1 
     invColor.Matrix40 = 1 
     invColor.Matrix41 = 1 
     invColor.Matrix42 = 1 

     imageAttr.SetColorMatrix(invColor, ColorAdjustType.Default, ColorAdjustType.Default) 
     g.DrawImage(image2, New Rectangle(0, 0, image1.Width, image1.Height), 0, 0, image1.Width, image1.Height, GraphicsUnit.Pixel, imageAttr) 

     Dim myColor As New Color 
     Dim x As Integer = 0 
     Dim y As Integer = 0 
     Dim myAlpha As Integer = 0 
     Dim orgColor(2) As Integer 

     Do Until y = image1.Height 
      Do Until x = image1.Width 
       'Get alpha 
       myAlpha = toRGB(image2.GetPixel(x, y)) 

       orgColor = currentRGB(image1.GetPixel(x, y)) 

       myColor = Color.FromArgb(myAlpha, orgColor(0), orgColor(1), orgColor(2)) 

       image2.SetPixel(x, y, myColor) 
       x = x + 1 
      Loop 
      x = 0 
      y = y + 1 
     Loop 

     image2.Save("C:\test\transparent.png", ImageFormat.Png) 

     image1.Dispose() 
     image2.Dispose() 
     g.Dispose() 

    Catch ex As System.IO.FileNotFoundException 
     MsgBox(ex.ToString & vbNewLine & " There was an error opening the bitmap." _ 
      & "Please check the path.") 
    End Try 

End Sub 
Private Function toRGB(ByVal Color As Color) As Integer 
    Dim r As Integer 
    r = Color.R 
    Return r 
End Function 
Private Function currentRGB(ByRef color As Color) As Array 
    Dim currRGB(2) As Integer 
    currRGB(0) = color.R 
    currRGB(1) = color.G 
    currRGB(2) = color.B 
    Return currRGB 
End Function 
End Module 
+0

給我們一個前後圖像怎麼樣?告訴我們需要多長時間? – 2014-09-10 21:22:11

+0

SetPixel非常慢。使用LockBits和指針的解決方案運行速度會快上百倍(並且可以完全擺脫ColorMatrix)。 – 2014-09-11 11:39:28

回答

1

你可以使用system()獲得ImageMagick的爲你做到這一點。它是免費的,並提供here

它還具有可用的Windows .NET綁定 - 請參閱here,以便您可以直接從您的程序調用ImageMagick的庫函數,而不需要system()

我知道你在試圖做可以像這樣在命令行來完成:

convert input.bmp \(+clone -colorspace gray \) -alpha off -compose copy_opacity -composite output.png 

我基準以上的圖像3500x2000的,它需要0.8秒 - 不知道如果這是什麼好與你的代碼相比還是不行!

1

這是完全未經測試的代碼(我甚至不知道它是否編譯正確),但它應該讓您瞭解如何儘可能快地完成它(當然,不使用GPU):

public static void AlphaGray(
    Bitmap bmp, 
    int threshold) 
{ 
    Rectangle r = new Rectangle(Point.Empty, bmp.Size); 
    BitmapData bd = bmp.LockBits(r, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
    unsafe 
    { 
     byte* p = (byte*)bd.Scan0.ToPointer(); 
     for (int i = r.Height * r.Width; i > 0; i--, p +=4) 
     { 
      var avg = (p[0] + p[1] + p[2]) /3; 
      var bx = p[0] - avg; 
      var gx = p[1] - avg; 
      var rx = p[2] - avg; 
      if(bx*bx + gx*gx + rx*rx < threshold) 
       p[3] = (byte)avg; 
     } 
    } 
    bmp.UnlockBits(bd); 
}