Meny

Unsharp Mask for PHP

When creating thumbnails in photo editing programs, it is a good idea to apply some kind of sharpening filter. I created this program to do the same with thumbnails created on the fly in PHP. Among other sites, the script has been implemented in the commercial forum software vBulletin. Feel free to copy it from the field below to use on your own website.

Test the parameters
See the effects on the image below.

Amount: (typically 50 - 200)
Radius: (typically 0.5 - 1)
Threshold: (typically 0 - 5)



Original

Sharpened image



More testshots (click to test):

Explanation: See the heading of the script itself, below.
Setup: Copy the following code and paste it into your image editing script.
Requirements: The phpUnsharpMask script requires php version 4.0.6 or higher and Thomas Boutell's gd library version 2.0 or higher. From php version 4.3.1 gd is included.
Last modified: July 31, 2007
<?php

/*

New: 
- In version 2.1 (February 26 2007) Tom Bishop has done some important speed enhancements.
- From version 2 (July 17 2006) the script uses the imageconvolution function in PHP 
version >= 5.1, which improves the performance considerably.


Unsharp masking is a traditional darkroom technique that has proven very suitable for 
digital imaging. The principle of unsharp masking is to create a blurred copy of the image
and compare it to the underlying original. The difference in colour values
between the two images is greatest for the pixels near sharp edges. When this 
difference is subtracted from the original image, the edges will be
accentuated. 

The Amount parameter simply says how much of the effect you want. 100 is 'normal'.
Radius is the radius of the blurring circle of the mask. 'Threshold' is the least
difference in colour values that is allowed between the original and the mask. In practice
this means that low-contrast areas of the picture are left unrendered whereas edges
are treated normally. This is good for pictures of e.g. skin or blue skies.

Any suggenstions for improvement of the algorithm, expecially regarding the speed
and the roundoff errors in the Gaussian blur process, are welcome.

*/

function UnsharpMask($img$amount$radius$threshold)    { 

////////////////////////////////////////////////////////////////////////////////////////////////  
////  
////                  Unsharp Mask for PHP - version 2.1.1  
////  
////    Unsharp mask algorithm by Torstein Hønsi 2003-07.  
////             thoensi_at_netcom_dot_no.  
////               Please leave this notice.  
////  
///////////////////////////////////////////////////////////////////////////////////////////////  



    // $img is an image that is already created within php using 
    // imgcreatetruecolor. No url! $img must be a truecolor image. 

    // Attempt to calibrate the parameters to Photoshop: 
    
if ($amount 500)    $amount 500
    
$amount $amount 0.016
    if (
$radius 50)    $radius 50
    
$radius $radius 2
    if (
$threshold 255)    $threshold 255
     
    
$radius abs(round($radius));     // Only integers make sense. 
    
if ($radius == 0) { 
        return 
$imgimagedestroy($img); break;        } 
    
$w imagesx($img); $h imagesy($img); 
    
$imgCanvas imagecreatetruecolor($w$h); 
    
$imgBlur imagecreatetruecolor($w$h); 
     

    
// Gaussian blur matrix: 
    //                         
    //    1    2    1         
    //    2    4    2         
    //    1    2    1         
    //                         
    ////////////////////////////////////////////////// 
         

    
if (function_exists('imageconvolution')) { // PHP >= 5.1  
            
$matrix = array(  
            array( 
12),  
            array( 
24),  
            array( 
12)  
        );  
        
imagecopy ($imgBlur$img0000$w$h); 
        
imageconvolution($imgBlur$matrix160);  
    }  
    else {  

    
// Move copies of the image around one pixel at the time and merge them with weight 
    // according to the matrix. The same matrix is simply repeated for higher radii. 
        
for ($i 0$i $radius$i++)    { 
            
imagecopy ($imgBlur$img0010$w 1$h); // left 
            
imagecopymerge ($imgBlur$img1000$w$h50); // right 
            
imagecopymerge ($imgBlur$img0000$w$h50); // center 
            
imagecopy ($imgCanvas$imgBlur0000$w$h); 

            
imagecopymerge ($imgBlur$imgCanvas0001$w$h 133.33333 ); // up 
            
imagecopymerge ($imgBlur$imgCanvas0100$w$h25); // down 
        

    } 

    if(
$threshold>0){ 
        
// Calculate the difference between the blurred pixels and the original 
        // and set the pixels 
        
for ($x 0$x $w-1$x++)    { // each row
            
for ($y 0$y $h$y++)    { // each pixel 
                     
                
$rgbOrig ImageColorAt($img$x$y); 
                
$rOrig = (($rgbOrig >> 16) & 0xFF); 
                
$gOrig = (($rgbOrig >> 8) & 0xFF); 
                
$bOrig = ($rgbOrig 0xFF); 
                 
                
$rgbBlur ImageColorAt($imgBlur$x$y); 
                 
                
$rBlur = (($rgbBlur >> 16) & 0xFF); 
                
$gBlur = (($rgbBlur >> 8) & 0xFF); 
                
$bBlur = ($rgbBlur 0xFF); 
                 
                
// When the masked pixels differ less from the original 
                // than the threshold specifies, they are set to their original value. 
                
$rNew = (abs($rOrig $rBlur) >= $threshold)  
                    ? 
max(0min(255, ($amount * ($rOrig $rBlur)) + $rOrig))  
                    : 
$rOrig
                
$gNew = (abs($gOrig $gBlur) >= $threshold)  
                    ? 
max(0min(255, ($amount * ($gOrig $gBlur)) + $gOrig))  
                    : 
$gOrig
                
$bNew = (abs($bOrig $bBlur) >= $threshold)  
                    ? 
max(0min(255, ($amount * ($bOrig $bBlur)) + $bOrig))  
                    : 
$bOrig
                 
                 
                             
                if ((
$rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew)) { 
                        
$pixCol ImageColorAllocate($img$rNew$gNew$bNew); 
                        
ImageSetPixel($img$x$y$pixCol); 
                    } 
            } 
        } 
    } 
    else{ 
        for (
$x 0$x $w$x++)    { // each row 
            
for ($y 0$y $h$y++)    { // each pixel 
                
$rgbOrig ImageColorAt($img$x$y); 
                
$rOrig = (($rgbOrig >> 16) & 0xFF); 
                
$gOrig = (($rgbOrig >> 8) & 0xFF); 
                
$bOrig = ($rgbOrig 0xFF); 
                 
                
$rgbBlur ImageColorAt($imgBlur$x$y); 
                 
                
$rBlur = (($rgbBlur >> 16) & 0xFF); 
                
$gBlur = (($rgbBlur >> 8) & 0xFF); 
                
$bBlur = ($rgbBlur 0xFF); 
                 
                
$rNew = ($amount * ($rOrig $rBlur)) + $rOrig
                    if(
$rNew>255){$rNew=255;} 
                    elseif(
$rNew<0){$rNew=0;} 
                
$gNew = ($amount * ($gOrig $gBlur)) + $gOrig
                    if(
$gNew>255){$gNew=255;} 
                    elseif(
$gNew<0){$gNew=0;} 
                
$bNew = ($amount * ($bOrig $bBlur)) + $bOrig
                    if(
$bNew>255){$bNew=255;} 
                    elseif(
$bNew<0){$bNew=0;} 
                
$rgbNew = ($rNew << 16) + ($gNew <<8) + $bNew
                    
ImageSetPixel($img$x$y$rgbNew); 
            } 
        } 
    } 
    
imagedestroy($imgCanvas); 
    
imagedestroy($imgBlur); 
     
    return 
$img

}
?>
Torstein Hønsi .:. N-6893 Vik i Sogn, Norway .:. (+47) 41 61 18 68 .:. Indekssider: Foto | Gardar | Stølar
Valid XHTML 1.0 Strict