PHP Conference Japan 2024

imagecolorclosest

(PHP 4, PHP 5, PHP 7, PHP 8)

imagecolorclosest获取与指定颜色最接近的颜色的索引值

说明

imagecolorclosest(
    GdImage $image,
    int $red,
    int $green,
    int $blue
): int

返回图像调色板中与指定 RGB 值“最接近”的颜色的索引值。

目标颜色与调色板中每个颜色之间的“距离”的计算,可以理解为 RGB 值表示的是三维空间中的一个点。

如果图像是从文件创建的,则只会解析图像中使用的颜色。仅存在于调色板中的颜色不会被解析。

参数

image

一个由图像创建函数(例如 imagecreatetruecolor())返回的 GdImage 对象。

red

红色成分的值。

green

绿色成分的值。

blue

蓝色成分的值。

颜色参数是介于 0 和 255 之间的整数,或者是介于 0x00 和 0xFF 之间的十六进制数。

返回值

返回图像调色板中与指定颜色最接近的颜色的索引值。

更新日志

版本 说明
8.0.0 image 现在需要一个 GdImage 实例;之前是一个有效的 gd resource

示例

示例 #1 在图像中搜索一组颜色

<?php
// 从一个图像开始,并将其转换为基于调色板的图像
$im = imagecreatefrompng('figures/imagecolorclosest.png');
imagetruecolortopalette($im, false, 255);

// 搜索颜色 (RGB)
$colors = array(
array(
254, 145, 154),
array(
153, 145, 188),
array(
153, 90, 145),
array(
255, 137, 92)
);

// 循环遍历每次搜索,并在调色板中找到最接近的颜色。
// 返回搜索编号、搜索的 RGB 值和转换后的 RGB 匹配值
foreach($colors as $id => $rgb)
{
$result = imagecolorclosest($im, $rgb[0], $rgb[1], $rgb[2]);
$result = imagecolorsforindex($im, $result);
$result = "({$result['red']}, {$result['green']}, {$result['blue']})";

echo
"#$id: 搜索 ($rgb[0], $rgb[1], $rgb[2]); 最接近的匹配: $result.\n";
}

imagedestroy($im);
?>

以上示例的输出类似于:

#0: Search (254, 145, 154); Closest match: (252, 150, 148).
#1: Search (153, 145, 188); Closest match: (148, 150, 196).
#2: Search (153, 90, 145); Closest match: (148, 90, 156).
#3: Search (255, 137, 92); Closest match: (252, 150, 92).

参见

添加一个注释

用户贡献的注释 4 个注释

4
info at codeworx dot ch
13 年前
这是一个比较两个十六进制颜色相似度的函数。如果你想检测肉眼无法分辨的颜色差异,这将非常有用。它返回一个布尔值:如果颜色彼此相似(在容差范围内),则返回 TRUE;如果颜色差异足够大,则返回 FALSE。
我测试了一些颜色,得出了 35 的容差值(rgb 值 - 应该在 0 到 255 之间),但你可以通过向函数传递第三个参数来更改该容差值。

<?php
function compareColors ($col1, $col2, $tolerance=35) {
$col1Rgb = array(
"r" => hexdec(substr($col1, 0, 2)),
"g" => hexdec(substr($col1, 2, 2)),
"b" => hexdec(substr($col1, 4, 2))
);
$col2Rgb = array(
"r" => hexdec(substr($col2, 0, 2)),
"g" => hexdec(substr($col2, 2, 2)),
"b" => hexdec(substr($col2, 4, 2))
);
return (
$col1Rgb['r'] >= $col2Rgb['r'] - $tolerance && $col1Rgb['r'] <= $col2Rgb['r'] + $tolerance) && ($col1Rgb['g'] >= $col2Rgb['g'] - $tolerance && $col1Rgb['g'] <= $col2Rgb['g'] + $tolerance) && ($col1Rgb['b'] >= $col2Rgb['b'] - $tolerance && $col1Rgb['b'] <= $col2Rgb['b'] + $tolerance);
}
?>
1
Hayley Watson
7年前 (7 years ago)
RGB 并不是衡量两种颜色之间距离的最佳选择,因为它忽略了一些事实,例如,我们将深绿色和浅绿色都视为“绿色”(#000000 和 #7f7f7f 之间的 RGB 距离与 #000000 和 #5443c0 之间的距离相同 - #5443c0是一种稍微变暗的板岩蓝)。(RGB space isn't the best choice for measuring the distance between two colours, since it ignores, for example, the fact that we count both dark green and light green as "green" (the RGB distance between #000000 and #7f7f7f is the same as the distance between #000000 and #5443c0 - a slightly darkened SlateBlue).)

Lab 颜色空间是一种更符合颜色感知方式的颜色空间,它根据颜色的明暗、红/绿和黄/蓝来测量颜色。(还有更好的模型,但它们的计算量更大。)(A better choice of colour space that conforms better to how colours are perceived is the so-called Lab space, which measures colours according to how light/dark, red/green, and yellow/blue they are. (There are still better models, but they come at the expense of increased computation.))

<?php

function warp1($c)
{
if(
$c > 10.3148)
{
return
pow((561 + 40*$c)/10761, 2.4);
}
else
{
return
$c / 3294.6;
}
}
function
warp2($c)
{
if(
$c > 0.008856)
{
return
pow($c, 1/3);
}
else
{
return
7.787 * $c + 4/29;
}
}
function
rgb2lab($rgb)
{
[
$red, $green, $blue] = array_map('warp1', $rgb);

$x = warp2($red * 0.4339 + $green * 0.3762 + $blue * 0.1899);
$y = warp2($red * 0.2126 + $green * 0.7152 + $blue * 0.0722);
$z = warp2($red * 0.0178 + $green * 0.1098 + $blue * 0.8730);

$l = 116*$y - 16;
$a = 500 * ($x - $y);
$b = 200 * ($y - $z);

return
array_map('intval', [$l, $a, $b]);
}

function
generate_palette_from_image($image)
{
$pal = [];
$width = imagesx($image);
$height = imagesy($image);
for(
$x = 0; $x < $width; ++$x)
{
for(
$y = 0; $y < $height; ++$y)
{
$pal[] = imagecolorat($image, $x, $y);
}
}
return
array_map(function($col)use($image)
{
$rgba = imagecolorsforindex($image, $col);
return [
$rgba['red'], $rgba['green'], $rgba['blue']];
},
array_unique($pal));
}

function
closest_rgb_in_palette($rgb, $palette)
{
// 如果调色板中存在完全相同的颜色,则快速返回。
if(($idx = array_search($rgb, $palette)) !== false)
{
return
$idx;
}
[
$tl, $ta, $tb] = rgb2lab($rgb);
$dists = array_map(function($plab)use($tl, $ta, $tb)
{
[
$pl, $pa, $pb] = $plab;
$dl = $pl - $tl;
$da = $pa - $ta;
$db = $pa - $tb;
return
$dl * $dl + $da * $da + $db * $db;
},
array_map('rgb2lab', $palette));
return
array_search(min($dists), $dists);
}

function
closest_rgb_in_image($rgb, $image)
{
$palette = generate_palette_from_image($image);
return
$palette[closest_rgb_in_palette($rgb, $palette)];
}

$lena = imagecreatefrompng('lena.png');
$red = closest_rgb_in_image([255,0,0],$lena);
echo
join(' ', $red); // 228 71 82

?>

如果要将许多颜色匹配到一个调色板,则可能需要预先计算并重用 Lab 调色板,而不是像此处这样每次都重新生成。
-1
MagicalTux at FF dot st
19 年前
一种每次都能得到答案的方法

<?php
function imagegetcolor($im, $r, $g, $b) {
$c=imagecolorexact($im, $r, $g, $b);
if (
$c!=-1) return $c;
$c=imagecolorallocate($im, $r, $g, $b);
if (
$c!=-1) return $c;
return
imagecolorclosest($im, $r, $g, $b);
}
?>

如果在图像中找到 *完全* 匹配的颜色,则返回该颜色。如果没有完全匹配的颜色,则尝试分配颜色。如果无法分配,则返回图像中最接近的颜色。
-1
Vikrant Korde <vakorde at hotmail dot com>
21 年前
当您处理先前存在的图像(如 .png、.jpg 等)时,此函数非常有用。您可以使用此函数在图像上写入文本。

对我来说,函数 imagecolorallocate() 返回值 -1。经过大量的研究和网站搜索后,我发现了一个使用 imagecolorclosest() 的函数。这解决了我在图像上使用自定义颜色写入文本的问题。

实际上,以前它是在图像上写入的,但颜色不明显。它使用了与背景图像相同的颜色。

以下代码段对我来说没问题。

header ("Content-type: image/jpeg");
$im = imagecreatefromjpeg("BlankButton.jpg");
$white = imageColorClosest($im, 255,255,255);
// 这适用于 TTF 字体
imagettftext ($im, 20, 0, 16, 30, $white, "/usr/X11R6/lib/X11/fonts/TTF/luximb.ttf", "Vikrant");

//这是普通字体
imagestring($im, 4, 0,0,"Korde", $white);
imagejpeg($im,"",150);
imagedestroy ($im);
To Top