在图像中查找十六进制颜色和X,Y



我正在尝试查找图像中的所有十六进制颜色,如果可能,请圈出或突出显示十六进制颜色所在的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>");     
}    
}

必须检查所有像素

在最坏的情况下(该颜色的像素不在图像中(,要找到与颜色匹配的像素,需要对图像中的每个像素进行遍历。

如何避免

将每个像素转换为DOM字符串是最糟糕的方法,因为DOM字符串会占用大量内存和CPU开销,尤其是在使用jQuery(它有自己的附加行李(实例化的情况下

数组的十六进制颜色

要找到像素,您只需要对照HEX值检查每个像素的颜色数据。您可以将十六进制值转换为一个3字节的数组。

以下函数将忽略alpha部分(如果包含(,从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)];
}

查找像素

我不知道你打算如何使用这样的功能,所以下面的例子是一个通用的方法,可以根据需要修改

如果你让它,即使没有完美的匹配,它也总能找到一个像素。它通过找到与你想要的颜色最接近的颜色来实现这一点。

of找到最匹配的原因是,当你在2D画布上绘制图像时,如果图像具有透明像素(预乘阿尔法(,则像素值会略有修改

函数通过测量像素和十六进制颜色之间的空间距离来找到像素(简单几何毕达哥拉斯(。距离最近的颜色是距离最小的颜色。

它将返回对象

{
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、CSShex颜色以及颜色匹配的阈值距离调用函数。

例如,找到#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;
}
})();

此功能已按上文所述进行了测试和工作

注意根据问题中的代码,忽略图像的alpha值和CSS十六进制颜色。

请注意如果您想从同一张图像中找到多种颜色,此功能并不最适合您的需要。如果是这种情况,请在评论中告诉我,我可以进行更改或指导您如何乐观地使用代码。

注意它不太适合单独使用。但是,如果是这种情况,请将行const findPixel = (() => {更改为var findPixel = (() => {,并在使用它之后删除引用findpixel = undefined;,JS将清理它所拥有的所有资源。

注意如果您还想获得最接近的颜色的实际颜色,那么添加它也很简单。在评论中提问。

注意它相当快(您将很难获得更快的结果(,但请注意,对于4K及以上的超大图像,它可能需要一点时间,而在非常低端的设备上,它可能会导致内存不足错误。如果这是一个问题,那么另一种解决方案是可能的,但速度要慢得多。

最新更新