Reputation: 20464
Having an image like this (original size increased by 100%):
Under C# or else Vb.Net, I wonder if I could use a color matrix or other workaround to increase the brightness/luminosity only to the white/greyed color of that image keeping the black background color untouched?
In other words, I would like to make the white cross brighter (only the cross, the white/grey pixels).
This is the brightness result that I expect to achieve:
Both images are taken from a 3rd-party application, the first image I shown is from a not focused close-button and the second image is the same button focused, the black portion of the image is the background of that 3rd-party app
The thing is that for personal reasons in my own application I'm using that image as a close-button and the same background color then I just wondered to simulate a button-focus in that way by giving brightness to the "X" in that image, I need to do the same with other images.
My knowledges of image processing are very poor, I've just been looking to approachs like this below, but I cannot get the expected result because the brightness increases in the entire image:
Adjust brightness contrast and gamma of an image
I'm trying to use @Paul Ishak approach.
I have the image set on a picturebox, the idea is to increase the brightness when the user is hovering the control, and reset the image when the mouse leaves,
the second time that I try to adjust the brightness it throws an ArgumentException at this line:
bm = New Bitmap(image.Width, image.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
with this message:
A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll
This is the code that I'm using, what is wrong?:
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
Upvotes: 3
Views: 1788
Reputation: 1093
This example will show the image being modified as the mouse enters and leaves the 'X'.
(example 2 will shrink the image by 50%)
Please try creating a new Visual Basic Winforms app for this example. Please try this example As-Is before modifying!
1.) Create new project
2.) Replace all of Form1's code with this code(only modifying path to image, nothing else)
3.) Click run.
4.) Move mouse into and out of the "X"
Example 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
Example 2 (image shrunken 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
Upvotes: 2