Cita de: Eleкtro en 17 Septiembre 2016, 13:51 PMEsta tarde he podido ver más tranquilamente su código y probarlo. He visto un problema que miraré mas tarde no quiero darle trabajo pues ya a aportado una respuesta excelente. Lo único que no he visto correcto es sacar la operación factor+= 100 de la función pues forma parte de la misma. De todos modos he conseguido sintentizar las operaciones, y ya no hace falta el 'factor+= 100', quedando así:
Como dije en el post, solo es un código de ejemplo, un ejemplo que se debe adaptar a las necesidades que tengas, de todas formas aceptando tu petición le cambié el nombre a la función y también especifiqué que la matriz de color es una idea original tuya.
Saludos!
Código (vbnet) [Seleccionar]
Dim r As Single = CSng(factor * (299 * -10 ^ -5))
Dim g As Single = CSng(factor * (587 * -10 ^ -5))
Dim b As Single = CSng(factor * (114 * -10 ^ -5))
factor = (factor / 100.0F) + 1
Dim matrix As Single()() = {
New Single() {(r + factor), r, r, 0.0F, 0.0F},
New Single() {g, (g + factor), g, 0.0F, 0.0F},
New Single() {b, b, (b + factor), 0.0F, 0.0F},
New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F},
New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}
}
o también:
Código [Seleccionar]
Dim r As Single = CSng(factor * -(299 * 10 ^ -5))
Dim g As Single = CSng(factor * -(587 * 10 ^ -5))
Dim b As Single = CSng(factor * -(114 * 10 ^ -5))
...
Código [Seleccionar]
Dim r As Single = CSng(factor * -(299 / 100000.0F))
Dim g As Single = CSng(factor * -(587 / 100000.0F))
Dim b As Single = CSng(factor * -(114 / 100000.0F))
Conseguí eliminar otra ecuación más
Código (vbnet) [Seleccionar]
''' <summary>
''' Función para saturación de color //por @Elektro y @FJDA
''' </summary>
''' <param name="srcImg">Objeto de tipo System.Drawing.Image</param>
''' <param name="Factor">Valor de saturación de color; de -100 a 100</param>
''' <param name="highQuality">Composición de calidad</param>
''' <returns></returns>
''' <remarks></remarks>
Public Function SetImageSaturation(ByVal srcImg As Image, ByVal Factor As Single, ByVal highQuality As Boolean) As Image
Dim F As Single = Factor
Dim R As Single = CSng(F * -(299 / 100000))
Dim G As Single = CSng(F * -(587 / 100000))
Dim B As Single = CSng(F * -(114 / 100000))
Dim bmp As New Bitmap(srcImg.Width, srcImg.Height, srcImg.PixelFormat)
Dim matrix As Single()() = {
New Single() {CSng((0.00701 * F) + 1), R, R, 0.0F, 0.0F},
New Single() {G, CSng((0.00413 * F) + 1), G, 0.0F, 0.0F},
New Single() {B, B, CSng((0.00886 * F) + 1), 0.0F, 0.0F},
New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F},
New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}
}
Using ia As New ImageAttributes
ia.ClearColorMatrix()
ia.SetColorMatrix(New ColorMatrix(matrix), ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
ia.SetGamma(1.0F, ColorAdjustType.Bitmap)
Using gdi As Graphics = Graphics.FromImage(bmp)
With gdi
If highQuality Then
.CompositingQuality = CompositingQuality.HighQuality
.InterpolationMode = InterpolationMode.HighQualityBicubic
.PixelOffsetMode = PixelOffsetMode.HighQuality
.SmoothingMode = SmoothingMode.HighQuality
Else
.CompositingQuality = CompositingQuality.HighSpeed
.InterpolationMode = InterpolationMode.NearestNeighbor
.PixelOffsetMode = PixelOffsetMode.None
.SmoothingMode = SmoothingMode.None
End If
.DrawImage(srcImg, New Rectangle(0, 0, bmp.Width, bmp.Height),
0, 0, srcImg.Width, srcImg.Height,
GraphicsUnit.Pixel, ia)
End With
End Using ' gdi
End Using ' ia
Return bmp
End Function
Buenas de nuevo.
@Elektro. he estado analizando su código y lo he ejecutado. Como comenté había algún problema y es que a pesar de que introdujo el trabajo en modo asincrónico seguía habiendo una ligera lentitud para mostrar el cambio si se movía muy rápido el TrackBar, especialmente se percibía al mostrar el valor de saturación en el Label.
Finalmente hemos conseguido eficiencia cien por cien, gracias a usted. ¡¡Buen trabajo!!
Tan solo tuve que realizar pequeños cambios. sin importancia. También mediante matemáticas eliminar ecuaciones innecesarias.
Aquí muestro los cambios y he reducido el código para que sea más fácil de entender y sea más corto.
*Deben crear un PictureBox, un TrackBar1 y un Label
* Coloquen el directorio para cargar la imagen en:
Código [Seleccionar]
.ImagenPrevia = Image.FromFile(".\Imagen.jpg")
Código (vbnet) [Seleccionar]
Imports System.Runtime.CompilerServices
Imports System.ComponentModel
Imports System.Drawing.Imaging
Imports System.Drawing.Drawing2D
Public NotInheritable Class Form1
Inherits Form
Private ImagenPrevia As Image
Private ImagenDeTrabajo As Image
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
With Me
'Propiedades para el TrackBar1
With .TrackBar1
.TickFrequency = 10
.TickStyle = TickStyle.TopLeft
.Maximum = 100
.Minimum = -100
.Value = 0
End With
'Propiedades para el PictureBox1
With .PictureBox1
.BackColor = Color.DarkGray
.SizeMode = PictureBoxSizeMode.Normal
End With
'Carga la imagen desde un directorio
.ImagenPrevia = Image.FromFile(".\Imagen.jpg")
'Tamaño de la imagen para trabajar
Dim TamañoImagenDeTrabajo As Size = .PictureBox1.Size
'Obtiene imagen previa para trabajar
.ImagenDeTrabajo = .ImagenPrevia.GetThumbnailImage(TamañoImagenDeTrabajo.Width, _
TamañoImagenDeTrabajo.Height, _
Nothing, Nothing)
.PictureBox1.Image = .ImagenDeTrabajo
End With
End Sub
Private Sub TrackBar1_ValueChanged(sender As Object, e As EventArgs) Handles TrackBar1.ValueChanged
'Ejecutar de forma asincrónica
Task.Factory.StartNew(Sub()
Dim lockImg As Image = ImagenDeTrabajo
SyncLock lockImg 'Bloqueo de instrucción antes de procesar
Me.Invoke(Sub()
Dim vSat As Single = TrackBar1.Value 'Obtiene el valor de saturación de color
Label1.Text = CStr(vSat) 'Muestra el valor de saturación de color
lockImg = lockImg.SetImageSaturation(sngSatVal:=vSat,
highQuality:=False)
Me.PictureBox1.Image = lockImg
End Sub) 'Me.Invoke
End SyncLock
End Sub) 'Task
End Sub
End Class
Public Module ImageExtensions
''' <summary>
''' Función para saturación de color //por @Elektro y @FJDA
''' </summary>
''' <param name="srcImg">Objeto de tipo System.Drawing.Image</param>
''' <param name="sngSatVal">Valor de saturación de -100 a 100</param>
''' <param name="highQuality">Composición de calidad</param>
''' <returns></returns>
''' <remarks></remarks>
<DebuggerStepThrough> <Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function SetImageSaturation(ByVal srcImg As Image, ByVal sngSatVal As Single, ByVal highQuality As Boolean) As Image
Dim R As Single = CSng(sngSatVal * -(299 / 100000))
Dim G As Single = CSng(sngSatVal * -(587 / 100000))
Dim B As Single = CSng(sngSatVal * -(114 / 100000))
Dim FactR As Single = CSng(((0.00701F * sngSatVal) + 1))
Dim FactG As Single = CSng(((0.00413F * sngSatVal) + 1))
Dim FactB As Single = CSng(((0.00886F * sngSatVal) + 1))
Dim matrix As Single()() = {
New Single() {FactR, R, R, 0, 0},
New Single() {G, FactG, G, 0, 0},
New Single() {B, B, FactB, 0, 0},
New Single() {0, 0, 0, 1, 0},
New Single() {0, 0, 0, 0, 1}
}
Dim bmp As New Bitmap(srcImg.Width, srcImg.Height, srcImg.PixelFormat)
Using ia As New ImageAttributes
ia.ClearColorMatrix()
ia.SetColorMatrix(New ColorMatrix(matrix), ColorMatrixFlag.Default, ColorAdjustType.Bitmap)
ia.SetGamma(1.0F, ColorAdjustType.Bitmap)
Using gdi As Graphics = Graphics.FromImage(bmp)
With gdi
If highQuality Then
.CompositingQuality = CompositingQuality.HighQuality
.InterpolationMode = InterpolationMode.HighQualityBicubic
.PixelOffsetMode = PixelOffsetMode.HighQuality
.SmoothingMode = SmoothingMode.HighQuality
Else
.CompositingQuality = CompositingQuality.HighSpeed
.InterpolationMode = InterpolationMode.NearestNeighbor
.PixelOffsetMode = PixelOffsetMode.None
.SmoothingMode = SmoothingMode.None
End If
.DrawImage(srcImg, New Rectangle(0, 0, bmp.Width, bmp.Height),
0, 0, srcImg.Width, srcImg.Height,
GraphicsUnit.Pixel, ia)
End With
End Using ' gdi
End Using ' ia
Return bmp
End Function
End Module
Hoy he modificado un poco la matriz para que sea más ordenado y legible. Ya que el uso del punto fijo 'F' junto con la variable single F (mal puesta por mi parte), lo hacía confuso. No veo necesario su uso en valores 0 o 1, así que lo he suprimido en estos valores. También he sacado las ecuaciones de la matriz pasándolas a FactR, FactG y FactB, nombrandolos Fact(Letra color) porque son los verdaderos factores de rojo, verde y azul.
Código [Seleccionar]
Dim R As Single = CSng(sngSatVal * -(299 / 100000))
Dim G As Single = CSng(sngSatVal * -(587 / 100000))
Dim B As Single = CSng(sngSatVal * -(114 / 100000))
Dim FactR As Single = CSng(((0.00701F * sngSatVal) + 1))
Dim FactG As Single = CSng(((0.00413F * sngSatVal) + 1))
Dim FactB As Single = CSng(((0.00886F * sngSatVal) + 1))
Dim matrix As Single()() = {
New Single() {FactR, R, R, 0, 0},
New Single() {G, FactG, G, 0, 0},
New Single() {B, B, FactB, 0, 0},
New Single() {0, 0, 0, 1, 0},
New Single() {0, 0, 0, 0, 1}
}
y recuerden que para guardar la imagen deben usar la imagen previa (la original en tamaño y calidad) y modificar la saturación en alta calidad en el momento de guardar. Como bien ha hecho @Elektro, para realizar los cambios previos se trabaja con una imagen de bajo tamaño y calidad para acelerar el trabajo, pero a la hora de guardar hay que trabajar con la imagen original en tamaño y calidad que hemos cargado.
Código (vbnet) [Seleccionar]
Using img As Image = SetImageSaturation(ImagenPrevia, TrackBar1.Value, highQuality:=True)
img.Save(".\Cambios.jpg", ImageFormat.Jpeg)
End Using
Aquí dejo finalizado el tema, creo que se ha conseguido y espero sea de utilidad para otros programadores.
Agradecimientos de nuevo a @Elektro por su gran ayuda.
Hasta luego.