|
41
|
Programación / .NET (C#, VB.NET, ASP) / Re: Librería de códigos C# (Compartan aquí sus códigos)
|
en: 22 Octubre 2018, 18:59 pm
|
BatchedCoroutines: Iterar coroutinas una a unaQueréis que vuestras ConcurrentQueues se ejecuten una por una? No problemo, con esta implementación to hard-codeada lo conseguiréis: using GTAMapper.Extensions.Threading; using System; using System.Collections; using UnityEngine; namespace GTAMapper.Extensions { public static class BatchedCoroutines { public static IEnumerator BatchCoroutines( MonoBehaviour monoBehaviour, Action finish, Func<int, bool>[] waitUntil = null, params Tuple<Action<object>, ConcurrentQueuedCoroutines<object>>[] tuple) // Tuple<Action<T>, ConcurrentQueuedCoroutines<T>> || dynamic // Fix for: https://stackoverflow.com/questions/15417174/using-the-params-keyword-for-generic-parameters-in-c-sharp { int i = 0; foreach (var val in tuple) { if (waitUntil != null && waitUntil[i] != null) yield return new WaitUntil (() => waitUntil [i ](i )); yield return val.Item2.GetCoroutine(monoBehaviour, val.Item1); ++i; } finish?.Invoke(); } } }
Un ejemplo de implementación: protected ConcurrentQueuedCoroutines <object> debuggingCoroutine = new ConcurrentQueuedCoroutines <object>(), colorCoroutine = new ConcurrentQueuedCoroutines <object>(); namespace GTAMapper.Core { public class Program : MonoBehaviour { public void Start() { StartCoroutine(BatchedCoroutines.BatchCoroutines( this, () => areCoroutinesCollected = true, F.GetFuncs(null, (_ii) => debuggingCoroutine.Queue.Count > 0), new Tuple <Action <object>, ConcurrentQueuedCoroutines <object>>((obj ) => { Tuple<int, Color> tuple = (Tuple<int, Color>)obj; int i = tuple.Item1, _x = i % width, _y = i / width; UnityEngine.Color actualColor = debugTexture.GetPixel(_x, _y), mixedColor = UnityEngine.Color.Lerp(actualColor, tuple.Item2, .5f); if (actualColor != mixedColor) { debugTexture.SetPixel(_x, _y, mixedColor); debugTexture.Apply(); } }, colorCoroutine), new Tuple <Action <object>, ConcurrentQueuedCoroutines <object>>((obj ) => { Color[] colors = (Color[])obj; debugTexture.SetPixels32(colors.CastBack().ToArray()); debugTexture.Apply(); }, debuggingCoroutine))); } } }
Básicamente, en las dos Queues vamos haciendo Enqueue donde sea necesario (en otro thread). Cuando todo haya acabado, desde el primer thread, llamamos a que se ejecute lo que acabo de mostrar. Y en mi caso por ejemplo, esto sirve para mostrar pixel a pixel donde se ha iterado una imagen. Y lo siguiente que ocurre es que la imagen se rellena con el algoritmo de flood-fill que enseñe el otro día. (Básicamente, para saber si se ha hecho bien) Nota: Si queréis el código de GetFuncs es este: using System; public static class F { public static Func<int, bool>[] GetFuncs(params Func<int, bool>[] waitUntil) { return waitUntil; } }
|
|
|
42
|
Programación / .NET (C#, VB.NET, ASP) / Re: Librería de códigos C# (Compartan aquí sus códigos)
|
en: 22 Octubre 2018, 18:55 pm
|
ConcurrentQueuedCoroutines: Implementación Thread-Safe de ConcurrentQueues dentro de CoroutinasLa idea de esta utilidad es que cuando tu almacenas items desde otro thread, puedas acceder desde el thread principal. Mezclando esta idea, con coroutinas, que básicamente, es un sistema del prehistorico que implementó Unity en su momento, que funciona de la siguiente forma, se crea un IEnumerator (con yields), el cual cada MoveNext se ejecuta en cada frame (yield return null) o cuando el programador especifique (yield return new WaitForSeconds(3) equivalente a Thread.Sleep(3000)) (por tal de no atorar el Main Thread, sí, Unity se ejecuta en un solo hilo). Entonces, teniendo estas 2 cosas, porque no hacer Dequeue en cada MoveNext? using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using UnityEngine; namespace GTAMapper.Extensions.Threading { public class ConcurrentQueuedCoroutines<T> { private List<Coroutine> coroutines; private Coroutine coroutine; private MonoBehaviour Mono; public ConcurrentQueue<object> Queue { get; private set; } public Action<T> Action { get; private set; } public bool Debugging { get; set; } public float SecondsToWait { get; private set; } private ConcurrentQueuedCoroutines() { } public ConcurrentQueuedCoroutines(float secondsToWait = -1) { Queue = new ConcurrentQueue <object>(); coroutines = new List <Coroutine >(); SecondsToWait = secondsToWait; } public Coroutine StartCoroutine(MonoBehaviour monoBehaviour, Action<T> action) { coroutines.Add(monoBehaviour.StartCoroutine(InternalCoroutine())); Mono = monoBehaviour; Action = action; return coroutine; } public Coroutine StartCoroutineOnce(MonoBehaviour monoBehaviour, Action<T> action) { if (Debugging) Debug.Log("Starting dequeing!"); if (coroutine == null) { coroutine = monoBehaviour.StartCoroutine(InternalCoroutine()); Mono = monoBehaviour; Action = action; } return coroutine; } public void StopCoroutine() { if (coroutine != null && Mono != null) Mono.StopCoroutine(coroutine); } public void StopAllCoroutines() { if (Mono != null && coroutines != null && coroutines.Count > 0) coroutines.ForEach((c) => Mono.StopCoroutine(c)); } public IEnumerator GetCoroutine(MonoBehaviour mono, Action<T> action) { Mono = mono; Action = action; return InternalCoroutine(); } private IEnumerator InternalCoroutine() { if (Debugging) Debug.Log($"Starting dequeing {Queue.Count} values!"); while (Queue.Count > 0) { object value = null; bool dequeued = Queue.TryDequeue(out value); if (!dequeued) { if (SecondsToWait == -1) yield return new WaitForEndOfFrame (); else yield return new WaitForSeconds (SecondsToWait ); continue; } Action?.Invoke((T)value); if (SecondsToWait == -1) yield return new WaitForEndOfFrame (); else yield return new WaitForSeconds (SecondsToWait ); } } } }
Y diréis, y para que sirve esta chorra, pues por ejemplo, lo que se puede conseguir, es visualizar como se recorre una textura. En el próximo post o enseñaré un caso de uso.
|
|
|
43
|
Programación / .NET (C#, VB.NET, ASP) / Re: Librería de códigos C# (Compartan aquí sus códigos)
|
en: 22 Octubre 2018, 18:48 pm
|
Thread Safe Bool: Implementación Thread-Safe de boolsEl otro día me pasaba que al asignar una variable que estaba declarada en ambito de la clase desde otro thread, al leerla desde otro thread no me devolvía el resultado esperado, por eso os traigo esta utilidad. using System.Threading; namespace GTAMapper.Extensions.Threading { /// <summary> /// Thread safe enter once into a code block: /// the first call to CheckAndSetFirstCall returns always true, /// all subsequent call return false. /// </summary> public class ThreadSafeBool { private static int NOTCALLED = 0, CALLED = 1; private int _state = NOTCALLED; /// <summary>Explicit call to check and set if this is the first call</summary> public bool Value { get { return Interlocked.Exchange(ref _state, CALLED) == NOTCALLED; } } /// <summary>usually init by false</summary> public static implicit operator ThreadSafeBool(bool called) { return new ThreadSafeBool () { _state = called ? CALLED : NOTCALLED }; } public static implicit operator bool(ThreadSafeBool cast) { if (cast == null) return false; return cast.Value; } } }
Extraído de: https://www.codeproject.com/Tips/375559/Implement-Thread-Safe-One-shot-Bool-Flag-with-Inte
|
|
|
46
|
Programación / Programación General / Re: Tengo un error en C#
|
en: 21 Octubre 2018, 06:50 am
|
En vez de usar =, usa Substring(...).Replace(..., ...) Con esto ya valdría: etiqueta = etiqueta.Replace(equiteta.Substring(0, 1), banco_palabras[numero_palabra].Substring(0, 1));
Básicamente, estás asignando un valor a una función (método del tipo nativo string) cosa que no se puede.
|
|
|
47
|
Programación / .NET (C#, VB.NET, ASP) / Re: Librería de Snippets para VB.NET !! (Compartan aquí sus snippets)
|
en: 19 Octubre 2018, 08:50 am
|
Te cuento de forma rápida lo que pretendo.
En el mapa hay x cantidad de colores predefinidos, tantos como enumeraciones tengas.
En este caso: Building, Asphalt, LightPavement, Pavement, Grass, DryGrass, Sand, Dirt, Mud, Water, Rails, Tunnel, BadCodingDark, BadCodingLight, BuildingLight, son 15.
Lo que pasa con esa imagen es hay micro variaciones de color. Quizás hay 100 tonos distintos de Grass con variaciones de pares en la escala RGB (es decir, nunca te vas a encontrar tonos que tengan un (0, 241, 0, 255), para el caso de un verde), y quizás con un rango total de ±10. Es decir, 5 posibilidades entre los 3 componentes: 5^3=125 tonos de verde.
Estos tonos son inperceptibles al ojo humano. Quizás se hizo por algun motivo (ya le metere saturación para ver si sigue algún patrón o algo. Estos de Rockstar te meten easter eggs hasta en los mapas).
Entonces lo que hago primero es iterar todos los colores. Mientras itero, voy comparando pixel a pixel, con los colores definidos en el diccionario, pero no los comparo literalmente (==), si no que saco un porcentaje de similitud. Y estás microvariaciones, como digo, como máximo su diferencia puede ser de ±10.
El porcentaje (con el mayor offset posible) sera en este caso: (255, 255, 255, 255) --> (245, 245, 245, 255) = 0.9609375 = 96,1% (un 3,9% de diferencia), vamos bien, ya que yo comparo con hasta un 10%, es decir una variación de ±25, es decir 25/2=12,5^3=1953 posibilidades, imagina.
Teniendo ese porcentaje, pues ya al debugear lo unico que hago es agrupar todos los colores (antes lo que hacia era posterizarlos, pero no me moló la idea, por eso hay un método de posterización) y sumar sus respectivas agrupaciones, pasamos de +1600 colores a unos 15 o menos (algunos no los detecta bien, otros directamente, no están presentes).
Un saludo.
|
|
|
49
|
Programación / .NET (C#, VB.NET, ASP) / Re: Librería de Snippets para VB.NET !! (Compartan aquí sus snippets)
|
en: 18 Octubre 2018, 19:51 pm
|
Leer los pixeles de una imagen y contarlos siguiendo un diccionario estático de coloresBásicamente, la funcionalidad que tiene esto, es definir un diccionario estático de colores (con una enumeración donde se especifiquen los apartados que hay (si fuese necesario)), se itera todo pixel a pixel, y cada color se compara con la muestra sacando el porcentaje de similitud, si la similitud es del 90% o mayor se da por hecho que ese color pertenece a x enumeración del diccionario. Para más INRI, le he añadido la utilidad de que se pueda leer desde Internet, lo que cambia si queremos leerlo desde el disco es que tenemos que llamar únicamente a System.IO.File.ReadAllBytes. Aquí el codigo: https://github.com/z3nth10n/GTA-ColorCount/blob/master/CountColors/Program.csNota: Tiene una versión compilada (para el que lo quiera probar). Nota2: No está optimizado (memory leak & no se ha mirado si se puede optimizar desde el punto de vista de procesamiento de cpu), asi que, si se elige guardar puede llegar a ocupar 1GB en memoria (la imagen tiene 7000x5000, en bruto son unos 140MB (7000x5000x4 (ARGB)) en memoria.) Codigo en VB.NET:Imports System Imports System.Net Imports System.Drawing Imports System.Drawing.Imaging Imports System.Runtime.InteropServices Imports System.IO Imports System.Collections.Generic Imports System.Linq Imports Color = zenthion.Color Imports System.Diagnostics Imports System.Reflection Public Enum GroundType Building Asphalt LightPavement Pavement Grass DryGrass Sand Dirt Mud Water Rails Tunnel BadCodingDark BadCodingLight BuildingLight End Enum Public Enum OrderingType ByColor [ByVal] ByName End Enum Public Class Program Public Shared colorToCompare As Color = Color.white Public Shared orderingType As OrderingType = OrderingType.ByVal Public Shared isDarkened As Boolean = False, isPosterized As Boolean = False, isOrdered As Boolean = True, saveTexture As Boolean = False Private Shared ReadOnly Property SavingPath() As String Get Return Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "texture.png") End Get End Property Public Shared Sub Main() Dim imageBytes() As Byte = Nothing ' OriginalTexture: http://i.imgur.com/g9fRYbm.png ' TextureColor: https://image.ibb.co/dP3Nvf/texture-Color.png Dim url As String = "https://image.ibb.co/dP3Nvf/texture-Color.png" Using webClient = New WebClient() imageBytes = webClient.DownloadData(url) End Using Dim sw As Stopwatch = Stopwatch.StartNew() isDarkened = url = "https://image.ibb.co/dP3Nvf/texture-Color.png" Dim colors As IEnumerable(Of Color) = Nothing Dim bitmap As Bitmap = Nothing Dim dict = GetColorCount(bitmap, imageBytes, (If(isDarkened, F.DarkenedMapColors, F.mapColors)).Values.AsEnumerable(), colors, isPosterized) Console.WriteLine(DebugDict(dict)) Console.WriteLine("Num of colors: {0}", dict.Keys.Count) If saveTexture Then colors.ToArray().SaveBitmap(7000, 5000, SavingPath) End If bitmap.Dispose() sw.Stop() Console.WriteLine("Ellapsed: {0} s", (sw.ElapsedMilliseconds / 1000F).ToString("F2")) Console.Read() End Sub Private Shared Function DebugDict (ByVal dict As Dictionary(Of Color, Integer)) As String Dim num = dict.Select(Function(x) New With {Key .Name = x.Key.GetGroundType(isPosterized), Key .Similarity = x.Key.ColorSimilaryPerc(colorToCompare), Key .Val = x.Value, Key .ColR = x.Key.r, Key .ColG = x.Key.g, Key .ColB = x.Key.b}).GroupBy(Function(x) x.Name).Select(Function(x) New With {Key .Name = x.Key, Key .Similarity = x.Average(Function(y) y.Similarity), Key .Val = x.Sum(Function(y) y.Val), Key .Col = New Color(CByte(x.Average(Function(y) y.ColR)), CByte(x.Average(Function(y) y.ColG)), CByte(x.Average(Function(y) y.ColB)))}) Dim num1 = num If isOrdered Then num1 = If(orderingType = OrderingType.ByName, num.OrderBy(Function(x) x.Name), num.OrderByDescending(Function(x)If(orderingType = OrderingType.ByColor, x.Col.ColorSimilaryPerc(colorToCompare), x.Val))) End If Dim num2 = num1.Select(Function(x) String.Format("[{2}] {0}: {1}", x.Name, x.Val.ToString("N0"), x.Similarity.ToString("F2"))) Return String.Join(Environment.NewLine, num2) End Function Public Shared Function GetColorCount (ByRef image As Bitmap, ByVal arr () As Byte, ByVal colors As IEnumerable (Of Color ), <System. Runtime. InteropServices. Out()> ByRef imageColors As IEnumerable (Of Color ), Optional ByVal isPosterized As Boolean = False) As Dictionary(Of Color, Integer) Using stream As Stream = New MemoryStream(arr) image = CType(System.Drawing.Image.FromStream(stream), Bitmap) End Using 'Color[] imageColors = image.ToColor() '.ToArray(); 'Parallel.ForEach(Partitioner.Create(imageColors, true).GetOrderableDynamicPartitions(), colorItem => For Each colorItem As Color In imageColors ' .Value Dim thresholedColor As Color = If((Not isPosterized), colorItem.GetSimilarColor(colors), colorItem) '.RoundColorOff(65); If Not count.ContainsKey(thresholedColor) Then count.Add(thresholedColor, 1) Else count(thresholedColor) += 1 End If Next colorItem Dim posterizedColors As Dictionary(Of Color, Integer) = If(isPosterized, New Dictionary(Of Color, Integer)(), count ) If isPosterized Then For Each kv In count Dim pColor As Color = kv.Key.Posterize(16) If Not posterizedColors.ContainsKey(pColor) Then posterizedColors.Add(pColor, kv.Value) Else posterizedColors(pColor) += kv.Value End If Next kv End If Return posterizedColors End Function End Class Public Module F Public mapColors As New Dictionary(Of GroundType, Color )() From { { GroundType.Building, Color.white }, { GroundType.Asphalt, Color.black }, { GroundType.LightPavement, New Color(206, 207, 206, 255) }, { GroundType.Pavement, New Color(156, 154, 156, 255) }, { GroundType.Grass, New Color(57, 107, 41, 255) }, { GroundType.DryGrass, New Color(123, 148, 57, 255) }, { GroundType.Sand, New Color(231, 190, 107, 255) }, { GroundType.Dirt, New Color(156, 134, 115, 255) }, { GroundType.Mud, New Color(123, 101, 90, 255) }, { GroundType.Water, New Color(115, 138, 173, 255) }, { GroundType.Rails, New Color(74, 4, 0, 255) }, { GroundType.Tunnel, New Color(107, 105, 99, 255) }, { GroundType.BadCodingDark, New Color(127, 0, 0, 255) }, { GroundType.BadCodingLight, New Color(255, 127, 127, 255) } } Private _darkened As Dictionary(Of GroundType, Color ) Public ReadOnly Property DarkenedMapColors () As Dictionary(Of GroundType, Color ) Get If _darkened Is Nothing Then _darkened = GetDarkenedMapColors() End If Return _darkened End Get End Property Private BmpStride As Integer = 0 Private Function GetDarkenedMapColors () As Dictionary(Of GroundType, Color ) ' We will take the last 2 elements Dim last2 = mapColors.Skip(mapColors.Count - 2) Dim exceptLast2 = mapColors.Take(mapColors.Count - 2) Dim dict As New Dictionary(Of GroundType, Color )() dict.AddRange(exceptLast2.Select(Function(x) New KeyValuePair(Of GroundType, Color)(x.Key, x.Value.Lerp(Color.black,.5F)))) dict.Add(GroundType.BuildingLight, Color.white) dict.AddRange(last2) Return dict End Function <System.Runtime.CompilerServices.Extension> _ Public Sub AddRange (Of TKey, TValue )(ByVal dic As Dictionary(Of TKey, TValue ), ByVal dicToAdd As IEnumerable (Of KeyValuePair (Of TKey, TValue ))) dicToAdd.ForEach(Sub(x) dic.Add(x.Key, x.Value)) End Sub <System.Runtime.CompilerServices.Extension> _ Public Sub ForEach(Of T)(ByVal source As IEnumerable(Of T), ByVal action As Action(Of T)) For Each item In source action(item) Next item End Sub 'INSTANT VB NOTE: The parameter color was renamed since it may cause conflicts with calls to static members of the user-defined type with this name: <System.Runtime.CompilerServices.Extension> _ Public Function Posterize(ByVal color_Renamed As Color, ByVal level As Byte) As Color Dim r As Byte = 0, g As Byte = 0, b As Byte = 0 Dim value As Double = color_Renamed.r \ 255.0 value *= level - 1 value = Math.Round(value) value /= level - 1 r = CByte(value * 255) value = color_Renamed.g \ 255.0 value *= level - 1 value = Math.Round(value) value /= level - 1 g = CByte(value * 255) value = color_Renamed.b \ 255.0 value *= level - 1 value = Math.Round(value) value /= level - 1 b = CByte(value * 255) Return New Color(r, g, b, 255) End Function <System.Runtime.CompilerServices.Extension> _ Public Function GetGroundType(ByVal c As Color, ByVal isPosterized As Boolean) As String Dim mapToUse = If(Program.isDarkened, DarkenedMapColors, mapColors) Dim kvColor As KeyValuePair(Of GroundType, Color) = mapToUse.FirstOrDefault(Function(x)If(isPosterized, x.Value.ColorSimilaryPerc(c) >.9F, x.Value = c)) If Not kvColor.Equals(Nothing) Then Return kvColor.Key.ToString() Else Return c.ToString() End If End Function <System.Runtime.CompilerServices.Extension> _ Public Function GetSimilarColor(ByVal c1 As Color, ByVal cs As IEnumerable(Of Color)) As Color Return cs.OrderBy(Function(x) x.ColorThreshold(c1)).FirstOrDefault() End Function <System.Runtime.CompilerServices.Extension> _ Public Function ColorThreshold(ByVal c1 As Color, ByVal c2 As Color) As Integer Return (Math.Abs(c1.r - c2.r) + Math.Abs(c1.g - c2.g) + Math.Abs(c1.b - c2.b)) End Function <System.Runtime.CompilerServices.Extension> _ Public Function ColorSimilaryPerc(ByVal a As Color, ByVal b As Color) As Single Return 1F - (a.ColorThreshold(b) / (256F * 3)) End Function <System.Runtime.CompilerServices.Extension> _ Public Function RoundColorOff(ByVal c As Color, Optional ByVal roundTo As Byte = 5) As Color Return New Color(c.r.RoundOff(roundTo), c.g.RoundOff(roundTo), c.b.RoundOff(roundTo), 255) End Function <System.Runtime.CompilerServices.Extension> _ Public Function RoundOff(ByVal i As Byte, Optional ByVal roundTo As Byte = 5) As Byte Return CByte(CByte(Math.Ceiling(i / CDbl(roundTo))) * roundTo) End Function <System.Runtime.CompilerServices.Extension> _ Public Iterator Function ToColor(ByVal bmp As Bitmap) As IEnumerable(Of Color) Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height) Dim bmpData As BitmapData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat) Dim ptr As IntPtr = bmpData.Scan0 Dim bytes As Integer = bmpData.Stride * bmp.Height Dim rgbValues(bytes - 1) As Byte ' Copy the RGB values into the array. Marshal.Copy(ptr, rgbValues, 0, bytes) BmpStride = bmpData.Stride For column As Integer = 0 To bmpData.Height - 1 For row As Integer = 0 To bmpData.Width - 1 ' Little endian Dim b As Byte = CByte(rgbValues((column * BmpStride) + (row * 4))) Dim g As Byte = CByte(rgbValues((column * BmpStride) + (row * 4) + 1)) Dim r As Byte = CByte(rgbValues((column * BmpStride) + (row * 4) + 2)) Yield New Color(r, g, b, 255) Next row Next column ' Unlock the bits. bmp.UnlockBits(bmpData) End Function <System.Runtime.CompilerServices.Extension> _ Public Sub SaveBitmap(ByVal bmp() As Color, ByVal width As Integer, ByVal height As Integer, ByVal path As String) Dim stride As Integer = BmpStride Dim rgbValues((BmpStride * height) - 1) As Byte For column As Integer = 0 To height - 1 For row As Integer = 0 To width - 1 Dim i As Integer = Pn(row, column, width) ' Little endian rgbValues((column * BmpStride) + (row * 4)) = bmp(i).b rgbValues((column * BmpStride) + (row * 4) + 1) = bmp(i).g rgbValues((column * BmpStride) + (row * 4) + 2) = bmp(i).r rgbValues((column * BmpStride) + (row * 4) + 3) = bmp(i).a Next row Next column Using image As New Bitmap(width, height, width * 4, PixelFormat.Format32bppArgb, Marshal.UnsafeAddrOfPinnedArrayElement(rgbValues, 0)) image.Save(path) End Using End Sub Public Function Pn(ByVal x As Integer, ByVal y As Integer, ByVal w As Integer) As Integer Return x + (y * w) End Function End Module Public Module Mathf <System.Runtime.CompilerServices.Extension> _ Public Function Clamp(Of T As IComparable(Of T))(ByVal val As T, ByVal min As T, ByVal max As T) As T If val.CompareTo(min) < 0 Then Return min ElseIf val.CompareTo(max) > 0 Then Return max Else Return val End If End Function ' Interpolates between /a/ and /b/ by /t/. /t/ is clamped between 0 and 1. Public Function Lerp(ByVal a As Single, ByVal b As Single, ByVal t As Single) As Single Return a + (b - a) * Clamp01(t) End Function ' Clamps value between 0 and 1 and returns value Public Function Clamp01(ByVal value As Single) As Single If value < 0F Then Return 0F ElseIf value > 1F Then Return 1F Else Return value End If End Function End Module Namespace zenthion ''' <summary> ''' Struct Color ''' </summary> ''' <seealso cref="System.ICloneable" /> <Serializable> Public Structure Color Implements ICloneable ''' <summary> ''' Clones this instance. ''' </summary> ''' <returns>System.Object.</returns> Public Function Clone() As Object Implements ICloneable.Clone Return MemberwiseClone() End Function ''' <summary> ''' The r ''' </summary> Public r, g, b, a As Byte ''' <summary> ''' Gets the white. ''' </summary> ''' <value>The white.</value> Public Shared ReadOnly Property white() As Color Get Return New Color(255, 255, 255) End Get End Property ''' <summary> ''' Gets the red. ''' </summary> ''' <value>The red.</value> Public Shared ReadOnly Property red() As Color Get Return New Color(255, 0, 0) End Get End Property ''' <summary> ''' Gets the green. ''' </summary> ''' <value>The green.</value> Public Shared ReadOnly Property green() As Color Get Return New Color(0, 255, 0) End Get End Property ''' <summary> ''' Gets the blue. ''' </summary> ''' <value>The blue.</value> Public Shared ReadOnly Property blue() As Color Get Return New Color(0, 0, 255) End Get End Property ''' <summary> ''' Gets the yellow. ''' </summary> ''' <value>The yellow.</value> Public Shared ReadOnly Property yellow() As Color Get Return New Color(255, 255, 0) End Get End Property ''' <summary> ''' Gets the gray. ''' </summary> ''' <value>The gray.</value> Public Shared ReadOnly Property gray() As Color Get Return New Color(128, 128, 128) End Get End Property ''' <summary> ''' Gets the black. ''' </summary> ''' <value>The black.</value> Public Shared ReadOnly Property black() As Color Get Return New Color(0, 0, 0) End Get End Property ''' <summary> ''' Gets the transparent. ''' </summary> ''' <value>The transparent.</value> Public Shared ReadOnly Property transparent() As Color Get Return New Color(0, 0, 0, 0) End Get End Property ''' <summary> ''' Initializes a new instance of the <see cref="Color"/> struct. ''' </summary> ''' <param name="r">The r.</param> ''' <param name="g">The g.</param> ''' <param name="b">The b.</param> Public Sub New(ByVal r As Byte, ByVal g As Byte, ByVal b As Byte) Me.r = r Me.g = g Me.b = b a = Byte.MaxValue End Sub ''' <summary> ''' Initializes a new instance of the <see cref="Color"/> struct. ''' </summary> ''' <param name="r">The r.</param> ''' <param name="g">The g.</param> ''' <param name="b">The b.</param> ''' <param name="a">a.</param> Public Sub New(ByVal r As Byte, ByVal g As Byte, ByVal b As Byte, ByVal a As Byte) Me.r = r Me.g = g Me.b = b Me.a = a End Sub ''' <summary> ''' Implements the ==. ''' </summary> ''' <param name="c1">The c1.</param> ''' <param name="c2">The c2.</param> ''' <returns>The result of the operator.</returns> Public Shared Operator =(ByVal c1 As Color, ByVal c2 As Color) As Boolean Return c1.r = c2.r AndAlso c1.g = c2.g AndAlso c1.b = c2.b AndAlso c1.a = c2.a End Operator ''' <summary> ''' Implements the !=. ''' </summary> ''' <param name="c1">The c1.</param> ''' <param name="c2">The c2.</param> ''' <returns>The result of the operator.</returns> Public Shared Operator <>(ByVal c1 As Color, ByVal c2 As Color) As Boolean Return Not(c1.r = c2.r AndAlso c1.g = c2.g AndAlso c1.b = c2.b AndAlso c1.a = c2.a) End Operator ''' <summary> ''' Returns a hash code for this instance. ''' </summary> ''' <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns> Public Overrides Function GetHashCode() As Integer Return GetHashCode() End Function ''' <summary> ''' Determines whether the specified <see cref="System.Object" /> is equal to this instance. ''' </summary> ''' <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param> ''' <returns><c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.</returns> Public Overrides Function Equals(ByVal obj As Object) As Boolean Dim c As Color = DirectCast(obj, Color) Return r = c.r AndAlso g = c.g AndAlso b = c.b End Function ''' <summary> ''' Implements the -. ''' </summary> ''' <param name="c1">The c1.</param> ''' <param name="c2">The c2.</param> ''' <returns>The result of the operator.</returns> Public Shared Operator -(ByVal c1 As Color, ByVal c2 As Color) As Color Return New Color(CByte(Mathf.Clamp(c1.r - c2.r, 0, 255)), CByte(Mathf.Clamp(c2.g - c2.g, 0, 255)), CByte(Mathf.Clamp(c2.b - c2.b, 0, 255))) End Operator ''' <summary> ''' Implements the +. ''' </summary> ''' <param name="c1">The c1.</param> ''' <param name="c2">The c2.</param> ''' <returns>The result of the operator.</returns> Public Shared Operator +(ByVal c1 As Color, ByVal c2 As Color) As Color Return New Color(CByte(Mathf.Clamp(c1.r + c2.r, 0, 255)), CByte(Mathf.Clamp(c2.g + c2.g, 0, 255)), CByte(Mathf.Clamp(c2.b + c2.b, 0, 255))) End Operator ''' <summary> ''' Lerps the specified c2. ''' </summary> ''' <param name="c2">The c2.</param> ''' <param name="t">The t.</param> ''' <returns>Color.</returns> Public Function Lerp(ByVal c2 As Color, ByVal t As Single) As Color Return New Color(CByte(Mathf.Lerp(r, c2.r, t)), CByte(Mathf.Lerp(g, c2.g, t)), CByte(Mathf.Lerp(b, c2.b, t))) End Function ''' <summary> ''' Inverts this instance. ''' </summary> ''' <returns>Color.</returns> Public Function Invert() As Color Return New Color(CByte(Mathf.Clamp(Byte.MaxValue - r, 0, 255)), CByte(Mathf.Clamp(Byte.MaxValue - g, 0, 255)), CByte(Mathf.Clamp(Byte.MaxValue - b, 0, 255))) End Function ''' <summary> ''' Returns a <see cref="System.String" /> that represents this instance. ''' </summary> ''' <returns>A <see cref="System.String" /> that represents this instance.</returns> Public Overrides Function ToString() As String If Me = white Then Return "white" ElseIf Me = transparent Then Return "transparent" ElseIf Me = red Then Return "red" ElseIf Me = blue Then Return "blue" ElseIf Me = black Then Return "black" ElseIf Me = green Then Return "green" ElseIf Me = yellow Then Return "yellow" Else Return String.Format("({0}, {1}, {2}, {3})", r, g, b, a) End If End Function ''' <summary> ''' Fills the specified x. ''' </summary> ''' <param name="x">The x.</param> ''' <param name="y">The y.</param> ''' <returns>Color[].</returns> Public Shared Iterator Function Fill(ByVal x As Integer, ByVal y As Integer) As IEnumerable(Of Color) For i As Integer = 0 To (x * y) - 1 Yield black Next i End Function End Structure End Namespace
Nota: A pesar de haber sido convertido con un conversor se ha comprobado en: https://dotnetfiddle.net/1vbkgGNota2: La idea era que se ejecutase de forma online y si le poneis una imagen más pequeña deberia sacar los pixeles, pero como digo no se puede, por tema de web clouds y recursos compartidos. Nota3: Le he metido esta imagen ( https://vignette.wikia.nocookie.net/gta-myths/images/8/80/Gtasa-blank.png/revision/latest?cb=20161204212845) pero me da un error que ahora mismo no me puedo parar a comprobar: Run-time exception (line -1): Arithmetic operation resulted in an overflow.
Stack Trace:
[System.OverflowException: Arithmetic operation resulted in an overflow.] at F.ColorThreshold(Color c1, Color c2) at F._Closure$__3._Lambda$__15(Color x) at System.Linq.EnumerableSorter`2.ComputeKeys(TElement[] elements, Int32 count) at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count) at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__1.MoveNext() at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source) at F.GetSimilarColor(Color c1, IEnumerable`1 cs) at Program.GetColorCount(Bitmap& image, Byte[] arr, IEnumerable`1 colors, IEnumerable`1& imageColors, Boolean isPosterized) at Program.Main() Y creo que eso es todo. Un saludo.PD: La razón de que el código esté mitad comentado y mitad sin comentar es porque la parte de la clase Color es una implementación propia de la clase Color que hice hace tiempo y la introducí en mi Lerp2API. PD2: Este código (el del ColorThreshold y lo de GetSimilarity, todo lo demás lo he escrito esta mañana y tarde) realmente lo estaba usando en mi proyecto de San Andreas Unity (de los últimos commits que hice antes de irme de este y empezar uno nuevo a solas). PD3: Todo esto es parte de un proceso de depuración un tanto largo que me ha servido para constrastar de donde me venían unos valores. Para ser más concretos, tengo un algoritmo que saca los contornos de los edificios que he estado optimizando (el cual empecé en 2016, y después de un año he retomado), y bueno, yo esperaba que me devolviese unos 2600 edificios, pero se me han devuelto unos 1027k y hay unos 1029k pixeles en la última imagen que he puesto (lo podéis comprobar vosotros mismos), así que ya se por donde seguir. Espero que vosotros también hagáis lo mismo con lo que escribo.
|
|
|
50
|
Programación / .NET (C#, VB.NET, ASP) / Re: Librería de Snippets para VB.NET !! (Compartan aquí sus snippets)
|
en: 18 Octubre 2018, 09:28 am
|
Como rellenar un array siguiendo el algoritmo Flood Fill usando HashSethttps://es.wikipedia.org/wiki/Algoritmo_de_relleno_por_difusi%C3%B3nImports System.Collections.Generic Imports System.Linq Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices Module F <Extension()> Sub FloodFill(Of T)(ByVal source As T(), ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal target As T, ByVal replacement As T) Dim i As Integer = 0 FloodFill(source, x, y, width, height, target, replacement, i) End Sub <Extension()> Sub FloodFill(Of T)(ByVal source As T(), ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal target As T, ByVal replacement As T, <Out> ByRef i As Integer) i = 0 Dim queue As HashSet(Of Integer) = New HashSet(Of Integer)() queue.Add(Pn(x, y, width)) While queue.Count > 0 Dim _i As Integer = queue.First(), _x As Integer = _i Mod width, _y As Integer = _i / width queue.Remove(_i) If source(_i).Equals(target) Then source(_i) = replacement For offsetX As Integer = -1 To 2 - 1 For offsetY As Integer = -1 To 2 - 1 If offsetX = 0 AndAlso offsetY = 0 OrElse offsetX = offsetY OrElse offsetX = -offsetY OrElse -offsetX = offsetY Then Continue For Dim targetIndex As Integer = Pn(_x + offsetX, _y + offsetY, width) Dim _tx As Integer = targetIndex Mod width, _ty As Integer = targetIndex / width If _tx < 0 OrElse _ty < 0 OrElse _tx >= width OrElse _ty >= height Then Continue For If Not queue.Contains(targetIndex) AndAlso source(targetIndex).Equals(target) Then queue.Add(targetIndex) i += 1 End If Next Next End While End Sub Function Pn(ByVal x As Integer, ByVal y As Integer, ByVal w As Integer) As Integer Return x + (y * w) End Function End Module
using System.Collections.Generic; using System.Linq; public static class F { /// <summary> /// Floods the fill. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source">The source.</param> /// <param name="x">The x.</param> /// <param name="y">The y.</param> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="target">The target to replace.</param> /// <param name="replacement">The replacement.</param> public static void FloodFill<T>(this T[] source, int x, int y, int width, int height, T target, T replacement) { int i = 0; FloodFill(source, x, y, width, height, target, replacement, out i); } /// <summary> /// Floods the array following Flood Fill algorithm /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source">The source.</param> /// <param name="x">The x.</param> /// <param name="y">The y.</param> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="target">The target to replace.</param> /// <param name="replacement">The replacement.</param> /// <param name="i">The iterations made (if you want to debug).</param> public static void FloodFill<T>(this T[] source, int x, int y, int width, int height, T target, T replacement, out int i) { i = 0; // Queue of pixels to process. :silbar: HashSet <int> queue = new HashSet <int>(); queue.Add(Pn(x, y, width)); while (queue.Count > 0) { int _i = queue.First(), _x = _i % width, _y = _i / width; queue.Remove(_i); if (source[_i].Equals(target)) source[_i] = replacement; for (int offsetX = -1; offsetX < 2; offsetX++) for (int offsetY = -1; offsetY < 2; offsetY++) { // do not check origin or diagonal neighbours if (offsetX == 0 && offsetY == 0 || offsetX == offsetY || offsetX == -offsetY || -offsetX == offsetY) continue; int targetIndex = Pn(_x + offsetX, _y + offsetY, width); int _tx = targetIndex % width, _ty = targetIndex / width; // skip out of bounds point if (_tx < 0 || _ty < 0 || _tx >= width || _ty >= height) continue; if (!queue.Contains(targetIndex) && source[targetIndex].Equals(target)) { queue.Add(targetIndex); ++i; } } } } public static int Pn(int x, int y, int w) { return x + (y * w); } }
EDIT: Añadidos using + función PN + codigo en VB.NET que para eso son los snippets de VB Prueba de concepto: https://dotnetfiddle.net/ZacRiBUn saludo.
|
|
|
|
|
|
|