ある色を同じ色の別の色合いに補間しようとしています。 (例:スカイブルーからダークブルー、そしてその逆)。
私は いくつかのコード 範囲が0-255または0-1の場合に使用できることに気づきました。ただし、私の場合、Color1とColor2のRGBコードがあり、回転を発生させたいと考えています。
色1:151,206,255
色2:114,127,157
これについてどうやって行くのかアイデアはありますか?
RGBをHSVに変換してから、そのコンポーネントを調整してから、RGBに戻すことをお勧めします。
ウィキペディアには 記事 があり、これについては以前にここで説明しました。
RGBをHSVに変換し、HSVをRGBに変換するアルゴリズム(両方とも0〜255の範囲)
また、多くのフレームワークには変換関数があります。たとえば、Qtには QColorクラス があります。
しかし、質問は実際の補間についてでした...ここに簡単な補間関数があります:
// 0 <= stepNumber <= lastStepNumber
int interpolate(int startValue, int endValue, int stepNumber, int lastStepNumber)
{
return (endValue - startValue) * stepNumber / lastStepNumber + startValue;
}
したがって、補間するすべての色成分について、ループでそれを呼び出します。 RBG補間では、すべてのコンポーネントを補間する必要があります。他の色空間では、1つだけを補間する必要がある場合があります。
私はこれが少し古いことを知っていますが、誰かがそれを探しているなら価値があります。
まず第一に、RGBを含む任意の色空間で補間を行うことができます。これは私の意見では最も簡単なものの1つです。
バリエーションが0から1の間の小数値(例:0.3)によって制御されると仮定します。ここで、0はフルカラー1を意味し、1はフルカラー2を意味します。
理論:
Result = (color2 - color1) * fraction + color1
申請中:
RGBには3つのチャネル(赤、緑、青)があるため、チャネルごとにこの計算を実行する必要があります。
サンプルカラーの使用:
color1: 151,206,255
color2: 114,127,157
R = (114-151) * fraction + 151
G = (127-206) * fraction + 206
B = (157-255) * fraction + 255
そのように簡単です!
RGBカラーをHSVに変換 次に、各コンポーネントを補間します(カラーだけでなく、回答の終わりを参照)。その後、RGBに戻すことができます。
RGB補間を行うことはできますが、この空間では色が輝度と彩度から分離されているため、結果はHSVの方が優れています( HSVに関するWikipediaの記事 )。 HSV補間は、RGB補間よりも「論理的」です。RGB補間を使用すると、補間中に余分な色を取得できるためです。
補間のためのいくつかのコード:
template<typename F>
ColorRGB interpolate(ColorRGB a, ColorRGB b, float t, F interpolator)
{
// 0.0 <= t <= 1.0
ColorHSV ca = convertRGB2HSV(a);
ColorHSV cb = convertRGB2HSV(b);
ColorHSV final;
final.h = interpolator(ca.h, cb.h, t);
final.s = interpolator(ca.s, cb.s, t);
final.v = interpolator(ca.v, cb.v, t);
return convertHSV2RGB(final);
}
int linear(int a, int b, float t)
{
return a * (1 - t) + b * t;
}
// use: result = interpolate(color1,color2,ratio,&linear);
視覚効果に使用するのに最適な色空間は [〜#〜] hcl [〜#〜] です。これは、その次元を横断しながら見栄えを良くするために特別に作成されたスペースであり、「見栄え」は、それぞれRGBやCMYKなどの光やインクの物理的特性とは関係ありません。
HCLの使用には費用がかかるため、このスペースに多数の中間値を作成してから、ネイティブのRGBで補間するのが最善の方法です。これは私が私の アニメーションエンジン で行ったことです。
これは、Swift 4.0のスニペットです。
extension UIColor {
typealias Components = (CGFloat, CGFloat, CGFloat, CGFloat)
enum Space: String {
case RGB = "RGB"
case HSB = "HSB"
case HCL = "HCL"
}
func components(in space: UIColor.Space) -> Components {
switch space {
case .RGB: return self.rgba // var defined in HandyUIKit's extension
case .HSB: return self.hsba // var defined in HandyUIKit's extension
case .HCL: return self.hlca // var defined in HandyUIKit's extension
}
}
func spectrum(to tcol: UIColor, for space: UIColor.Space) -> [UIColor] {
var spectrum = [UIColor]()
spectrum.append(self)
let fcomps = self.components(in: space)
let tcomps = tcol.components(in: space)
for i in 0 ... 5 {
let factor = CGFloat(i) / 5.0
let comps = (1.0 - factor) * fcomps + factor * tcomps
let color = UIColor(with: comps, in: space)
spectrum.append(color)
}
spectrum.append(tcol)
return spectrum
}
convenience init(with components: Components, in space: Space) {
switch space {
case .RGB: self.init(red: components.0, green: components.1, blue: components.2, alpha: components.3)
case .HSB: self.init(hue: components.0, saturation: components.1, brightness: components.2, alpha: components.3)
case .HCL: self.init(hue: components.0, luminance: components.1, chroma: components.2, alpha: components.3)
}
}
}
func *(lhs:CGFloat, rhs:UIColor.Components) -> UIColor.Components {
return (lhs * rhs.0, lhs * rhs.1, lhs * rhs.2, lhs * rhs.3)
}
func +(lhs:UIColor.Components, rhs:UIColor.Components) -> UIColor.Components {
return (lhs.0 + rhs.0, lhs.1 + rhs.1, lhs.2 + rhs.2, lhs.3 + rhs.3)
}
エンジンと上記の例はどちらも、スペース間の変換に HandyUIKit を使用しているため、上記のコードが機能するように、構築しているものにこのプロジェクトを追加してください。
私はそれについて 記事 を書きました。
これが@hydeの答えに基づくSwift 2バージョンです:
import UIKit
func interpolate(start start: CGFloat, end: CGFloat, progress: CGFloat) -> CGFloat {
return (end - start) * progress + start
}
extension UIColor {
func interpolateTo(color end: UIColor, progress: CGFloat) -> UIColor {
var r1: CGFloat = 0
var g1: CGFloat = 0
var b1: CGFloat = 0
var a1: CGFloat = 0
getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
var r2: CGFloat = 0
var g2: CGFloat = 0
var b2: CGFloat = 0
var a2: CGFloat = 0
end.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)
return UIColor(
red: interpolate(start: r1, end: r2, progress: progress),
green: interpolate(start: g1, end: g2, progress: progress),
blue: interpolate(start: b1, end: b2, progress: progress),
alpha: interpolate(start: a1, end: a2, progress: progress)
)
}
}
次のように使用できます。
color1.interpolateTo(color: color2, progress: t)
ここで、t
は補間のパーセンテージ(0-1)です。
SynxisのCの例 (上記)を実行可能なJavaScriptプログラムに適合させました。
プログラムは、redおよびgreenから色yellowを補間します。入出力はRGB-spaceにありますが、補間はHSV-spaceで処理されます。 RGB補間の例も追加しました。以下に示すように、RGB-spaceでredおよびgreenを補間すると、dark-yellowが生成されます。 。
/** Main */
var red = { r : 255, g : 0, b : 0 };
var green = { r : 0, g : 255, b : 0 };
var yellow = interpolateHsv(red, green, 0.5, linear);
var darkYellow = interpolateRgb(red, green, 0.5, linear);
document.body.innerHTML =
'Yellow: ' + JSON.stringify(yellow, null, ' ') + '<br />' +
'Dark Yellow: ' + JSON.stringify(darkYellow, null, ' ');
/**
* Returns an HSV interpolated value between two rgb values.
*
* @param {Object} rgbA - rgb() Tuple
* @param {Object} rgbB - rgb() Tuple
* @param {Number} threshold - float between [0.0, 1.0]
* @param {function} interpolatorFn - interpolator function
* @return {Object} rbg
*/
function interpolateHsv(rgbA, rgbB, threshold, interpolatorFn) {
var hsvA = rgbToHsv(rgbA);
var hsvB = rgbToHsv(rgbB);
threshold = toArray(threshold, 3);
return hsvToRgb({
h : interpolatorFn(hsvA.h, hsvB.h, threshold[0]),
s : interpolatorFn(hsvA.s, hsvB.s, threshold[1]),
v : interpolatorFn(hsvA.v, hsvB.v, threshold[2])
});
}
/**
* Returns an RGB interpolated value between two rgb values.
*
* @param {Object} rgbA - rgb() Tuple
* @param {Object} rgbB - rgb() Tuple
* @param {Number} threshold - float between [0.0, 1.0]
* @param {function} interpolatorFn - interpolator function
* @return {Object} rbg
*/
function interpolateRgb(rgbA, rgbB, threshold, interpolatorFn) {
threshold = toArray(threshold, 3);
return {
r : ~~interpolatorFn(rgbA.r, rgbB.r, threshold[0]),
g : ~~interpolatorFn(rgbA.g, rgbB.g, threshold[1]),
b : ~~interpolatorFn(rgbA.b, rgbB.b, threshold[2])
};
}
/**
* Returns an interpolated value between two values.
*
* @param {Number} valueA - color channel int value
* @param {Number} valueB - color channel int value
* @param {Number} threshold - float between [0.0, 1.0]
* @param {function} interpolatorFn - interpolator function
* @return {int}
*/
function linear(valueA, valueB, threshold) {
return valueA * (1 - threshold) + valueB * threshold;
}
/**
* Converts an RGB color value to HSV. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and v in the set [0, 1].
*
* @param {Object} rgb - Color in rgb mode
* @return {Object} - Color in hsv mode
*/
function rgbToHsv(rgb) {
var r = rgb.r / 255,
g = rgb.g / 255,
b = rgb.b / 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, v = max;
var d = max - min;
s = max === 0 ? 0 : d / max;
if (max == min) {
h = 0; // achromatic
} else {
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return {
h : h,
s : s,
v : v
};
}
/**
* Converts an HSV color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes h, s, and v are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param {Object} hsv - Color in hsv mode
* @return {Object} - Color in rgb mode
*/
function hsvToRgb(hsv){
var r, g, b, i, f, p, q, t,
h = hsv.h,
s = hsv.s,
v = hsv.v;
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch(i % 6){
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return {
r : r * 255,
g : g * 255,
b : b * 255
};
}
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function toArray(arr, size) {
var isNum = isNumeric(arr);
arr = !Array.isArray(arr) ? [arr] : arr;
for (var i = 1; i < size; i++) {
if (arr.length < size) {
arr.Push(isNum ? arr[0] : 0);
}
}
return arr;
}
この質問に「openframeworks」タグを付けたようです。したがって、必要なのはメソッドofColor::getLerped
またはofColor::lerp
を使用することだけです。
getLerped
は新しい値を返し、lerp
は色を変更します。
例えば:
ofColor c1(151,206,255);
ofColor c2(114,127,157);
float p = 0.2f;
ofColor c3 = c1.getLerped(c2, p);
または
c1.lerp(c2, 0.3f);