Я пытаюсь реализовать код, который выбирает цвета из изображения, а затем получает палитру определенных цветов из всех цветов изображения. Я пытаюсь использовать алгоритм Median Cut для реализации этого.
В настоящее время я выполняю шаги для алгоритма Median Cut, упомянутого здесь:
Вот фрагмент кода из моего POC:
const getColor = () => {
const canvas = document.createElement('canvas');
canvas.width = displayImage.width;
canvas.height = displayImage.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(displayImage, 0, 0);
const pixelData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
getPallete(pixelData);
};
const getPallete = (data) => {
// data contains image data (r,g,b,a)
if (data.length != 0) {
for (let i = 0; i < data.length; i += 4) {
let [red, green, blue] = [data[i], data[i + 1], data[i + 2]];
if (red < channelProperties.minRed) {
channelProperties.minRed = red;
}
if (red > channelProperties.maxRed) {
channelProperties.maxRed = red;
}
// Update minimum and maximum values for green channel
if (green < channelProperties.minGreen) {
channelProperties.minGreen = green;
}
if (green > channelProperties.maxGreen) {
channelProperties.maxGreen = green;
}
// Update minimum and maximum values for blue channel
if (blue < channelProperties.minBlue) {
channelProperties.minBlue = blue;
}
if (blue > channelProperties.maxBlue) {
channelProperties.maxBlue = blue;
}
}
// gets the channel with highest range
let highestChannel = getChannel();
//This sorts the image data based on highest channel
let sortedData = sortImageData(data, highestChannel);
//This gives back the middle index
let median = getMedian(sortedData);
//Here I break the array from median and resend it
const lowerPart = data.slice(0, median);
const upperPart = data.slice(median + 1);
getPallete(lowerPart);
getPallete(upperPart);
}
};
Я реализовал первые 4 шага, упомянутые в ссылке. Тем не менее, я ошибаюсь на последнем шаге или, скорее, я не могу понять, как получить мой последний поддон. Может ли кто-нибудь помочь исправить этот код/рассказать мне, что я пропустил?
Похоже, вы ничего не возвращаете и, похоже, не нарушаете рекурсию. Кроме того, в связанном источнике говорится, что вы должны строить средние значения по корзинам. И вам нужно указать количество цветов для поиска, что соответствует количеству итераций.
Вот что, я думаю, вам нужно добавить:
const getPallete = (data, iterations) => {
if (data.length === 0) {
return []
}
if (iterations <= 1){
return [getAverageColor(data)] // <--- build bucket average
}
// build upper and lower bucket, same as before
return [ // <--- collect and return recursion result
...getPallete(lowerPart, iterations-1),
...getPallete(upperPart, iterations-1)
]
}
const getAverageColor = (data) => {
const sums = [0,0,0,0]
for (let i = 0; i < data.length; i += 4) {
for (let j = 0; j < 4; j++) {
sums[j] += data[i+j]
}
}
const numberOfPixels = data.length / 4
return sums.map(v => Math.round(v/numberOfPixels))
}
Вот быстрая песочница
О, интересно. Я предполагаю, что это алгебраическая операция с undefined
, вероятно, из-за доступа к индексу массива, который не установлен. Я предполагаю, что sortImageData()
довольно много копирует, так что это похоже на место для поиска.
Обнаружил проблему, я пропускал средний индекс при нарезке массива (строка upperPart
была неправильной). Позже это привело к undefined
, поскольку цикл for в функции getAverageColor
увеличивался на 4
для каждой итерации. Однако я все еще довольно далек от решения, так как получаю темные цветовые оттенки, которые не являются частью изображения.
Ой, нашел ошибку в getAverageColor()
, средние надо делить на data.length / 4
, а не на data.length
. Я думаю, именно поэтому у вас более темные оттенки (извините!).
Не беспокойтесь, ваш код уже очень помог мне, показав правильный путь вперед, большое спасибо! Что касается моего прогресса, я рефакторил свой код (почти) с нуля. Я на 90% близок к тому, что я понимаю. Завтра сейчас проверю.
Это привело меня к тому, что я получаю значения NaN для некоторых цветов. Но, кажется, это укажет мне правильный путь. Я пытаюсь найти причину NaN прямо сейчас