模拟PhotoShop的“颜色范围”算法

时间:2013-11-14 19:06:49

标签: algorithm image-processing colors reverse-engineering photoshop

我正在尝试使用在服务器上完成的自动过程替换在PhotoShop中完成的手动过程。目前在PhotoShop中,“颜色范围”工具用于使用“模糊”因子选择一系列颜色,并从黑色或白色开始,具体取决于过程的部分。

我的初始方法包括在L * a * b颜色空间中使用发光阈值以及候选颜色和黑/白之间的DE94。在这两种情况下,我选择了不应该选择的颜色和/或没有选择应该的颜色。

我的预感是我应该使用锥体而不是球体供我选择。

任何人都可以了解PhotoShop正在做什么以及我是否正朝着正确的方向前进?此外,如果有一个库可以做到这一点,那将是很棒的我现在用C语言写这个。

3 个答案:

答案 0 :(得分:5)

根据我在Photoshop中看到的,该算法可能类似于以下内容:

  1. 定义计算两种颜色的接近度的函数:例如,在颜色空间中使用欧几里德距离 - 即,使用Euclidean distance formula计算RGB空间中两个像素的颜色之间的距离。
  2. 接下来,使用fallof函数调整每个像素的强度, 例如Gaussian function。你可能需要调整一下 一些参数。澄清一下:你计算两个距离 RGB空间中的像素(不是2D像素坐标中的距离),和 然后将其输入到将提供结果的衰减函数中 介于0.0和1.0之间。将当前的所有颜色分量相乘 具有衰减函数结果的像素。这样做 图像的每个像素。
  3. 如果要添加效果的范围参数,只需使用 再次为每个像素提供相同的衰减函数,但这次给它喂它 所选像素与电流之间的欧几里德距离 像素在2D空间中的像素(像素之间的距离) 图像上的坐标)。
  4. 如果您只想选择某些像素,则可以将衰减值存储在double的矩阵中,而不是直接在图像中的像素上应用效果,范围为0.0到1.0。然后,选择一个阈值,在该阈值之上,您将选择给定的像素。

    例如,如果坐标(x,y)处的像素的步骤2.得到0.8而步骤3.得到0.5,则坐标x和y的矩阵元素的值应为0.8*0.5=0.4 。如果您选择的选择阈值低于0.4,则选择像素(x,y),否则,您将不会。

答案 1 :(得分:3)

我不知道Photoshop是如何做到的,但这是一个简单的RGB作为XYZ 3d矢量方法:

rDelta = pixel.r - color.r
gDelta = pixel.g - color.g
bDelta = pixel.b - color.b
fuzziness = 0.1  // anything 0 to 1.0
maxDistance = fuzziness * 441 // max distance, black -> white

distance = Math.sqrt(rDelta * rDelta + gDelta * gDelta + bDelta * bDelta)

if (distance < maxDistance) includePixel()
else dontIncludePixel()

这是来自gimp源的pixel_difference函数:

https://github.com/GNOME/gimp/blob/125cf2a2a3e1e85172af25871a2cda3638292fdb/app/core/gimpimage-contiguous-region.c#L290

static gfloat
pixel_difference (const gfloat        *col1,
                  const gfloat        *col2,
                  gboolean             antialias,
                  gfloat               threshold,
                  gint                 n_components,
                  gboolean             has_alpha,
                  gboolean             select_transparent,
                  GimpSelectCriterion  select_criterion)
{
  gfloat max = 0.0;

  /*  if there is an alpha channel, never select transparent regions  */
  if (! select_transparent && has_alpha && col2[n_components - 1] == 0.0)
    return 0.0;

  if (select_transparent && has_alpha)
    {
      max = fabs (col1[n_components - 1] - col2[n_components - 1]);
    }
  else
    {
      gfloat diff;
      gint   b;

      if (has_alpha)
        n_components--;

      switch (select_criterion)
        {
        case GIMP_SELECT_CRITERION_COMPOSITE:
          for (b = 0; b < n_components; b++)
            {
              diff = fabs (col1[b] - col2[b]);
              if (diff > max)
                max = diff;
            }
          break;

        case GIMP_SELECT_CRITERION_R:
          max = fabs (col1[0] - col2[0]);
          break;

        case GIMP_SELECT_CRITERION_G:
          max = fabs (col1[1] - col2[1]);
          break;

        case GIMP_SELECT_CRITERION_B:
          max = fabs (col1[2] - col2[2]);
          break;

        case GIMP_SELECT_CRITERION_H:
          {
            /* wrap around candidates for the actual distance */
            gfloat dist1 = fabs (col1[0] - col2[0]);
            gfloat dist2 = fabs (col1[0] - 1.0 - col2[0]);
            gfloat dist3 = fabs (col1[0] - col2[0] + 1.0);

            max = MIN (dist1, dist2);
            if (max > dist3)
              max = dist3;
          }
          break;

        case GIMP_SELECT_CRITERION_S:
          max = fabs (col1[1] - col2[1]);
          break;

        case GIMP_SELECT_CRITERION_V:
          max = fabs (col1[2] - col2[2]);
          break;
        }
    }

  if (antialias && threshold > 0.0)
    {
      gfloat aa = 1.5 - (max / threshold);

      if (aa <= 0.0)
        return 0.0;
      else if (aa < 0.5)
        return aa * 2.0;
      else
        return 1.0;
    }
  else
    {
      if (max > threshold)
        return 0.0;
      else
        return 1.0;
    }
}

答案 2 :(得分:2)

我受过教育的猜测是它正在使用HSL颜色空间,而模糊性是一个参数,它在明亮的窗口中选择具有特定色调和饱和度的所有颜色(基于this)。

现在选择可能只是在进行阈值计算,找到该窗口内的所有内容(这将是颜色空间中的一个非常小的区域)。但是,它也可能正在进行统计距离计算。如果颜色样本实际上很小的颜色采样窗口,您可以计算颜色方差,并使用Mahalanobis距离计算和阈值。

同样,这只是猜想,但也许它会帮助你的思考过程。

最后,虽然这个库没有直接实现这样的东西,但OpenCV有许多图像处理工具可以使实现更容易。