GD and Image 函数
在线手册:中文  英文

imageconvolution

(PHP 5 >= 5.1.0)

imageconvolution用系数 div 和 offset 申请一个 3x3 的卷积矩阵

说明

bool imageconvolution ( resource $image , array $matrix , float $div , float $offset )

Applies a convolution matrix on the image, using the given coefficient and offset.

参数

image

由图象创建函数(例如 imagecreatetruecolor())返回的图象资源。

matrix

A 3x3 matrix: an array of three arrays of three floats.

div

The divisor of the result of the convolution, used for normalization.

offset

Color offset.

返回值

成功时返回 TRUE, 或者在失败时返回 FALSE

范例

Example #1 Embossing the PHP.net logo

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

$emboss = array(array(200), array(0, -10), array(00, -1));
imageconvolution($image$emboss1127);

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

以上例程会输出:

Output of example : Embossing the PHP.net logo

Example #2 Gaussian blur

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

// Writes the text and apply a gaussian blur on the image
imagestring($image5108'Gaussian Blur Text'0x00ff00);
$gaussian = array(array(1.02.01.0), array(2.04.02.0), array(1.02.01.0));
imageconvolution($image$gaussian160);

// Rewrites the text for comparison
imagestring($image51018'Gaussian Blur Text'0x00ff00);

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

以上例程会输出:

Output of example : Gaussian blur

注释

Note: 此函数仅在与 GD 库捆绑编译的 PHP 版本中可用。

参见


GD and Image 函数
在线手册:中文  英文

用户评论:

magilvia (2011-05-17 01:36:14)

Here's a good sharpen setting for thumbnail creation:

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

            
// calculate the sharpen divisor
            
$divisor array_sum(array_map('array_sum'$sharpenMatrix));            

            
$offset 0;
            
            
// apply the matrix
            
imageconvolution($img$sharpenMatrix$divisor$offset);
?>

phunction.sf.net (2010-05-15 21:20:21)

You don't need any custom function to calculate the $divisor of the $matrix, using array_map() and array_sum() does the trick:

<?php

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

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

?>

fabien dot snauwaert at gmail dot com (2010-03-07 10:44:09)

Normalization is necessary to keep the image balanced (else any filter may quickly turn the image almost completely black or white).

Here is a short, easy-to-use, class to handle normalization automatically and make for easier input of the 3x3 matrix:

The code respects the "array of three arrays" syntax for use with the imageconvolution() function and automatically calculates the necesarry divisor for normalization.

<?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();
    }
}

?>

Example usage:

<?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->div0);

?>

Some common filters:

<?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        );

?>

Remember you can use imagefilter() for such basic needs but the above class will make it easier for you when you want to create your own filters.

php at pulseforce dot com (2009-01-02 15:27:19)

I forgot mention the easiest format of all:

<?php

$aFilter 
convFilter("
    2 0 0 0 -1 0 0 0 -1
"
);

?>

There's nothing nicer or quicker than just typing out the values and hitting space between each! ;-) Enjoy!

php at pulseforce dot com (2009-01-02 15:04:45)

Here is something that you will find extremely handy while beta testing your convolution filters.

It's very time consuming to have something like:
$aFilter = array(
  array(-1, 2, -1),
  array(2, 4, 2),
  array(-1, 2, -1)
);

Because every time you're making a change you have to jump around a lot, and are forced to be careful with your edits to avoid destroying the array format (such as accidentally deleting a parenthesis or comma). That's not fun at all and very counter productive. Wouldn't it be good if you could just type the matrix out in text form and separate the entries with either spaces or tabs or newlines? Ie any of the following:

-1 2 -1
2 4 2
-1 2 -1

or

-1
2
-1
2
4
2
-1
2
-1

Well, now you can! I'd like to emphasis that you should only use this function for development purposes, while trying out different convolution matrices! And without further ado:

<?php

function convFilter($saFilter)
{
    
$aParts preg_split('/\s+/s'$saFilter, -1PREG_SPLIT_NO_EMPTY);
    if (
count($aParts) != 9) { return false; }
    
$aMatrix array_chunk($aParts3);
    return 
$aMatrix;
}

// Usage:

$aFilter convFilter("
    1.0    2.0    1.0
    2.0    4.0    2.0
    1.0    2.0    1.0
"
);
imageconvolution($rImg$aFilter160);

?>

Enjoy! You can now type your matrices out in any way you want (even floats), as long as any form of whitespace separates the various numbers. Once you are done testing, just type the matrix out as a normal array to save on processing time.

And please post your convolution filters if you come up with some useful ones so they can be implemented by others. ;-)

Jase (2007-09-13 15:53:11)

The comment below is an extremely good workaround

however, php did throw lots of warnings at me when i had error reporting set to E_ALL

this can be avoided with one line of code and no impact (as i can see) to the rest of the function

<?php
//include this file whenever you have to use imageconvolution...
//you can use in your project, but keep the comment below :)
//great for any image manipulation library
//Made by Chao Xu(Mgccl) 2/28/07
//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;
    }
        
    
#FIX HERE
    #$pxl array was the problem so simply set it with very low values
    
$pxl = array(1,1);
    
#this little fix worked for me as the undefined array threw out errors

    
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 $j0), $sy 1);
                for (
$i=0$i<3; ++$i) {
                        
$pxl = array(min(max($x $i0), $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;
}
}
?>

mgcclx at gmail dot com (2007-02-28 19:55:25)

imageconvolution() does not appear in PHP with non-bundled GD libraries. It is a rare situation, but it still happens. That's why I wrote a replication of imageconvolution() in PHP. Compare to the post below, this one makes the use of offset and 30% faster.
Because it's written in PHP, it is 50 times slower than the bundled version.
Actually, this is a replication of gdimageconvolutaion() of GD library, it does not support data validating feature imageconvolution() have. But I guess people who uses this function knows their stuff.

THE SCRIPT:
<?php
//include this file whenever you have to use imageconvolution...
//you can use in your project, but keep the comment below :)
//great for any image manipulation library
//Made by Chao Xu(Mgccl) 2/28/07
//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 $j0), $sy 1);
                for (
$i=0$i<3; ++$i) {
                        
$pxl = array(min(max($x $i0), $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;
}
}
?>

interghost at crovortex dot com (2006-03-31 11:26:31)

an implementation of this function for PHP versions <5.1
<?php
if(!function_exists("imageconvolution"))
{
 function 
imageconvolution(&$img,$mat,$div,$off)
 {
   if(!
imageistruecolor($img) || !is_array($mat) || count($mat)!=|| count($mat[0])!=|| count($mat[1])!=|| 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;
  }
}
?>

it's a bit slowish so I wouldn't recommend big images, also offset is not implemented (don't know what it's suppose to do)

mlconnor at yahoo dot com (2006-03-21 09:00:46)

I've seen many people come up with ways to do a drop shadow behind a rectangle such as a picture. I haven't found one yet that was fast, PHP 4 complaint, and nice looking. Here is one I came up with last night. It takes an image, fills it with the background, and creates a blurred drop shadow at the specified coords using the colors and the distance offset specified. It looks great!!!
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);
}
}
}

dyer85 at gmail dot com (2006-01-07 02:24:06)

Took me a while, but thanks to a couple of the user notes on the array_values PHP documentation page, I was able to come up with a way to dynamically compute the divisor.

I'm using PHP 5.1.0b2 on Win32 with the bundled GD library. When I try and use the imageconvolution function, whether normally, or via the functions below, the resulting image (I've only tried JPEGs and GIFs), always comes out far too bright, even when the divisor makes matrix sum equal to 1. The only thing that would reduce the brightness was to make the offset argument ridiculously large. So, I'm not sure if this effects anyone else.

Here are the functions with an example:

<?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);

/**
 * functions
 */
// This flattens the 3X3 array matrix, so we can get the sum of all the values
function array_flatten($array) {
    (array)
$tempArray = array();

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

    return 
$tempArray;
}

// Creates the divisor value dynamically, and passes offset
function makeFilter($resource$matrix$offset=1.0) {
    global $
$resource;
    (float)
$divisor array_sum(array_flatten($matrix));
    return 
imageconvolution($resource$matrix$divisor$offset) ? true false;
}
?>

(2005-10-26 17:32:44)

The example below didn't provide a 3x3 matrix. Correctly, it's a multidimensional array.

<?php
    $matrix 
= array(    array( -1, -1, -),
                        array( -
116, -),
                        array( -
1, -1, -) );
?>

timeshifting at gmail dot com (2005-08-24 15:40:38)

Matrices can be used for sharpening, blurring, edge detection, etc, ala Photoshop.

A sharpening example:

<?php

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

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

?>

Below is some information on building different kinds of matrices. (If you have photoshop (or PSP, GIMP) you can test out your matrices before applying them in PHP)

http://loriweb.pair.com/8udf-basics.html (covers blurs)
http://loriweb.pair.com/8udf-sharpen.html
http://loriweb.pair.com/8udf-edges.html
http://loriweb.pair.com/8udf-emboss.html

易百教程