Найти шестнадцатеричные цвета и X, Y в изображениях - PullRequest
0 голосов
/ 26 марта 2020

Я пытаюсь найти все шестнадцатеричные цвета на изображении и, если возможно, обведите или выделите положение X, Y того, где находятся шестнадцатеричные цвета. Мой текущий код пытается найти все цвета и почти сбивает мой браузер, и моя попытка найти координаты X, Y каждого изображения тоже не подходит.

У меня есть две функции, выполняющие разные функции, вот что Я пытался работать, чтобы привести пример того, что пытались ... Любая помощь была бы отличной!

Любая помощь была бы удивительной!

<canvas id="myCanvas" width="240" height="297" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
</canvas>
<img id="origImage" width="220" height="277" src="loggraph.PNG">
<script>
function getPixel(imgData, index) {
    var i = index*4, d = imgData.data;
    return [d[i],d[i+1],d[i+2],d[i+3]] // [R,G,B,A]
  }

  function getPixelXY(imgData, x, y) {
    return getPixel(imgData, y*imgData.width+x);
  }

    function goCheck() {
            var cvs = document.createElement('canvas'),
            img = document.getElementsByTagName("img")[0]; 
            cvs.width = img.width; cvs.height = img.height;
            var ctx = cvs.getContext("2d");
            ctx.drawImage(img,0,0,cvs.width,cvs.height);
            var idt = ctx.getImageData(0,0,cvs.width,cvs.height);

            console.log(getPixel(idt, 852));  // returns array [red, green, blue, alpha]
            console.log(getPixelXY(idt,1,1)); // same pixel using x,y
    }

        function getColors(){
                var canvas = document.getElementById("myCanvas");
                var devices = canvas.getContext("2d");
                var imageData = devices.getImageData(0, 0, canvas.width, canvas.height);
                var data = imageData.data;


                // iterate over all pixels
                for(var i = 0, n = data.length; i < n; i += 4) {
                var r  = data[i];
                var g  = data[i + 1];
                var b  = data[i + 2];   
                var rgb = "("+r+","+g+","+b+")";

                var incoming = i*4, d = imageData.data;
                var bah = [d[incoming],d[incoming+1],d[incoming+2],d[incoming+3]];
                    $('#list').append("<li>"+rgb+"</li>");
                    colorList.push(rgb);
                    }
                $('#list').append("<li>"+[d[incoming],d[incoming+1],d[incoming+2],d[incoming+3]]+"</li>");     
                    }    

        }

1 Ответ

2 голосов
/ 26 марта 2020

Необходимо проверить все пиксели

Чтобы найти пиксель, соответствующий цвету, в худшем случае (пиксель этого цвета отсутствует на изображении) вам нужно перешагнуть через каждый пиксель изображения.

Как этого не делать

Преобразование каждого пикселя в строку DOM является наихудшим способом сделать это, поскольку строка DOM использует много памяти и ресурсов ЦП, особенно если создается с использованием jQuery (у которого есть свой дополнительный багаж)

От шестнадцатеричного цвета к массиву

Чтобы найти пиксель, вам нужно только проверить данные цвета каждого пикселя относительно значения HEX. Вы преобразуете шестнадцатеричное значение в массив из 3 байтов.

Следующая функция преобразует из CSS шестнадцатеричных форматов "#HHH" "#HHHH", "#HHHHHH" и "#HHHHHHHH", игнорируя альфа-часть, если она включена, к массиву целых чисел 0-255

const hex2RGB = h => {
    if(h.length === 4 || h.length === 5) {
        return [parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16), parseInt(h[3] + h[3], 16)];
    }
    return [parseInt(h[1] + h[2], 16), parseInt(h[3] + h[4], 16), parseInt(h[5] + h[6], 16)];
}

Поиск пикселя

Я не знаю, как вы планируете использовать такую ​​функцию, поэтому приведенный ниже пример - это метод общего назначения, который поможет и может быть изменен при необходимости

Он всегда найдет пиксель, если вы позволите ему, даже если нет идеального соответствия. Это достигается путем нахождения ближайшего к нужному цвету цвета.

Причина, по которой наиболее близкое совпадение заключается в том, что при рисовании изображения на 2D-холсте значения пикселей слегка изменяются, если изображение имеет прозрачные пиксели (предварительно умноженное альфа) * ​​1026 *

Функция находит пиксель путем измерения пространственного расстояния между пикселем и шестнадцатеричным цветом (простая геометрия Пифагора). Ближайший цвет - это наименьшее расстояние.

Возвращает объект

{
   x, // the x coordinate of the match
   y, // the y coordinate of the match
   distance, // how closely the color matches the requested color.
             // 0 means a perfect match 
             // to 441 completely different eg black and white
             // value is floored to an integer value
}

Если изображение испорчено (перекрестное происхождение, локальное устройство хранения) или вы пропустили что-то которые не могут быть преобразованы в пиксели, функция вернет undefined

Функция сохраняет холст, который она использует для получения данных пикселей, поскольку предполагает, что она будет использоваться много раз. Если изображение испорчено, оно поймает ошибку (добавит предупреждение в консоль), очистит испорченный холст и будет готово для другого изображения.

Использование

Чтобы использовать функцию, добавьте его в Ваша база кода будет настроена автоматически.

Получите изображение и шестнадцатеричное значение и вызовите функцию с цветом image, CSS hex и, при желании, пороговым расстоянием для соответствия цветов.

Например, найти точное соответствие для # FF0000

const result = findPixel(origImage, "#FF0000", 0); // find exact match for red
if (result) { // only if found
     console.log("Found color #FF0000 at pixel " + result.x + ", " + result.y);
} else {
     console.log("The color #FF0000 is not in the image");
}

или найти цвет, близкий к

const result = findPixel(origImage, "#FF0000", 20); // find a match for red
                                                    // within 20 units. 
                                                    // A unit is 1 of 256
if (result) { // only if found
     console.log("Found closest color within " + result.distance + "units of #FF0000 at pixel " + result.x + ", " + result.y);
}

или найти ближайший

// find the closest, no threshold ensures a result
const result = findPixel(origImage, "#FF0000"); 
console.log("Found closest color within " + result.distance + "units of #FF0000 at pixel " + result.x + ", " + result.y);

Код

Функция выглядит следующим образом.

const findPixel = (() => {
    var can, ctx;
    function createCanvas(w, h) {
        if (can === undefined){
            can = document.createElement("canvas");
            ctx = can.getContext("2d");     
        }
        can.width = w;
        can.height = h;
    }
    function getPixels(img) {
        const w = img.naturalWidth || img.width, h =  img.naturalHeight || img.height;
        createCanvas(w, h);
        ctx.drawImage(img, 0, 0);
        try {
            const imgData = ctx.getImageData(0, 0, w, h);
            can.width = can.height = 1; // make canvas as small as possible so it wont 
                                        // hold memory. Leave in place to avoid instantiation overheads
            return imgData;
        } catch(e) { 
            console.warn("Image is un-trusted and pixel access is blocked");
            ctx = can = undefined; // canvas and context can no longer be used so dump them
        }
        return {width: 0, height: 0, data: []}; // return empty pixel data
    }
    const hex2RGB = h => { // Hex color to array of 3 values
        if(h.length === 4 || h.length === 5) {
            return [parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16), parseInt(h[3] + h[3], 16)];
        }
        return [parseInt(h[1] + h[2], 16), parseInt(h[3] + h[4], 16), parseInt(h[5] + h[6], 16)];
    }
    const idx2Coord = (idx, w) => ({x: idx % w, y: idx / w | 0});
    return function (img, hex, minDist = Infinity) {
        const [r, g, b] = hex2RGB(hex);         
        const {width, height, data} = getPixels(img);
        var idx = 0, found;
        while (idx < data.length) {
            const R = data[idx] - r;
            const G = data[idx + 1] - g;
            const B = data[idx + 2] - b;
            const d = R * R + G * G + B * B;
            if (d === 0) { // found exact match 
                return {...idx2Coord(idx / 4, width), distance: 0};
            }
            if (d < minDist) {
                minDist = d;
                found = idx;
            }
            idx += 4;
        }
        return found ? {...idx2Coord(found / 4, width), distance: minDist ** 0.5 | 0 } : undefined;
    }
})();

Эта функция была протестирована и работает, как описано выше.

Примечание Если код, указанный в вашем вопросе, игнорировать альфа-значение изображения и CSS шестнадцатеричный цвет.

Обратите внимание , что если вы собираетесь найти много цветов на том же изображении эта функция не совсем подходит для ваших нужд. Если это так, дайте мне знать в комментарии, и я могу внести изменения или объяснить, как оптимизировать код для таких целей.

Примечание Он не очень подходит для одноразового использования , Однако в этом случае измените строку const findPixel = (() => { на var findPixel = (() => { и после ее использования удалите ссылку findpixel = undefined;, а JS очистит все имеющиеся у нее ресурсы.

Примечание Если вы также хотите получить фактический цвет ближайшего найденного цвета, который тоже тривиально добавить. Спросите в комментариях.

Примечание Это достаточно быстро (вам будет трудно получить более быстрый результат), но имейте в виду, что для очень больших изображений 4K и выше это может занять немного и на устройствах очень низкого уровня это может вызвать ошибку нехватки памяти. Если это проблема, тогда возможно другое решение, но оно намного медленнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...