我不知道 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;
}
}