增加图像中特定颜色的亮度?

Increase brightness of specific color in image?

有这样一张图片(原始大小增加了 100%):

在 C# 或 Vb.Net 下,我想知道是否可以使用颜色矩阵或其他解决方法将 brightness/luminosity 仅增加到该图像的 white/greyed 颜色,同时保持黑色背景颜色不变?

换句话说,我想让白色十字更亮(只有十字,white/grey 像素)。

这是我期望达到的亮度结果:

两张图片均来自第三方应用程序,我显示的第一张图片来自未聚焦的关闭按钮,第二张图片是同一按钮聚焦的图片,图片的黑色部分是该按钮的背景第 3 方应用

问题是,出于个人原因,在我自己的应用程序中,我将该图像用作关闭按钮和相同的背景颜色,然后我只是想通过为"X"在那张图片中,我需要对其他图片做同样的事情。

我的图像处理知识很差,我一直在寻找下面这样的方法,但我无法得到预期的结果,因为整个图像的亮度增加了:

Adjust brightness contrast and gamma of an image

更新

我正在尝试使用@Paul Ishak 方法。

我在图片框上设置了图像,想法是当用户悬停控件时增加亮度,并在鼠标离开时重置图像,

我第二次尝试调整亮度时,它在这一行抛出 ArgumentException:

 bm = New Bitmap(image.Width, image.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

带有此消息:

A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll

这是我正在使用的代码,有什么问题吗?:

    Private minimizeBitmap As Bitmap

    Private Sub PictureBox_MinimizeButton_MouseEnter(ByVal sender As Object, ByVal e As EventArgs) _
    Handles PictureBox_MinimizeButton.MouseEnter

        Dim pcb As PictureBox = DirectCast(sender, PictureBox)

        If Me.minimizeBitmap Is Nothing Then
            Me.minimizeBitmap = New Bitmap(pcb.ClientRectangle.Width, pcb.ClientRectangle.Height)
            pcb.DrawToBitmap(Me.minimizeBitmap, pcb.ClientRectangle)
        End If

        pcb.BackgroundImage = BrightenPixels(Me.minimizeBitmap, threshold:=33, modTimes:=5D)

    End Sub

    Private Sub PictureBox_MinimizeButton_MouseLeave(ByVal sender As Object, ByVal e As EventArgs) _
    Handles PictureBox_MinimizeButton.MouseLeave

        If Me.minimizeBitmap IsNot Nothing Then
            Me.minimizeBitmap.Dispose()
        End If

        DirectCast(sender, PictureBox).BackgroundImage = Nothing

    End Sub

    Public Function BrightenPixels(ByVal image As Bitmap, threshold As Decimal, modTimes As Decimal) As Bitmap

        Dim bmp As Bitmap
        modTimes = Math.Abs(modTimes)
        If image Is Nothing Then
            Throw New ArgumentNullException(paramname:="image")
        End If

        Try

            bmp = New Bitmap(image.Width, image.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Catch ex As Exception
            MsgBox(ex.GetType.Name)
            MsgBox(ex.Message)

        End Try

        Dim g As Graphics = Graphics.FromImage(bmp)
        g.DrawImage(image, New Point(0, 0))
        Dim rect As New Rectangle(New Point(0, 0), bmp.Size)
        Dim bitmapData As System.Drawing.Imaging.BitmapData = bmp.LockBits(rect, Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Dim ptr As IntPtr = bitmapData.Scan0
        Dim byteCount As Integer = bitmapData.Stride * bitmapData.Height
        Dim argb(byteCount - 1) As Byte
        Marshal.Copy(ptr, argb, 0, byteCount)

        For i As Integer = 0 To byteCount - 1 Step 4

            Dim red As Decimal = argb(i + 2)
            Dim green As Decimal = argb(i + 1)
            Dim blue As Decimal = argb(i)
            Dim percentR As Decimal = (red / 255) * 100
            Dim percentG As Decimal = (green / 255) * 100
            Dim percentB As Decimal = (blue / 255) * 100
            Dim aboveThresholdCount As Integer = 0
            If percentR > threshold Then aboveThresholdCount += 1
            If percentG > threshold Then aboveThresholdCount += 1
            If percentB > threshold Then aboveThresholdCount += 1
            ' Label3.Text = aboveThresholdCount.ToString
            If aboveThresholdCount = 3 Then
                red = red * modTimes
                green = green * modTimes
                blue = blue * modTimes
                If red > 255 Then red = 255
                If green > 255 Then green = 255
                If blue > 255 Then blue = 255
            End If
            argb(i + 2) = CByte(Math.Round(red, 0))
            argb(i + 1) = CByte(Math.Round(green, 0))
            argb(i) = CByte(Math.Round(blue, 0))

        Next

        Marshal.Copy(argb, 0, ptr, byteCount)
        bmp.UnlockBits(bitmapData)
        Return bmp

    End Function

此示例将显示在鼠标进入和离开时修改的图像 'X'。
(示例 2 会将图像缩小 50%)

请尝试为此示例创建一个新的 Visual Basic Winforms 应用程序。请在修改之前按原样尝试此示例!

1.) 创建新项目
2.) 用这段代码替换Form1的所有代码(只修改图片路径,没有别的)
3.) 点击运行.
4.) 将鼠标移入和移出 "X"

示例 1:

Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
    Private originalPic As Bitmap = Nothing
    Friend WithEvents PictureBox1 As New PictureBox With {.Parent = Me, .Location = New Point(10, 10)}
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'Only modify this line to the location of your "x" image'
        Dim exPath As String = System.IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "picexample.jpg")
        AddHandler PictureBox1.MouseMove, AddressOf PictureBox1_MouseMove
        If System.IO.File.Exists(exPath) Then
            originalPic = CType(Image.FromFile(exPath), Bitmap)
            PictureBox1.Size = originalPic.Size
            PictureBox1.Image = originalPic
        Else
            Application.Exit()
        End If
    End Sub
    Public Function BrightenPixels(ByVal Image As Bitmap, threshold As Decimal, modTimes As Decimal) As Bitmap
        modTimes = Math.Abs(modTimes)
        If Image Is Nothing Then Return Nothing
        Dim bm As New Bitmap(Image.Width, Image.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Dim g As Graphics = Graphics.FromImage(bm)
        g.DrawImage(Image, New Point(0, 0))
        Dim rect As New Rectangle(New Point(0, 0), bm.Size)
        Dim bitmapData As System.Drawing.Imaging.BitmapData = bm.LockBits(rect, Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Dim ptr As IntPtr = bitmapData.Scan0
        Dim byteCount As Integer = bitmapData.Stride * bitmapData.Height
        Dim argb(byteCount - 1) As Byte
        System.Runtime.InteropServices.Marshal.Copy(ptr, argb, 0, byteCount)
        For i As Integer = 0 To byteCount - 1 Step 4
            Dim alpha As Decimal = argb(i + 3)
            Dim red As Decimal = argb(i + 2)
            Dim green As Decimal = argb(i + 1)
            Dim blue As Decimal = argb(i)
            Dim percentR As Decimal = (red / 255) * 100
            Dim percentG As Decimal = (green / 255) * 100
            Dim percentB As Decimal = (blue / 255) * 100
            Dim aboveThresholdCount As Integer = 0
            If percentR > threshold Then aboveThresholdCount += 1
            If percentG > threshold Then aboveThresholdCount += 1
            If percentB > threshold Then aboveThresholdCount += 1
            If aboveThresholdCount = 3 Then
                red = red * modTimes
                green = green * modTimes
                blue = blue * modTimes
                If red > 255 Then red = 255
                If green > 255 Then green = 255
                If blue > 255 Then blue = 255
            End If
            argb(i + 2) = CByte(Math.Round(red, 0))
            argb(i + 1) = CByte(Math.Round(green, 0))
            argb(i) = CByte(Math.Round(blue, 0))
        Next
        System.Runtime.InteropServices.Marshal.Copy(argb, 0, ptr, byteCount)
        bm.UnlockBits(bitmapData)
        Return bm
    End Function
    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        Dim intersectionRect As New Rectangle(13, 18, 22, 21)
        Dim mouseRect As New Rectangle(PictureBox1.PointToClient(MousePosition), New Size(1, 1))
        Me.Text = mouseRect.ToString
        If intersectionRect.IntersectsWith(mouseRect) Then
            Dim tmp As Bitmap = BrightenPixels(originalPic, 33, 1.5D)
            '---------------------Delete this section of code(inbetween lines) to remove circular highlight----------'
            Using g As Graphics = Graphics.FromImage(tmp)
                Using gp As New System.Drawing.Drawing2D.GraphicsPath
                    gp.AddRectangle(intersectionRect)
                    Using pgp As New System.Drawing.Drawing2D.PathGradientBrush(gp)
                        Dim center As New PointF(intersectionRect.Left + (intersectionRect.Width \ 2), intersectionRect.Top + (intersectionRect.Height \ 2))
                        pgp.CenterPoint = center
                        pgp.CenterColor = Color.FromArgb(64, Color.White)
                        pgp.SurroundColors = {Color.FromArgb(0, Color.White), Color.FromArgb(0, Color.White)}
                        g.FillPath(pgp, gp)
                    End Using
                End Using
            End Using
            '-----------------------------------------------------------------------------------------------------------'
            PictureBox1.Image = tmp
        Else
            PictureBox1.Image = originalPic
        End If
    End Sub
End Class

示例 2(图像 sh运行ken by 50%):

Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
    Private originalPic As Bitmap = Nothing
    Private intersectionPic As Bitmap = Nothing
    Private intersectionRect As New Rectangle(6, 9, 11, 10)
    Friend WithEvents PictureBox1 As New PictureBox With {.Parent = Me, .Location = New Point(10, 10)}
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'Only modify this line to the location of your "x" image'
        Dim exPath As String = System.IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "picexample.jpg")
        AddHandler PictureBox1.MouseMove, AddressOf PictureBox1_MouseMove
        If System.IO.File.Exists(exPath) Then
            Dim img As Bitmap = CType(Image.FromFile(exPath), Bitmap)
            Dim bm As New Bitmap(img.Width \ 2, img.Height \ 2, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
            Dim g1 As Graphics = Graphics.FromImage(bm)
            Dim cRect As New Rectangle(New Point(0, 0), bm.Size)
            g1.DrawImage(CType(Image.FromFile(exPath), Bitmap), cRect)
            originalPic = bm
            Dim tmp As Bitmap = BrightenPixels(originalPic, 33, 1.5D)
            '---------------------Delete this section of code(inbetween lines) to remove circular highlight----------'
            Using g2 As Graphics = Graphics.FromImage(tmp)
                Using gp As New System.Drawing.Drawing2D.GraphicsPath
                    gp.AddRectangle(intersectionRect)
                    Using pgp As New System.Drawing.Drawing2D.PathGradientBrush(gp)
                        Dim center As New PointF(intersectionRect.Left + (intersectionRect.Width \ 2), intersectionRect.Top + (intersectionRect.Height \ 2))
                        pgp.CenterPoint = center
                        pgp.CenterColor = Color.FromArgb(128, Color.White)
                        pgp.SurroundColors = {Color.FromArgb(0, Color.White), Color.FromArgb(0, Color.White)}
                        g2.FillPath(pgp, gp)
                    End Using
                End Using
            End Using
            '-----------------------------------------------------------------------------------------------------------'
            intersectionPic = tmp
            PictureBox1.Size = originalPic.Size
            PictureBox1.Image = originalPic
        Else
            Application.Exit()
        End If
    End Sub
    Public Function BrightenPixels(ByVal Image As Bitmap, threshold As Decimal, modTimes As Decimal) As Bitmap
        modTimes = Math.Abs(modTimes)
        If Image Is Nothing Then Return Nothing
        Dim bm As New Bitmap(Image.Width, Image.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Dim g As Graphics = Graphics.FromImage(bm)
        g.DrawImage(Image, New Point(0, 0))
        Dim rect As New Rectangle(New Point(0, 0), bm.Size)
        Dim bitmapData As System.Drawing.Imaging.BitmapData = bm.LockBits(rect, Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        Dim ptr As IntPtr = bitmapData.Scan0
        Dim byteCount As Integer = bitmapData.Stride * bitmapData.Height
        Dim argb(byteCount - 1) As Byte
        System.Runtime.InteropServices.Marshal.Copy(ptr, argb, 0, byteCount)
        For i As Integer = 0 To byteCount - 1 Step 4
            Dim alpha As Decimal = argb(i + 3)
            Dim red As Decimal = argb(i + 2)
            Dim green As Decimal = argb(i + 1)
            Dim blue As Decimal = argb(i)
            Dim percentR As Decimal = (red / 255) * 100
            Dim percentG As Decimal = (green / 255) * 100
            Dim percentB As Decimal = (blue / 255) * 100
            Dim aboveThresholdCount As Integer = 0
            If percentR > threshold Then aboveThresholdCount += 1
            If percentG > threshold Then aboveThresholdCount += 1
            If percentB > threshold Then aboveThresholdCount += 1
            If aboveThresholdCount = 3 Then
                red = red * modTimes
                green = green * modTimes
                blue = blue * modTimes
                If red > 255 Then red = 255
                If green > 255 Then green = 255
                If blue > 255 Then blue = 255
            End If
            argb(i + 2) = CByte(Math.Round(red, 0))
            argb(i + 1) = CByte(Math.Round(green, 0))
            argb(i) = CByte(Math.Round(blue, 0))
        Next
        System.Runtime.InteropServices.Marshal.Copy(argb, 0, ptr, byteCount)
        bm.UnlockBits(bitmapData)
        Return bm
    End Function
    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        Dim mouseRect As New Rectangle(PictureBox1.PointToClient(MousePosition), New Size(1, 1))
        Me.Text = mouseRect.ToString
        If intersectionRect.IntersectsWith(mouseRect) Then
            PictureBox1.Image = intersectionPic
        Else
            PictureBox1.Image = originalPic
        End If
    End Sub
End Class