Tinta che si avvicina o si allontana da una tonalità di una certa percentuale
Domanda
Sto cercando di emulare il Effetto tinta di OpenXML.Ciò che fa è cambiare la tonalità dei pixel in un'immagine spostando la tonalità.Ci vogliono 2 parametri:1) il hue
(in gradi) e 2) il amt
(l'importo, una percentuale).È il numero 2 con cui sto riscontrando problemi.La specifica afferma:
Tinta:Sposta i valori di colore effetto verso o lontano dalla tonalità della quantità specificata.
- amt (Quantità) - Specifica di quanto viene spostato il valore del colore.
- tinta (Tonalità) - Specifica la tonalità verso cui tingere.
Non importando la costruzione XML, posso emulare valori che hanno un file amt
del 100%.Quindi, ad esempio, se voglio il blu (tonalità:240°), posso creare questo (the Colorato uno).Ecco un esempio:
Originale E Colorato (tonalità = 240, importo = 100%).
Ciò si ottiene semplicemente impostando la tonalità su 240, mantenendo la stessa saturazione e luminanza, convertendola in RGB e scrivendo ciascun pixel.
Ecco cosa però non riesco a ottenere:
Tonalità=240 (blu), Importo = 30%, 50% E 80%, rispettivamente
Ancora una volta, le specifiche per Amount
dice Specifica di quanto viene spostato il valore del colore.Ho provato tutti i modi qui per farlo funzionare, ma non riesco a farlo (hue=hue*amount
, originalhue * amount + hue
, eccetera.)
Altri esempi:Tonalità=120 (verde), Importo = 30%, 50%, 80% E 100%, rispettivamente.IL 100% uno che posso ottenere.
Ecco alcuni elenchi di valori di un singolo pixel nelle immagini sopra:
Pixel 159, 116 - Immagini blu
Importo della tonalità RGB | HSL Originale 244 196 10 | 48 0.92 0.5 Blue 240 30% 237 30 45 | 356 0.85 0.52 Blue 240 50% 245 9 156 | 323 0.93 0.5 Blue 240 80% 140 12 244 | 273 0.91 0.5 Blue 240 100% 12 12 244 | 240 0.91 0.5
Pixel 159, 116 - Immagini verdi
Importo della tonalità RGB | HSL Originale 244 196 10 | 48 0.92 0.5 Green 120 30% 211 237 30 | 68 0.85 0.52 Green 120 50% 159 237 30 | 83 0.85 0.52 Green 120 80% 81 237 29 | 105 0.85 0.52 Green 120 100% 29 237 29 | 120 0.85 0.52
Quindi, la domanda è:Qualcuno sa come dovrebbe funzionare?
Nota:Questo è non un duplicato di:
- Cambiare la tinta di una bitmap preservando la luminosità generale
- Ruota la tonalità utilizzando ImageAttributes in C#
- ...o qualsiasi altra cosa che potrei trovare su SO
Soluzione
Sono abbastanza certo che il tuo problema derivi dal modo in cui stai interpolando gli angoli.Ecco una funzione di interpolazione (scritta in Python) che dovrebbe fare il trucco.Si basa su un suggerimento dal thread del forum xna Interpolazione dell'angolo 2D più breve.
def wrap(value, lower, upper):
distance = upper - lower
return value - ((value-lower)//distance)*distance
def shortestangle(a,b):
angle = wrap(b-a, 0, 360)
if angle>=180: angle -= 360
return angle
def interpolate(a,b,amount):
return (a+shortestangle(a,b)*amount)%360
Ora, interpolate(originalHue,hue,amount)
dovrebbe produrre il risultato desiderato.
Modificare: Mi risulta che il tuo obiettivo sia ruotare la tonalità originale verso una determinata tonalità target di un determinato importo.Sono sicuro che lo conosci già, ma a scopo illustrativo, ecco una ruota dei colori.
(fonte: sapdesignguild.org)
Il problema è che mescolare (o interpolare) due angoli non è banale, quindi il codice piace hue = ((hue - originalHue) * amount) + originalHue
non funzionerà.I modi in cui puoi passare da un'angolazione all'altra sono infiniti grazie all'avvolgimento a 360°.Per passare da 0° a 60° è possibile ruotare di 60° in senso antiorario, 420° in senso antiorario, 300° in senso orario ecc.Di solito l'angolo più corto è quello desiderato.
Consideriamo ad esempio il collo del pinguino:se la tonalità originale è 30° (arancione), il target è 240° (blu) e la quantità è 50%, otterresti i seguenti risultati:
//Linear Interpolation
(30° + (240° - 30°)*0.5) = 135° (green)
//"Shortest 2D Angle Interpolation"
(30° + shortestangle(30°,240°)*0.5) % 360 = (30° + (-150°)*0.5) % 360 = 315° (magenta)
La mia ipotesi è che il secondo risultato sia quello che stai cercando, ma potrei sbagliarmi e l'errore potrebbe essere completamente diverso...
Altri suggerimenti
Dovresti dare un'occhiata TintParams in GDI+ (non parte di .NET però): questo potrebbe essere proprio quello che stai cercando.