Intelligent Thumbnails
Posted: Sat Mar 29, 2008 1:31 pm
I was a little sick of doing proper work this afternoon so I decided to spend an hour messing about with GD for the first time in almost a year.
It's faaaaaaaaar from being production code yet, but I've created a script for making "intelligent thumbnails". Basically, it'll take an image and make a thumbnail from the more important part of the picture. This is just a really early version at the moment, but it's a fun thing to play with.
The code:
NOTE: CURRENTLY THE CODE JUST MARKS THE AREA THE THUMBNAIL WOULD USE, IT DOESN'T MAKE THE THUMBNAIL.
Examples of what it does:

Clearly it's not very intelligent at the moment. Tweaking the sample area size ($sample) produces wildly varying results. This is because it's taking the row and column with the most edge changes in them and using the point they intersect as the origin for the thumbnail area. That can be hugely improved using a rolling average instead of a total, or figuring out which area of the image has the most changes, or figuring out which area has the most contiguous changes, etc. I'm not sure Sobel edge detection is the best option either. There's plenty still to do. Hopefully it won't be another year before I get a chance to revisit it.
Thoughts, comments, code optimisations appreciated.
It's faaaaaaaaar from being production code yet, but I've created a script for making "intelligent thumbnails". Basically, it'll take an image and make a thumbnail from the more important part of the picture. This is just a really early version at the moment, but it's a fun thing to play with.
The code:
NOTE: CURRENTLY THE CODE JUST MARKS THE AREA THE THUMBNAIL WOULD USE, IT DOESN'T MAKE THE THUMBNAIL.
Code: Select all
<?php
$source_filename = "3.jpg";
$sample = 28;
$thumb_x = 100;
$thumb_y = 100;
// -----------------------------------------------------------------------------
//Open the image
$source = imagecreatefromjpeg($source_filename);
$source_info = getimagesize($source_filename);
$source_x = $source_info[0];
$source_y = $source_info[1];
// -----------------------------------------------------------------------------
//Scale to temp_s CAR
if ($source_x < $source_y) { // X>Y
$temp_x = $sample;
$temp_y = ($sample/$source_x)*$source_y;
} else { // Y>X or Y==X
$temp_x = ($sample/$source_y)*$source_x;
$temp_y = $sample;
}
$temp = imagecreatetruecolor($temp_x, $temp_y);
imagecopyresized($temp, $source, 0, 0, 0, 0, $temp_x, $temp_y, $source_x, $source_y);
// -----------------------------------------------------------------------------
//Detect edges
$mx = array(array(-1,0,1),
array(-2,0,2),
array(-1,0,1)
);
$my = array(array(1,2,1),
array(0,0,0),
array(-1,-2,-1)
);
$m_elements = count($mx);
$m_offset = floor($m_elements/2);
for ($y=0;$y<$temp_y;$y++) {
for ($x=0;$x<$temp_x;$x++) {
$t1 = imagecolorat($temp,$x,$y);
$p[$x][$y]['r'] = ($t1 >> 16) & 0xFF;
$p[$x][$y]['g'] = ($t1 >> 8) & 0xFF;
$p[$x][$y]['b'] = $t1 & 0xFF;
}
}
for($y=0; $y<$temp_y; $y++) {
for($x=0; $x<$temp_x; $x++) {
$sumXr = 0;
$sumXg = 0;
$sumXb = 0;
$sumYr = 0;
$sumYg = 0;
$sumYb = 0;
for($i=-1; $i<=1; $i++) {
for($j=-1; $j<=1; $j++) {
$sumXr = $sumXr + (($p[$x+$i][$y+$j]['r']) * $mx[$i+1][$j+1]);
$sumXg = $sumXg + (($p[$x+$i][$y+$j]['g']) * $mx[$i+1][$j+1]);
$sumXb = $sumXb + (($p[$x+$i][$y+$j]['b']) * $mx[$i+1][$j+1]);
$sumYr = $sumYr + (($p[$x+$i][$y+$j]['r']) * $my[$i+1][$j+1]);
$sumYg = $sumYg + (($p[$x+$i][$y+$j]['g']) * $my[$i+1][$j+1]);
$sumYb = $sumYb + (($p[$x+$i][$y+$j]['b']) * $my[$i+1][$j+1]);
}
}
$sumr = abs($sumXr) + abs($sumYr);
$sumg = abs($sumXg) + abs($sumYg);
$sumb = abs($sumXb) + abs($sumYb);
if($sumr>255) $sumr=255;
if($sumg>255) $sumg=255;
if($sumb>255) $sumb=255;
if($sumr<0) $sumr=0;
if($sumg<0) $sumg=0;
if($sumb<0) $sumb=0;
//$color = imagecolorallocate($temp,255-$sumr,255-$sumg,255-$sumb);
//imagesetpixel($temp,$x,$y,$color);
$e[$x][$y] = (($sumr)+($sumg)+($sumb))/3;
}
}
// -----------------------------------------------------------------------------
//Calculate 'interest point'
$line_x = 0;
$line_y = 0;
$line_xt = 0;
$line_yt = 0;
for($x=1; $x<($temp_x-2); $x++) {
$t = 0;
for($f=0; $f<$temp_x; $f++) {
$t += $e[$x][$f];
}
if ($line_xt < $t) {
$line_x = $x;
$line_xt = $t;
}
}
for($y=1; $y<($temp_y-2); $y++) {
$t = 0;
for($f=0; $f<$temp_x; $f++) {
$t += $e[$f][$y];
}
if ($line_yt < $t) {
$line_y = $y;
$line_yt = $t;
}
}
// -----------------------------------------------------------------------------
//Generate thumbnail
$scale_x = $source_x/$temp_x;
$scale_y = $source_y/$temp_y;
$red = imagecolorallocate($temp,255,0,0);
imagerectangle($source,(($line_x*$scale_x)-floor($thumb_x/2)),(($line_y*$scale_y)-floor($thumb_y/2)),(($line_x*$scale_x)+ceil($thumb_x/2)),(($line_y*$scale_y)+ceil($thumb_y/2)),$red);
header("Content-type: image/png");
imagepng($source);

Clearly it's not very intelligent at the moment. Tweaking the sample area size ($sample) produces wildly varying results. This is because it's taking the row and column with the most edge changes in them and using the point they intersect as the origin for the thumbnail area. That can be hugely improved using a rolling average instead of a total, or figuring out which area of the image has the most changes, or figuring out which area has the most contiguous changes, etc. I'm not sure Sobel edge detection is the best option either. There's plenty still to do. Hopefully it won't be another year before I get a chance to revisit it.
Thoughts, comments, code optimisations appreciated.