ある色を同じ色の別の色合いに補間しようとしています。(例: スカイブルーからダークブルーへ、そして戻る)。
範囲が 0 ~ 255 または 0 ~ 1 の場合に使用できるコードを見つけました。ただし、私の場合、Color1 と Color2 の RGB コードがあり、回転を発生させたいと考えています。
カラー 1: 151,206,255
カラー 2: 114,127,157
これについてどうすればいいですか?
ある色を同じ色の別の色合いに補間しようとしています。(例: スカイブルーからダークブルーへ、そして戻る)。
範囲が 0 ~ 255 または 0 ~ 1 の場合に使用できるコードを見つけました。ただし、私の場合、Color1 と Color2 の RGB コードがあり、回転を発生させたいと考えています。
カラー 1: 151,206,255
カラー 2: 114,127,157
これについてどうすればいいですか?
これが少し古いことは知っていますが、誰かがそれを探しているなら価値があります.
まず第一に、RGB を含む任意の色空間で補間を行うことができます。これは、私の意見では、最も簡単な色空間の 1 つです。
バリエーションが 0 から 1 の間の分数値 (たとえば 0.3) によって制御されると仮定しましょう。ここで、0 はフル カラー 1 を意味し、1 はフル カラー 2 を意味します。
法則:
Result = (color2 - color1) * fraction + color1
申請中:
RGB には 3 つのチャネル (赤、緑、青) があるため、チャネルごとにこの計算を実行する必要があります。
あなたの例の色を使用して:
fraction: 0.3
color1: 151,206,255
color2: 114,127,157
R = (114-151) * fraction + 151
G = (127-206) * fraction + 206
B = (157-255) * fraction + 255
C/C++ でのコード例:
/**
* interpolate 2 RGB colors
* @param color1 integer containing color as 0x00RRGGBB
* @param color2 integer containing color as 0x00RRGGBB
* @param fraction how much interpolation (0..1)
* - 0: full color 1
* - 1: full color 2
* @return the new color after interpolation
*/
int interpolate(int color1, int color2, float fraction)
{
unsigned char r1 = (color1 >> 16) & 0xff;
unsigned char r2 = (color2 >> 16) & 0xff;
unsigned char g1 = (color1 >> 8) & 0xff;
unsigned char g2 = (color2 >> 8) & 0xff;
unsigned char b1 = color1 & 0xff;
unsigned char b2 = color2 & 0xff;
return (int) ((r2 - r1) * fraction + r1) << 16 |
(int) ((g2 - g1) * fraction + g1) << 8 |
(int) ((b2 - b1) * fraction + b1);
}
/*
* 0x0097ceff == RGB(151,206,255)
* 0x00727f9d == RGB(114,127,157)
*/
int new_color = interpolate(0x0097ceff, 0x00727f9d, 0.3f);
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カラーをHSVに変換し、各コンポーネントを補間します(色だけでなく、回答の最後を参照)。その後、RGBに戻すことができます。
RGB 補間を実行できますが、HSV では色が輝度と彩度から分離されているため、結果は HSV の方が優れています ( HSV に関するウィキペディアの記事)。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);
この質問に「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);
Synxis の C の例(上記) を実行可能な JavaScript プログラムに適合させました。
プログラムは、赤と緑から黄色を補間します。入力と出力はRGB 空間にありますが、補間はHSV 空間で処理されます。RGB 補間の例も追加しました。以下に示すように、RGB 空間で赤と緑を補間すると、濃い黄色が生成されます。
/** 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;
}