数组数组中最近的数组

如何解决数组数组中最近的数组

我有一个数组 colors

const colors = [
    [0,10,56],[40,233,247],[50,199,70],[255,0],...
];

一个函数reduceColor

const reduceColor = pix => {
    let lowdist = Number.MAX_SAFE_INTEGER;
    let closestColor;
    for (let color of colors) {
        const dist = Math.abs(pix[0] - color[0]) + 
                     Math.abs(pix[1] - color[1]) + 
                     Math.abs(pix[2] - color[2]) ;
        if (dist<lowdist) {
            lowdist = dist;
            closestColor = color;
        }
    }
    return closestColor;
}

console.log(reduceColor([240,30]));
// [255,0]

哪个工作很好,但在整个图像的上下文中很慢。

有没有办法在提供数组时检查另一个数组(由子数组组成)中最近的子数组,而不必迭代和检查每个子数组?

解决方法

我认为没有更好的解决方案,您必须检查每一行,但是如果您充分利用其内置方法,您可以使用通常具有更快实现的 Typed Arrays。通常浏览器在音频处理或画布渲染中使用这些类型化数组。

一定要避免使用 JS 数组,因为它们在内存中不是连续的,对它们进行大量操作可能会非常慢。类型化数组是连续的。

还要避免使用 Math 方法,因为它们是通过 JS 解释器对象的抽象实现的,所以 Math.abs 可能会很慢(它应该处理大数、浮点数、字符串、null、NaN 等) .在这些情况下,数值运算会更快。

对于解决方案,您可以使用 Uint32Array (MDN),将颜色重新解释为 32 位数字。在十六进制中,我们用 2 个十六进制数字表示一个字节,因此 32 位是 8 位数字。我们将它们存储在数组中:

   -- RR GG BB
0x 00 00 00 00
function makeColor(r,g,b) {
  // the 32-bit color will be "0x00RRGGBB" in hex
  return (r << 16) + (g << 8) + b;
}

function parseColor(color) {
  // isolating the corrispondent bit of the colors
  return [ (color & 0xff0000) >> 16,(color & 0xff00) >> 8,color & 0xff ];
}

function makeColorArray(colors) {
  // creating the Uint32Array from the colors array
  return new Uint32Array(colors.map(c => makeColor(...c)));
}

function distanceRGB(p1,p2) {
  let r1 = (p1 & 0xff0000) >> 16,// extract red p1
      g1 = (p1 &   0xff00) >> 8,// extract green p1
      b1 =  p1 &     0xff,// extract blue p1
      r2 = (p2 & 0xff0000) >> 16,// extract red p2
      g2 = (p2 &   0xff00) >> 8,// extract green p2
      b2 =  p2 &     0xff,// extract blue p2
      rd = r1 > r2 ? (r1 - r2) : (r2 - r1),// compute dist r
      gd = g1 > g2 ? (g1 - g2) : (g2 - g1),// compute dist g
      bd = b1 > b2 ? (b1 - b2) : (b2 - b1); // compute dist b
  return rd + gd + bd; // sum them up
}

// rising the threshold can speed up the process
function findNearest(colors,distance,threshold) {
  return function(pixel) {
    let bestDist = 765,best = 0,curr; // 765 is the max distance
    for (c of colors) {
      curr = distance(pixel,c);
      if (curr <= threshold) { return c; }
      else if (curr < bestDist) {
        best = c;
        bestDist = curr;
      }
    }
    return best;
  };
}

const colors = makeColorArray([
    [0,10,56],[40,233,247],[50,199,70],[255,0],//... other colors
]);

const image = makeColorArray([
   [240,30]
   //... other pixels
])

const nearest = Array.from(image.map(findNearest(colors,distanceRGB,0))).map(parseColor)
// ===== TEST  =====
function randomColor() {
  return [ Math.floor(Math.random() * 255),Math.floor(Math.random() * 255),Math.floor(Math.random() * 255) ];
}
testImages = [];
for (let i = 0; i < 1000000; ++i) { testImages.push(randomColor()); }
testImages = makeColorArray(testImages)

testColors = [];
for (let i = 0; i < 1000; ++i) { testColors.push(randomColor()); }
testColors = makeColorArray(testColors);

// START
let testNow = Date.now();
Array.from(testImages.map(findNearest(testColors,0))).map(parseColor)
console.log(Date.now() - testNow)

我已经用 4 种颜色对超过一百万个随机像素 (1000x1000) 进行了测试,耗时不到一秒(~250-450 毫秒),一千种测试颜色需要 12-15 秒。用普通阵列做同样的实验只用 4 种颜色就需要 4-6 秒,我没有尝试千色测试(显然都是在我的电脑上)。

考虑将繁重的工作交给 Worker (MDN) 以避免 UI 冻结。

我不知道在更大的图像上运行是否足够。我相信它可以进一步优化(也许通过格雷码汉明距离),但顺便说一下,这是一个很好的起点。

您也可能有兴趣获得一种从图像中提取像素值的方法,只需检查 <img><canvas> 元素中的 ImageData (MDN)how to retrive it (Stack Overflow)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?