在图像中找到相似颜色的区域 [英] Find regions of similar color in image

查看:113
本文介绍了在图像中找到相似颜色的区域的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究这个问题已经有一段时间没有什么好处了。我试图将图像分割成相似颜色的连接区域。 (基本上将所有像素的列表分成多个组(每个组包含属于它的像素的坐标并共享相似的颜色)。

I've been working on this problem for some time now with little promising results. I am trying to split up an image into connected regions of similar color. (basically split a list of all the pixels into multiple groups (each group containing the coordinates of the pixels that belong to it and share a similar color).

例如:
http://unsplash.com/photos/SoC1ex6sI4w/

在这张图片中,顶部的乌云可能会分成一组。山上的一些灰色岩石在另一组中,一些橙色的草在另一组中。雪将是另一组 - 背包的红色等等。

In this image the dark clouds at the top would probably fall into one group. Some of the grey rock on the mountain in another, and some of the orange grass in another. The snow would be another - the red of the backpack - etc.

我正在尝试设计一种既准确又高效的算法(它需要在几秒钟内运行)中档笔记本电脑级硬件)

I'm trying to design an algorithm that will be both accurate and efficient (it needs to run in a matter of ms on midrange laptop grade hardware)

以下是我的尝试:

使用基于连通分量的算法从左上角扫描每个像素,从左到右扫描每一行像素(并将当前像素与顶部像素和左像素进行比较)。如果顶部或左侧的像素在一定范围内,那么唱CIEDE2000色差公式,那么它将被视为相似并且是该组的一部分。

Using a connected component based algorithm to go through every pixel from top left scanning every line of pixels from left to right (and comparing the current pixel to the top pixel and left pixel). Using the CIEDE2000 color difference formula if the pixel at the top or left was within a certain range then it would be considered "similar" and part of the group.

这种工作 - 但问题是它依赖于具有锐边的颜色区域 - 如果任何颜色组通过软渐变连接它将沿着该渐变向下移动并继续连接像素,因为被比较的各个像素之间的差异是小到足以被认为是相似。

This sort of worked - but the problem is it relies on color regions having sharp edges - if any color groups are connected by a soft gradient it will travel down that gradient and continue to "join" the pixels as the difference between the individual pixels being compared is small enough to be considered "similar".

为了尝试解决这个问题,我选择将每个访问过的像素的颜色设置为大多数相似相邻像素的颜色(顶部或左)。如果没有相似的像素,则保留其原始颜色。这在某种程度上解决了更加模糊的边界或柔化边缘的问题,因为随着算法的进展,新组的第一种颜色将被携带,并且最终该颜色与当前比较颜色之间的差异将超过相似性威胁和不再是该群体的一部分。

To try to fix this I chose to set every visited pixel's color to the color of most "similar" adjacent pixel (either top or left). If there are no similar pixels than it retains it's original color. This somewhat fixes the issue of more blurred boundaries or soft edges because the first color of a new group will be "carried" along as the algorithm progresses and eventually the difference between that color and the current compared color will exceed the "similarity" threashold and no longer be part of that group.

希望这是有道理的。问题是这些选项都没有真正起作用。在上面的图像上返回的不是干净的组,而是嘈杂的碎片组,这不是我想要的。

Hopefully this is making sense. The problem is neither of these options are really working. On the image above what is returned are not clean groups but noisy fragmented groups that is not what I am looking for.

我不是专门寻找代码 - 但更多关于如何构建算法以成功解决此问题的想法。有没有人有这方面的想法?

I'm not looking for code specifically - but more ideas as to how an algorithm could be structured to successfully combat this problem. Does anyone have ideas about this?

谢谢!

推荐答案

你可以从 RGB 转换为 HSL ,以便更容易计算颜色之间的距离。我在行中设置色差容差:

You could convert from RGB to HSL to make it easier to calculate the distance between the colors. I'm setting the color difference tolerance in the line:

if (color_distance(original_pixels[i], group_headers[j]) < 0.3) {...}

如果更改 0.3 ,你可以得到不同的结果。

If you change 0.3, you can get different results.

看到它正常工作

请告诉我是否有帮助。

function hsl_to_rgb(h, s, l) {
    // from http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
    var r, g, b;

    if (s == 0) {
      r = g = b = l; // achromatic
    } else {
      var hue2rgb = function hue2rgb(p, q, t) {
        if (t < 0) t += 1;
        if (t > 1) t -= 1;
        if (t < 1 / 6) return p + (q - p) * 6 * t;
        if (t < 1 / 2) return q;
        if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
        return p;
      }

      var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
      var p = 2 * l - q;
      r = hue2rgb(p, q, h + 1 / 3);
      g = hue2rgb(p, q, h);
      b = hue2rgb(p, q, h - 1 / 3);
    }

    return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
  }

function rgb_to_hsl(r, g, b) {
    // from http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
    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 color_distance(v1, v2) {
  // from http://stackoverflow.com/a/13587077/1204332
  var i,
    d = 0;

  for (i = 0; i < v1.length; i++) {
    d += (v1[i] - v2[i]) * (v1[i] - v2[i]);
  }
  return Math.sqrt(d);
};

function round_to_groups(group_nr, x) {
  var divisor = 255 / group_nr;
  return Math.ceil(x / divisor) * divisor;
};

function pixel_data_to_key(pixel_data) {
  return pixel_data[0].toString() + '-' + pixel_data[1].toString() + '-' + pixel_data[2].toString();

}

function posterize(context, image_data, palette) {
  for (var i = 0; i < image_data.data.length; i += 4) {
    rgb = image_data.data.slice(i, i + 3);
    hsl = rgb_to_hsl(rgb[0], rgb[1], rgb[2]);
    key = pixel_data_to_key(hsl);
    if (key in palette) {
      new_hsl = palette[key];

      new_rgb = hsl_to_rgb(new_hsl[0], new_hsl[1], new_hsl[2]);
      rgb = hsl_to_rgb(hsl);
      image_data.data[i] = new_rgb[0];
      image_data.data[i + 1] = new_rgb[1];
      image_data.data[i + 2] = new_rgb[2];
    }
  }
  context.putImageData(image_data, 0, 0);
}


function draw(img) {


  var canvas = document.getElementById('canvas');
  var context = canvas.getContext('2d');
  context.drawImage(img, 0, 0, canvas.width, canvas.height);
  img.style.display = 'none';
  var image_data = context.getImageData(0, 0, canvas.width, canvas.height);
  var data = image_data.data;


  context.drawImage(target_image, 0, 0, canvas.width, canvas.height);
  data = context.getImageData(0, 0, canvas.width, canvas.height).data;

  original_pixels = [];
  for (i = 0; i < data.length; i += 4) {
    rgb = data.slice(i, i + 3);
    hsl = rgb_to_hsl(rgb[0], rgb[1], rgb[2]);
    original_pixels.push(hsl);
  }

  group_headers = [];
  groups = {};
  for (i = 0; i < original_pixels.length; i += 1) {
    if (group_headers.length == 0) {
      group_headers.push(original_pixels[i]);
    }
    group_found = false;
    for (j = 0; j < group_headers.length; j += 1) {
      // if a similar color was already observed
      if (color_distance(original_pixels[i], group_headers[j]) < 0.3) {
        group_found = true;
        if (!(pixel_data_to_key(original_pixels[i]) in groups)) {
          groups[pixel_data_to_key(original_pixels[i])] = group_headers[j];
        }
      }
      if (group_found) {
        break;
      }
    }
    if (!group_found) {
      if (group_headers.indexOf(original_pixels[i]) == -1) {
        group_headers.push(original_pixels[i]);
      }
      if (!(pixel_data_to_key(original_pixels[i]) in groups)) {
        groups[pixel_data_to_key(original_pixels[i])] = original_pixels[i];
      }
    }
  }
  posterize(context, image_data, groups)
}


var target_image = new Image();
target_image.crossOrigin = "";
target_image.onload = function() {
  draw(target_image)
};
target_image.src = "http://i.imgur.com/zRzdADA.jpg";

canvas {
  width: 300px;
  height: 200px;
}

<canvas id="canvas"></canvas>

这篇关于在图像中找到相似颜色的区域的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆