imageconvolution

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

imageconvolution使用系数和偏移量应用 3x3 卷积矩阵

描述

imageconvolution(
    GdImage $image,
    array $matrix,
    float $divisor,
    float $offset
): bool

使用给定的系数和偏移量,将卷积矩阵应用于图像。

参数

image

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

matrix

一个 3x3 矩阵:一个包含三个包含三个浮点数的数组的数组。

divisor

卷积结果的除数,用于归一化。

offset

颜色偏移。

返回值

如果成功则返回 true,失败则返回 false

变更日志

版本 描述
8.0.0 image 现在期望一个 GdImage 实例;以前,期望一个有效的 gd resource

示例

示例 #1 对 PHP.net 徽标进行浮雕处理

<?php
$image
= imagecreatefromgif('https://php.net/images/php.gif');

$emboss = array(array(2, 0, 0), array(0, -1, 0), array(0, 0, -1));
imageconvolution($image, $emboss, 1, 127);

header('Content-Type: image/png');
imagepng($image, null, 9);
?>

上面的示例将输出

Output of example : Embossing the PHP.net logo

示例 #2 高斯模糊

<?php
$image
= imagecreatetruecolor(180,40);

// 编写文本并在图像上应用高斯模糊
imagestring($image, 5, 10, 8, 'Gaussian Blur Text', 0x00ff00);
$gaussian = array(array(1.0, 2.0, 1.0), array(2.0, 4.0, 2.0), array(1.0, 2.0, 1.0));
imageconvolution($image, $gaussian, 16, 0);

// 重新编写文本以进行比较
imagestring($image, 5, 10, 18, 'Gaussian Blur Text', 0x00ff00);

header('Content-Type: image/png');
imagepng($image, null, 9);
?>

上面的示例将输出

Output of example : Gaussian blur

参见

添加笔记

用户贡献的笔记 10 个笔记

12
magilvia
13 年前
这里有一个用于缩略图创建的良好锐化设置

<?php
$sharpenMatrix
= array
(
array(-
1.2, -1, -1.2),
array(-
1, 20, -1),
array(-
1.2, -1, -1.2)
);

// 计算锐化除数
$divisor = array_sum(array_map('array_sum', $sharpenMatrix));

$offset = 0;

// 应用矩阵
imageconvolution($img, $sharpenMatrix, $divisor, $offset);
?>
3
fabien dot snauwaert at gmail dot com
14 年前
归一化对于保持图像平衡是必要的(否则任何滤镜都可能很快使图像几乎完全变黑或变白)。

这里有一个简短易用的类,可以自动处理归一化并使 3x3 矩阵的输入更容易

代码遵循用于与 imageconvolution() 函数一起使用的“包含三个数组的数组”语法,并自动计算用于归一化的必要除数。

<?php

class ConvolutionFilter {
public
$matrix;
public
$div;

public function
computeDiv() {
$this->div = array_sum ($this->matrix[0]) + array_sum ($this->matrix[1]) + array_sum ($this->matrix[2]);
}

function
__construct() {
$matrix = func_get_args();
$this->matrix = array( array($matrix[0], $matrix[1], $matrix[2]),
array(
$matrix[3], $matrix[4], $matrix[5]),
array(
$matrix[6], $matrix[7], $matrix[8])
);
$this->computeDiv();
}
}

?>

示例用法

<?php

$gaussianFilter
= new ConvolutionFilter( 1.0, 2.0, 1.0,
2.0, 3.0, 2.0,
1.0, 2.0, 1.0 );
imageconvolution($image, $gaussianFilter->matrix, $gaussianFilter->div, 0);

?>

一些常见的过滤器

<?php

$identityFilter
= new ConvolutionFilter( 0.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 0.0 );
$sharpenFilter = new ConvolutionFilter( 0.0, -1.0, 0.0,
-
1.0, 5.0, -1.0,
0.0, -1.0, 0.0 );
$edgeFilter = new ConvolutionFilter( 0.0, 1.0, 0.0,
1.0, -4.0, 1.0,
0.0, 1.0, 0.0 );
$findEdgesFilter = new ConvolutionFilter( -1.0, -1.0, -1.0,
-
2.0, 8.0, -1.0,
-
1.0, -1.0, -1.0 );

?>

记住,你可以使用 imagefilter() 来满足这些基本需求,但是当你想创建自己的过滤器时,上面的类会让你的工作更容易。
1
匿名
18 年前
下面的例子没有提供一个 3x3 的矩阵。正确的说,它是一个多维数组。

<?php
$matrix
= array( array( -1, -1, -1 ),
array( -
1, 16, -1 ),
array( -
1, -1, -1 ) );
?>
1
mlconnor at yahoo dot com
18 年前
我见过很多人想出各种方法来在矩形(比如图片)后面添加阴影。但我还没找到一个既快又符合 PHP 4 标准,而且看起来不错的。这是我昨晚想出来的一个。它接收一张图片,用背景色填充,并在指定坐标处创建模糊阴影,使用指定的颜色和距离偏移量。看起来很棒!

function blurRect(&$image, $distance, $rectX1, $rectY1, $rectX2, $rectY2, $shadowR, $shadowG, $shadowB, $backR, $backG, $backB) {

$potentialOverlap = ($distance * 2) * ($distance * 2);

$backgroundColor = imagecolorallocate($image, $backR, $backG, $backB);
$shadowColor = imagecolorallocate($image, $shadowR, $shadowG, $shadowB);

$imageWidth = imagesx($image);
$imageHeight = imagesy($image);

imageFilledRectangle($image, 0, 0, $imageWidth - 1, $imageHeight - 1, $backgroundColor);
imageFilledRectangle($image, $rectX1, $rectY1, $rectX2, $rectY2, $shadowColor);

for ( $pointX = $rectX1 - $distance; $pointX < $imageWidth; $pointX++ ) {
for ( $pointY = $rectY1 - $distance; $pointY < $imageHeight; $pointY++ ) {

if ( $pointX > $rectX1 + $distance &&
$pointX < $rectX2 - $distance &&
$pointY > $rectY1 + $distance &&
$pointY < $rectY2 - $distance ) {
$pointY = $rectY2 - $distance;
}

$boxX1 = $pointX - $distance;
$boxY1 = $pointY - $distance;
$boxX2 = $pointX + $distance;
$boxY2 = $pointY + $distance;

$xOverlap = max(0, min($boxX2, $rectX2) - max($boxX1, $rectX1));
$yOverlap = max(0, min($boxY2, $rectY2) - max($boxY1, $rectY1));

$totalOverlap = $xOverlap * $yOverlap;
$shadowPcnt = $totalOverlap / $potentialOverlap;
$backPcnt = 1.0 - $shadowPcnt;

$newR = $shadowR * $shadowPcnt + $backR * $backPcnt;
$newG = $shadowG * $shadowPcnt + $backG * $backPcnt;
$newB = $shadowB * $shadowPcnt + $backB * $backPcnt;

$newcol = imagecolorallocate($image, $newR, $newG, $newB);
imagesetpixel($image, $pointX, $pointY, $newcol);
}
}
}
1
timeshifting at gmail dot com
18 年前
矩阵可用于锐化、模糊、边缘检测等,类似于 Photoshop。

锐化示例

<?php

$sharpenMatrix
= array(-1,-1,-1,-1,16,-1,-1,-1,-1);
$divisor = 8;
$offset = 0;

imageconvolution($myImage, $sharpenMatrix, $divisor, $offset);

?>

下面是一些关于构建不同类型矩阵的信息。(如果你有 Photoshop(或 PSP、GIMP),你可以在 PHP 中应用它们之前先测试你的矩阵)

http://loriweb.pair.com/8udf-basics.html (涵盖模糊)
http://loriweb.pair.com/8udf-sharpen.html
http://loriweb.pair.com/8udf-edges.html
http://loriweb.pair.com/8udf-emboss.html
0
mgcclx at gmail dot com
17 年前
在没有捆绑 GD 库的 PHP 中,imageconvolution() 似乎并不存在。这种情况很少见,但确实会发生。这就是我用 PHP 重写 imageconvolution() 的原因。与下面的帖子相比,这个帖子使用了偏移量,速度提高了 30%。
因为它是用 PHP 编写的,所以它比捆绑版本慢 50 倍。
实际上,这是一个 GD 库中 gdimageconvolutaion() 的复制品,它不支持 imageconvolution() 拥有的数据验证功能。但我猜使用这个函数的人应该知道他们的东西。

脚本
<?php
// 只要需要使用 imageconvolution 时,就包含此文件...
// 你可以在你的项目中使用它,但请保留下面的评论 :)
// 非常适合任何图像处理库
// 作者:徐超(Mgccl) 2007 年 2 月 28 日
// www.webdevlogs.com
// V 1.0
if(!function_exists('imageconvolution')){
function
imageconvolution($src, $filter, $filter_div, $offset){
if (
$src==NULL) {
return
0;
}

$sx = imagesx($src);
$sy = imagesy($src);
$srcback = ImageCreateTrueColor ($sx, $sy);
ImageCopy($srcback, $src,0,0,0,0,$sx,$sy);

if(
$srcback==NULL){
return
0;
}

for (
$y=0; $y<$sy; ++$y){
for(
$x=0; $x<$sx; ++$x){
$new_r = $new_g = $new_b = 0;
$alpha = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_a = $alpha >> 24;

for (
$j=0; $j<3; ++$j) {
$yv = min(max($y - 1 + $j, 0), $sy - 1);
for (
$i=0; $i<3; ++$i) {
$pxl = array(min(max($x - 1 + $i, 0), $sx - 1), $yv);
$rgb = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_r += (($rgb >> 16) & 0xFF) * $filter[$j][$i];
$new_g += (($rgb >> 8) & 0xFF) * $filter[$j][$i];
$new_b += ($rgb & 0xFF) * $filter[$j][$i];
}
}

$new_r = ($new_r/$filter_div)+$offset;
$new_g = ($new_g/$filter_div)+$offset;
$new_b = ($new_b/$filter_div)+$offset;

$new_r = ($new_r > 255)? 255 : (($new_r < 0)? 0:$new_r);
$new_g = ($new_g > 255)? 255 : (($new_g < 0)? 0:$new_g);
$new_b = ($new_b > 255)? 255 : (($new_b < 0)? 0:$new_b);

$new_pxl = ImageColorAllocateAlpha($src, (int)$new_r, (int)$new_g, (int)$new_b, $new_a);
if (
$new_pxl == -1) {
$new_pxl = ImageColorClosestAlpha($src, (int)$new_r, (int)$new_g, (int)$new_b, $new_a);
}
if ((
$y >= 0) && ($y < $sy)) {
imagesetpixel($src, $x, $y, $new_pxl);
}
}
}
imagedestroy($srcback);
return
1;
}
}
?>
-1
phunction.sf.net
14 年前
你不需要任何自定义函数来计算 $matrix 的 $divisor,使用 array_map() 和 array_sum() 就足够了

<?php

$matrix
= array
(
array(-
1, -1, -1),
array(-
1, 16, -1),
array(-
1, -1, -1),
);

$divisor = array_sum(array_map('array_sum', $matrix)); // 8

?>
-1
Jase
16 年前
下面的评论是一个非常好的解决方法

然而,当我将错误报告设置为 E_ALL 时,php 向我抛出了很多警告

这可以通过一行代码来避免,并且不会对函数的其余部分产生影响(据我所知)

<?php
// 只要需要使用图像卷积,就包含此文件...
// 你可以在项目中使用,但请保留下面的注释 :)
// 适用于任何图像处理库
// 作者:徐超 (Mgccl) 2007年2月28日
// www.webdevlogs.com
// V 1.0
if(!function_exists('imageconvolution')){
function
imageconvolution($src, $filter, $filter_div, $offset){
if (
$src==NULL) {
return
0;
}

$sx = imagesx($src);
$sy = imagesy($src);
$srcback = ImageCreateTrueColor ($sx, $sy);
ImageCopy($srcback, $src,0,0,0,0,$sx,$sy);

if(
$srcback==NULL){
return
0;
}

# 此处修复
# $pxl 数组是问题所在,因此只需将其设置为非常低的值
$pxl = array(1,1);
# 这个小修复对我有用,因为未定义的数组抛出了错误

for ($y=0; $y<$sy; ++$y){
for(
$x=0; $x<$sx; ++$x){
$new_r = $new_g = $new_b = 0;
$alpha = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_a = $alpha >> 24;

for (
$j=0; $j<3; ++$j) {
$yv = min(max($y - 1 + $j, 0), $sy - 1);
for (
$i=0; $i<3; ++$i) {
$pxl = array(min(max($x - 1 + $i, 0), $sx - 1), $yv);
$rgb = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_r += (($rgb >> 16) & 0xFF) * $filter[$j][$i];
$new_g += (($rgb >> 8) & 0xFF) * $filter[$j][$i];
$new_b += ($rgb & 0xFF) * $filter[$j][$i];
}
}

$new_r = ($new_r/$filter_div)+$offset;
$new_g = ($new_g/$filter_div)+$offset;
$new_b = ($new_b/$filter_div)+$offset;

$new_r = ($new_r > 255)? 255 : (($new_r < 0)? 0:$new_r);
$new_g = ($new_g > 255)? 255 : (($new_g < 0)? 0:$new_g);
$new_b = ($new_b > 255)? 255 : (($new_b < 0)? 0:$new_b);

$new_pxl = ImageColorAllocateAlpha($src, (int)$new_r, (int)$new_g, (int)$new_b, $new_a);
if (
$new_pxl == -1) {
$new_pxl = ImageColorClosestAlpha($src, (int)$new_r, (int)$new_g, (int)$new_b, $new_a);
}
if ((
$y >= 0) && ($y < $sy)) {
imagesetpixel($src, $x, $y, $new_pxl);
}
}
}
imagedestroy($srcback);
return
1;
}
}
?>
-1
interghost at crovortex dot com
18 年前
针对 PHP 版本 <5.1 的此函数的实现
<?php
if(!function_exists("imageconvolution"))
{
function
imageconvolution(&$img,$mat,$div,$off)
{
if(!
imageistruecolor($img) || !is_array($mat) || count($mat)!=3 || count($mat[0])!=3 || count($mat[1])!=3 || count($mat[2])!=3) return FALSE;
unset(
$bojainfo);
for(
$nx=0;$nx<imagesx($img)-1;$nx++)
{
for(
$ny=0;$ny<imagesy($img)-1;$ny++)
{
$rgb=imagecolorat($img,$nx,$ny);
$bojainfo[$nx][$ny][r]=($rgb>>16)&0xFF;
$bojainfo[$nx][$ny][g]=($rgb>>8)&0xFF;
$bojainfo[$nx][$ny][b]=$rgb&0xFF;
}
}
for(
$nx=1;$nx<imagesx($img)-1;$nx++)
{
for(
$ny=1;$ny<imagesy($img)-1;$ny++)
{
$nr=$mat[0][0]*$bojainfo[$nx-1][$ny-1][r] + $mat[0][1]*$bojainfo[$nx][$ny-1][r] + $mat[0][2]*$bojainfo[$nx+1][$ny-1][r] + $mat[1][0]*$bojainfo[$nx-1][$ny][r] + $mat[1][1]*$bojainfo[$nx][$ny][r] + $mat[1][2]*$bojainfo[$nx+1][$ny][r] + $mat[2][0]*$bojainfo[$nx-1][$ny+1][r] + $mat[2][1]*$bojainfo[$nx][$ny+1][r] + $mat[2][2]*$bojainfo[$nx+1][$ny+1][r];
$nr=intval(round($nr/$div));
if(
$nr<0) $nr=0;
elseif(
$nr>255) $nr=255;
$ng=$mat[0][0]*$bojainfo[$nx-1][$ny-1][g] + $mat[0][1]*$bojainfo[$nx][$ny-1][g] + $mat[0][2]*$bojainfo[$nx+1][$ny-1][g] + $mat[1][0]*$bojainfo[$nx-1][$ny][g] + $mat[1][1]*$bojainfo[$nx][$ny][g] + $mat[1][2]*$bojainfo[$nx+1][$ny][g] + $mat[2][0]*$bojainfo[$nx-1][$ny+1][g] + $mat[2][1]*$bojainfo[$nx][$ny+1][g] + $mat[2][2]*$bojainfo[$nx+1][$ny+1][g];
$ng=intval(round($ng/$div));
if(
$ng<0) $ng=0;
elseif(
$ng>255) $ng=255;
$nb=$mat[0][0]*$bojainfo[$nx-1][$ny-1][b] + $mat[0][1]*$bojainfo[$nx][$ny-1][b] + $mat[0][2]*$bojainfo[$nx+1][$ny-1][b] + $mat[1][0]*$bojainfo[$nx-1][$ny][b] + $mat[1][1]*$bojainfo[$nx][$ny][b] + $mat[1][2]*$bojainfo[$nx+1][$ny][b] + $mat[2][0]*$bojainfo[$nx-1][$ny+1][b] + $mat[2][1]*$bojainfo[$nx][$ny+1][b] + $mat[2][2]*$bojainfo[$nx+1][$ny+1][b];
$nb=intval(round($nb/$div));
if(
$nb<0) $nb=0;
elseif(
$nb>255) $nb=255;
$nrgb=($nr<<16)+($ng<<8)+$nb;
if(!
imagesetpixel($img,$nx,$ny,$nrgb)) return FALSE;
}
}
return
TRUE;
}
}
?>

它有点慢,所以我不推荐使用大图像,而且偏移量也没有实现(不知道它应该做什么)
-2
dyer85 at gmail dot com
18 年前
我花了一段时间,但感谢 PHP 文档页面上的一些用户注释,我找到了一种动态计算除数的方法。

我在 Win32 上使用 PHP 5.1.0b2 和捆绑的 GD 库。当我尝试使用 imageconvolution 函数时,无论是正常使用还是通过以下函数,生成的图像(我只尝试了 JPEG 和 GIF)总是太亮,即使除数使矩阵总和等于 1。唯一能降低亮度的方法是使 offset 参数变得过大。因此,我不确定这是否会影响其他人。

以下是带有示例的函数

<?php
$im
= imagecreatefromjpeg('path/to/pic.jpg');
$matrix = array( array(5,5,5),
array(
5,15,5),
array(
5,5,5) );
makeFilter($im, $matrix);

header ( 'Content-Type: image/jpeg' );
imagejpeg($im);
imagedestroy($im);

/**
* 函数
*/
// 将 3X3 数组矩阵展平,以便获取所有值的总和
function array_flatten($array) {
(array)
$tempArray = array();

foreach (
$array as $value ) {
if (
is_array($value) ) {
$tempArray = array_merge($tempArray, array_flatten($value));
} else {
$tempArray[] = $value;
}
}

return
$tempArray;
}

// 动态创建除数值,并传递偏移量
function makeFilter($resource, $matrix, $offset=1.0) {
global $
$resource;
(float)
$divisor = array_sum(array_flatten($matrix));
return
imageconvolution($resource, $matrix, $divisor, $offset) ? true : false;
}
?>
To Top