gpt4 book ai didi

javascript - 如何优化 RGB 到 HSL 转换函数的执行时间?

转载 作者:塔克拉玛干 更新时间:2023-11-02 22:21:44 25 4
gpt4 key购买 nike

我创建了这个函数来将 RGB 颜色转换为 HSL 颜色。它工作完美。

但我需要让它运行得更快,因为它用于替换 Canvas 上的颜色,我需要减少替换时间。由于图像包含 360k 像素 (600x600px),因此任何东西都可以使它更快。

这是我当前的实现:

/**
* Convert RGB Color to HSL Color
* @param {{R: integer, G: integer, B: integer}} rgb
* @returns {{H: number, S: number, L: number}}
*/
Colorize.prototype.rgbToHsl = function(rgb) {
var R = rgb.R/255;
var G = rgb.G/255;
var B = rgb.B/255;
var Cmax = Math.max(R,G,B);
var Cmin = Math.min(R,G,B);
var delta = Cmax - Cmin;
var L = (Cmax + Cmin) / 2;
var S = 0;
var H = 0;

if (delta !== 0) {
S = delta / (1 - Math.abs((2*L) - 1));

switch (Cmax) {
case R:
H = ((G - B) / delta) % 6;
break;
case G:
H = ((B - R) / delta) + 2;
break;
case B:
H = ((R - G) / delta) + 4;
break;
}
H *= 60;
}

// Convert negative angles from Hue
while (H < 0) {
H += 360;
}

return {
H: H,
S: S,
L: L
};
};

最佳答案

tl;dr

  • 在计算之前定义一切
  • Switch 对性能不利
  • 循环不好
  • 使用 Closure Compiler 进行自动优化
  • 记住! (这个在基准测试中不可用,因为它当时只使用一种颜色)
  • 比较 Math.maxMath.min 中的对(据我所知,if-else 对于更大的数字效果更好)

基准

基准测试非常基础;我每次都生成随机 RGB 颜色并将其用于测试服。

转换器的所有实现都使用相同的颜色。

我目前使用的是高速计算机,因此您的数字可能会有所不同。

此时很难进一步优化,因为性能因数据而异。

优化

一开始就定义结果值的对象。预先为对象分配内存以某种方式提高了性能。

var res = {
H: 0,
S: 0,
L: L
}
// ...
return res;

不使用 switch 可以轻松提高性能。

if (delta !== 0) {
S = delta / (1 - Math.abs((2 * L) - 1));

if (Cmax === R) {
H = ((G - B) / delta) % 6;
} else if (Cmax === G) {
H = ((B - R) / delta) + 2;
} else if (Cmax === B) {
H = ((R - G) / delta) + 4;
}
H *= 60;
}

While 循环可以通过以下方式轻松移除:

if (H < 0) {
remainder = H % 360;

if (remainder !== 0) {
H = remainder + 360;
}
}

我还应用了 Closure Compiler 来删除代码中的冗余操作。

你应该记住结果!

考虑重构函数以使用三个参数,这样就可以为内存缓存提供一个多维 HashMap 。或者,您可以尝试使用 WeakMap ,但此解决方案的性能未知。

查看文章Faster JavaScript Memoization For Improved Application Performance

结果

节点.js

最好的是 rgbToHslOptimizedClosure

node -v
v6.5.0

rgbToHsl x 16,468,872 ops/sec ±1.64% (85 runs sampled)
rgbToHsl_ x 15,795,460 ops/sec ±1.28% (84 runs sampled)
rgbToHslIfElse x 16,091,606 ops/sec ±1.41% (85 runs sampled)
rgbToHslOptimized x 22,147,449 ops/sec ±1.96% (81 runs sampled)
rgbToHslOptimizedClosure x 46,493,753 ops/sec ±1.55% (85 runs sampled)
rgbToHslOptimizedIfElse x 21,825,646 ops/sec ±2.93% (85 runs sampled)
rgbToHslOptimizedClosureIfElse x 38,346,283 ops/sec ±9.02% (73 runs sampled)
rgbToHslOptimizedIfElseConstant x 30,461,643 ops/sec ±2.68% (81 runs sampled)
rgbToHslOptimizedIfElseConstantClosure x 40,625,530 ops/sec ±2.70% (73 runs sampled)

Fastest is rgbToHslOptimizedClosure
Slowest is rgbToHsl_

浏览器

Chrome Version 55.0.2883.95 (64-bit)

rgbToHsl x 18,456,955 ops/sec ±0.78% (62 runs sampled)
rgbToHsl_ x 16,629,042 ops/sec ±2.34% (63 runs sampled)
rgbToHslIfElse x 17,177,059 ops/sec ±3.85% (59 runs sampled)
rgbToHslOptimized x 27,552,325 ops/sec ±0.95% (62 runs sampled)
rgbToHslOptimizedClosure x 47,659,771 ops/sec ±3.24% (47 runs sampled)
rgbToHslOptimizedIfElse x 26,033,751 ops/sec ±2.63% (61 runs sampled)
rgbToHslOptimizedClosureIfElse x 43,430,875 ops/sec ±3.55% (59 runs sampled)
rgbToHslOptimizedIfElseConstant x 33,696,558 ops/sec ±3.97% (58 runs sampled)
rgbToHslOptimizedIfElseConstantClosure x 44,529,209 ops/sec ±3.56% (60 runs sampled)

Fastest is rgbToHslOptimizedClosure
Slowest is rgbToHsl_

自己运行基准测试

请注意,浏览器会卡住片刻。

function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

var RGB = { R: getRandomInt(0, 255), G: getRandomInt(0, 255), B: getRandomInt(0, 255) }

// http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c

/**
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and l in the set [0, 1].
*
* @param {number} r The red color value
* @param {number} g The green color value
* @param {number} b The blue color value
* @return {Array} The HSL representation
*/
function rgbToHsl_(r, g, b) {
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;

if (max == min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
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, s, l ];
}

function rgbToHsl(rgb) {
var R = rgb.R / 255;
var G = rgb.G / 255;
var B = rgb.B / 255;
var Cmax = Math.max(R, G, B);
var Cmin = Math.min(R, G, B);
var delta = Cmax - Cmin;
var L = (Cmax + Cmin) / 2;
var S = 0;
var H = 0;

if (delta !== 0) {
S = delta / (1 - Math.abs((2 * L) - 1));

switch (Cmax) {
case R:
H = ((G - B) / delta) % 6;
break;
case G:
H = ((B - R) / delta) + 2;
break;
case B:
H = ((R - G) / delta) + 4;
break;
}
H *= 60;
}

// Convert negative angles from Hue
while (H < 0) {
H += 360;
}

return {
H: H,
S: S,
L: L
};
};

function rgbToHslIfElse(rgb) {
var R = rgb.R / 255;
var G = rgb.G / 255;
var B = rgb.B / 255;
var Cmax = Math.max(R, G, B);
var Cmin = Math.min(R, G, B);
var delta = Cmax - Cmin;
var L = (Cmax + Cmin) / 2;
var S = 0;
var H = 0;

if (delta !== 0) {
S = delta / (1 - Math.abs((2 * L) - 1));

if (Cmax === R) {
H = ((G - B) / delta) % 6;
} else if (Cmax === G) {
H = ((B - R) / delta) + 2;
} else if (Cmax === B) {
H = ((R - G) / delta) + 4;
}
H *= 60;
}

// Convert negative angles from Hue
while (H < 0) {
H += 360;
}

return {
H: H,
S: S,
L: L
};
};

function rgbToHslOptimized(rgb) {
var R = rgb.R / 255;
var G = rgb.G / 255;
var B = rgb.B / 255;
var Cmax = Math.max(Math.max(R, G), B);
var Cmin = Math.min(Math.min(R, G), B);
var delta = Cmax - Cmin;
var S = 0;
var H = 0;
var L = (Cmax + Cmin) / 2;
var res = {
H: 0,
S: 0,
L: L
}
var remainder = 0;

if (delta !== 0) {
S = delta / (1 - Math.abs((2 * L) - 1));

switch (Cmax) {
case R:
H = ((G - B) / delta) % 6;
break;
case G:
H = ((B - R) / delta) + 2;
break;
case B:
H = ((R - G) / delta) + 4;
break;
}
H *= 60;
}

if (H < 0) {
remainder = H % 360;

if (remainder !== 0) {
H = remainder + 360;
}
}

res.H = H;
res.S = S;

return res;
}

function rgbToHslOptimizedIfElse(rgb) {
var R = rgb.R / 255;
var G = rgb.G / 255;
var B = rgb.B / 255;
var Cmax = Math.max(Math.max(R, G), B);
var Cmin = Math.min(Math.min(R, G), B);
var delta = Cmax - Cmin;
var S = 0;
var H = 0;
var L = (Cmax + Cmin) / 2;
var res = {
H: 0,
S: 0,
L: L
}
var remainder = 0;

if (delta !== 0) {
S = delta / (1 - Math.abs((2 * L) - 1));

if (Cmax === R) {
H = ((G - B) / delta) % 6;
} else if (Cmax === G) {
H = ((B - R) / delta) + 2;
} else if (Cmax === B) {
H = ((R - G) / delta) + 4;
}
H *= 60;
}

if (H < 0) {
remainder = H % 360;

if (remainder !== 0) {
H = remainder + 360;
}
}

res.H = H;
res.S = S;

return res;
}

function rgbToHslOptimizedIfElseConstant(rgb) {
var R = rgb.R * 0.00392156862745;
var G = rgb.G * 0.00392156862745;
var B = rgb.B * 0.00392156862745;
var Cmax = Math.max(Math.max(R, G), B);
var Cmin = Math.min(Math.min(R, G), B);
var delta = Cmax - Cmin;
var S = 0;
var H = 0;
var L = (Cmax + Cmin) * 0.5;
var res = {
H: 0,
S: 0,
L: L
}
var remainder = 0;

if (delta !== 0) {
S = delta / (1 - Math.abs((2 * L) - 1));

if (Cmax === R) {
H = ((G - B) / delta) % 6;
} else if (Cmax === G) {
H = ((B - R) / delta) + 2;
} else if (Cmax === B) {
H = ((R - G) / delta) + 4;
}
H *= 60;
}

if (H < 0) {
remainder = H % 360;

if (remainder !== 0) {
H = remainder + 360;
}
}

res.H = H;
res.S = S;

return res;
}

function rgbToHslOptimizedIfElseConstantClosure(c) {
var a = .00392156862745 * c.h, e = .00392156862745 * c.f, f = .00392156862745 * c.c, g = Math.max(Math.max(a, e), f), d = Math.min(Math.min(a, e), f), h = g - d, b = c = 0, k = (g + d) / 2, d = {
a: 0,
b: 0,
g: k
};
0 !== h && (c = h / (1 - Math.abs(2 * k - 1)), g === a ? b = (e - f) / h % 6 : g === e ? b = (f - a) / h + 2 : g === f && (b = (a - e) / h + 4), b *= 60);
0 > b && (a = b % 360, 0 !== a && (b = a + 360));
d.a = b;
d.b = c;
return d;
};

function rgbToHslOptimizedClosure(c) {
var a = c.f / 255, e = c.b / 255, f = c.a / 255, k = Math.max(Math.max(a, e), f), d = Math.min(Math.min(a, e), f), g = k - d, b = c = 0, l = (k + d) / 2, d = {
c: 0,
g: 0,
h: l
};
if (0 !== g) {
c = g / (1 - Math.abs(2 * l - 1));
switch (k) {
case a:
b = (e - f) / g % 6;
break;
case e:
b = (f - a) / g + 2;
break;
case f:
b = (a - e) / g + 4;
}
b *= 60;
}
0 > b && (a = b % 360, 0 !== a && (b = a + 360));
d.c = b;
d.g = c;
return d;
}

function rgbToHslOptimizedClosureIfElse(c) {
var a = c.f / 255, e = c.b / 255, f = c.a / 255, g = Math.max(Math.max(a, e), f), d = Math.min(Math.min(a, e), f), h = g - d, b = c = 0, l = (g + d) / 2, d = {
c: 0,
g: 0,
h: l
};
0 !== h && (c = h / (1 - Math.abs(2 * l - 1)), g === a ? b = (e - f) / h % 6 : g === e ? b = (f - a) / h + 2 : g === f && (b = (a - e) / h + 4), b *= 60);
0 > b && (a = b % 360, 0 !== a && (b = a + 360));
d.c = b;
d.g = c;
return d;
}

new Benchmark.Suite()
.add('rgbToHsl', function () {
rgbToHsl(RGB);
})
.add('rgbToHsl_', function () {
rgbToHsl_(RGB.R, RGB.G, RGB.B);
})
.add('rgbToHslIfElse', function () {
rgbToHslIfElse(RGB);
})
.add('rgbToHslOptimized', function () {
rgbToHslOptimized(RGB);
})
.add('rgbToHslOptimizedClosure', function () {
rgbToHslOptimizedClosure(RGB);
})
.add('rgbToHslOptimizedIfElse', function () {
rgbToHslOptimizedIfElse(RGB);
})
.add('rgbToHslOptimizedClosureIfElse', function () {
rgbToHslOptimizedClosureIfElse(RGB);
})
.add('rgbToHslOptimizedIfElseConstant', function () {
rgbToHslOptimizedIfElseConstant(RGB);
})
.add('rgbToHslOptimizedIfElseConstantClosure', function () {
rgbToHslOptimizedIfElseConstantClosure(RGB);
})
// add listeners
.on('cycle', function (event) {
console.log(String(event.target));
})
.on('complete', function () {
console.log('Fastest is ' + this.filter('fastest').map('name'));
console.log('Slowest is ' + this.filter('slowest').map('name'));
})
// run async
.run({ 'async': false });
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdn.rawgit.com/bestiejs/benchmark.js/master/benchmark.js"></script>

关于javascript - 如何优化 RGB 到 HSL 转换函数的执行时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41229411/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com