Permalink
Cannot retrieve contributors at this time
<?php | |
/************************************************************************** | |
* PsychoMorph Classes | |
* | |
* PHP version 5 | |
* | |
* @author Lisa DeBruine <debruine@gmail.com> | |
* @copyright 2013 Face Research Lab | |
*************************************************************************/ | |
require_once 'psychomorph.file.class.php'; | |
include_once 'png_reader.class.php'; | |
include_once('PEL/PelJpeg.php'); | |
function mean($values) { | |
// return the mean of an array of values | |
$n = count($values); | |
if (0 == $n) return false; | |
$mean = array_sum($values) / $n; | |
return $mean; | |
} | |
function mode($values, $p = 0) { | |
// returns modal value or average of $p % at the mode | |
sort($values); | |
$n = count($values); | |
if ($p == 0) { | |
if ($n%2 == 0) { | |
$mode = $values[($n/2)-1]; | |
} else { | |
$mode = ( $values[floor($n/2)-1] + $values[ceil($n/2)-1] ) / 2; | |
} | |
} else { | |
$get = round($n * $p); // what percent of the total to average | |
if ($n%2 != $get%2) { $get++; } // if $get doesn't centre on $n, add 1 to $get | |
$start = ($n - $get)/2; | |
$end = $start + $get; | |
for ($i = $start; $i < $end; $i++) { | |
$inmode[] = $values[$i]; | |
} | |
$mode = mean($inmode); | |
} | |
return $mode; | |
} | |
function stdev($v1, $v2 = NULL) { | |
// returns the SD of an array of values | |
if (is_null($v2)) { | |
// calculate SD for one array | |
$values = $v1; | |
} else { | |
// calculate SD for difference between 2 arrays | |
$values = array(); | |
foreach ($v1 as $k => $v) { | |
$values[] = $v1[$k] - $v2[$k]; | |
} | |
} | |
$n = count($values); | |
if (0 == $n) return false; | |
$mean = mean($values); | |
foreach ($values as $x) { | |
$d2[] = ($mean - $x) * ($mean - $x); | |
} | |
$sum_squares = array_sum($d2); | |
$stdev = sqrt($sum_squares/($n-1)); | |
return $stdev; | |
} | |
function sterror($values) { | |
// returns the standard error of the mean for an array of values | |
$n = count($values); | |
if (0 == $n) return false; | |
$sd = stdev($values); | |
$sterror = $sd / sqrt($n); | |
return $sterror; | |
} | |
function deltaE($lab1, $lab2, $l = 1, $c = 1) { | |
// http://www.brucelindbloom.com/index.html?ColorCheckerCalcHelp.html | |
$L1 = $lab1['L']; | |
$a1 = $lab1['a']; | |
$b1 = $lab1['b']; | |
$L2 = $lab2['L']; | |
$a2 = $lab2['a']; | |
$b2 = $lab2['b']; | |
$H1 = rad2deg(atan($b1/$a1)); | |
if ($H1 < 0) { | |
$H1 = $H1 + 360; | |
} else if ($H1 >= 360) { | |
$H1 = $H1 - 360; | |
} | |
if ($H1 >= 164 && $H1 <= 345) { | |
$T = 0.56 + abs( 0.2 * cos($H1 + 168) ); | |
} else { | |
$T = 0.36 + abs( 0.4 * cos($H1 + 35) ); | |
} | |
$C1 = sqrt(($a1*$a1) + ($b1*$b1)); | |
$C2 = sqrt(($a2*$a2) + ($b2*$b2)); | |
$deltaC = $C1 - $C2; | |
$deltaL = $L1 - $L2; | |
$deltaa = $a1 - $a2; | |
$deltab = $b1 - $b2; | |
$deltaH = sqrt( ($deltaa * $deltaa) + ($deltab * $deltab) - ($deltaC * $deltaC) ); | |
if ($L1 < 16) { | |
$S_L = 0.511; | |
} else { | |
$S_L = (0.040976 * $L1) / (1 + (0.01765 * $L1)); | |
} | |
$S_C = ((0.0638 * $C1) / (1 + (0.0131 * $C1))) + 0.638; | |
$F = sqrt( pow($C1, 4) / (pow($C1, 4) + 1900) ); | |
$S_H = $S_C * (($F*$T) + 1 - $F); | |
$deltaE = sqrt( | |
pow(($deltaL / ($l * $S_L)), 2) + | |
pow(($deltaC / ($c * $S_C)), 2) + | |
pow(($deltaH / $S_H), 2) | |
); | |
return $deltaE; | |
} | |
function rgb2lab($r, $g, $b) { | |
// checked at http://www.brucelindbloom.com/index.html?ColorCheckerCalcHelp.html | |
/********************************************************************** | |
* RGB to XYZ via http://www.easyrgb.com/index.php?X=MATH&H=02#text2 | |
***********************************************************************/ | |
// change to 0-1 | |
$rgb = array( | |
'r' => $r/255, | |
'g' => $g/255, | |
'b' => $b/255 | |
); | |
// inverse sRGB companding | |
foreach ($rgb as $i => $v) { | |
if ( $v > 0.04045 ) { | |
$rgb[$i] = pow( (( $v + 0.055 ) / 1.055 ), 2.4); | |
} else { | |
$rgb[$i] = $v / 12.92; | |
} | |
$rgb[$i] = $rgb[$i] * 100; | |
} | |
//Observer. = 2°, Illuminant = D65 | |
$X = $rgb['r'] * 0.4124 + $rgb['g'] * 0.3576 + $rgb['b'] * 0.1805; | |
$Y = $rgb['r'] * 0.2126 + $rgb['g'] * 0.7152 + $rgb['b'] * 0.0722; | |
$Z = $rgb['r'] * 0.0193 + $rgb['g'] * 0.1192 + $rgb['b'] * 0.9505; | |
/********************************************************************** | |
* XYZ to CieL*ab via http://www.easyrgb.com/index.php?X=MATH&H=07#text7 | |
***********************************************************************/ | |
// Observer= 2°, Illuminant= D65 | |
// see http://www.brucelindbloom.com/index.html?ColorCheckerCalcHelp.html for other values | |
$ref_X = 95.047; | |
$ref_Y = 100.000; | |
$ref_Z = 108.883; | |
$xyz = array( | |
'x' => $X / $ref_X, | |
'y' => $Y / $ref_Y, | |
'z' => $Z / $ref_Z | |
); | |
foreach ($xyz as $i => $v) { | |
if ( $v > 0.008856 ) { | |
$xyz[$i] = pow($v, ( 1/3 )); | |
} else { | |
$xyz[$i] = ( 7.787 * $v ) + ( 16 / 116 ); | |
} | |
} | |
$L = ( 116 * $xyz['y'] ) - 16; | |
$a = 500 * ( $xyz['x'] - $xyz['y'] ); | |
$b = 200 * ( $xyz['y'] - $xyz['z'] ); | |
return array( | |
'X' => $X, | |
'Y' => $Y, | |
'Z' => $Z, | |
'L' => $L, | |
'a' => $a, | |
'b' => $b, | |
'lab' => array('L' => round($L,2), 'a' => round($a,2), 'b' => round($b,2)), | |
); | |
} | |
function rgb2rgbpoly($rgb, $number) { | |
/* | |
takes single pixel value and returns function of rgb values depending on | |
the value of number: | |
% | |
% 3 : r g b | |
% 5 : r g b rgb 1 | |
% 6 : r g b rg rb gb | |
% 8 : r g b rg rb gb rgb 1 | |
% 9 : r g b rg rb gb r2 g2 b2 | |
% 11: r g b rg rb gb r2 g2 b2 rgb 1 | |
*/ | |
if ($number == 3) { | |
$rgb_poly = array($rgb[0], $rgb[1], $rgb[2]); | |
} else if ($number == 5) { | |
$rgb_poly = array($rgb[0], $rgb[1], $rgb[2], $rgb[0]*$rgb[1]*$rgb[2], 1); | |
} else if ($number == 6) { | |
$rgb_poly = array($rgb[0], $rgb[1], $rgb[2], $rgb[0]*$rgb[1], $rgb[0]*$rgb[2], $rgb[1]*$rgb[2]); | |
} else if ($number == 8) { | |
$rgb_poly = array($rgb[0], $rgb[1], $rgb[2], $rgb[0]*$rgb[1], $rgb[0]*$rgb[2], $rgb[1]*$rgb[2], $rgb[0]*$rgb[1]*$rgb[2], 1); | |
} else if ($number == 9) { | |
$rgb_poly = array($rgb[0], $rgb[1], $rgb[2], $rgb[0]*$rgb[1], $rgb[0]*$rgb[2], $rgb[1]*$rgb[2], pow($rgb[0],2), pow($rgb[1],2), pow($rgb[2],2)); | |
} else if ($number == 11) { | |
$rgb_poly = array($rgb[0], $rgb[1], $rgb[2], $rgb[0]*$rgb[1], $rgb[0]*$rgb[2], $rgb[1]*$rgb[2], pow($rgb[0],2), pow($rgb[1],2), pow($rgb[2],2), $rgb[0]*$rgb[1]*$rgb[2], 1); | |
} | |
return $rgb_poly; | |
} | |
/************************************************************************** | |
* PsychoMorph_Image | |
*************************************************************************/ | |
class PsychoMorph_Image extends PsychoMorph_File { | |
private $_image = false; | |
private $_embeddedTem = ''; | |
private $_id; | |
public function __destruct() { | |
if ($this->_image) imagedestroy($this->_image); | |
} | |
public function _loadFile() { | |
$this->_image = false; | |
$path = $this->getPath(); | |
if (!file_exists($path)) { | |
return false; | |
} | |
// check all image types in order: jpg, png, gif, bmp | |
if (exif_imagetype($path) == IMAGETYPE_JPEG) { | |
$img = @imagecreatefromjpeg($path); | |
} else if (exif_imagetype($path) == IMAGETYPE_PNG) { | |
$img = @imagecreatefrompng($path); | |
} else if (exif_imagetype($path) == IMAGETYPE_GIF) { | |
$img = @imagecreatefromgif($path); | |
} else if (exif_imagetype($path) == IMAGETYPE_BMP) { | |
//$img = @imagecreatefrombmp($path); | |
} else { | |
return false; | |
} | |
$this->_image = $img; | |
// set description | |
$exif = $this->_readExif(); | |
if (empty($exif['ImageDescription'])) { | |
$this->setDescription('original', $this->getURL()); | |
} else { | |
$desc = json_decode($exif['ImageDescription'], true); | |
$this->setDescription($desc); | |
} | |
return $this; | |
} | |
public function setImage($img) { | |
if ($this->_image) imagedestroy($this->_image); | |
$this->_image = $img; | |
return $this; | |
} | |
public function setImageBase64($b64) { | |
$data = base64_decode($b64); | |
$this->_image = imagecreatefromstring($data); | |
return $this; | |
} | |
public function setEmbeddedTem($v) { | |
$this->_embeddedTem = $v; | |
return $this; | |
} | |
public function getEmbeddedTem() { | |
if ($this->_embeddedTem == '') { | |
// not already set, get from exif | |
if ($exif = $this->_readExif()) { | |
$this->_embeddedTem = $exif['COMPUTED']['UserComment']; | |
} | |
} | |
return $this->_embeddedTem; | |
} | |
public function getImage() { return $this->_image; } | |
public function getWidth() { | |
if (!$this->_image) { return false; } | |
return imagesx($this->_image); | |
} | |
public function getHeight() { | |
if (!$this->_image) { return false; } | |
return imagesy($this->_image); | |
} | |
public function getImg() { return $this; } | |
private function _makeThumb($original_image) { | |
// Get new dimensions | |
$width = imagesx($original_image); | |
$height = imagesy($original_image); | |
$new_height = 100; | |
$new_width = $width * $new_height / $height; | |
// Resample | |
$thumbnail_image = imagecreatetruecolor($new_width, $new_height); | |
imagecopyresampled( | |
$thumbnail_image, $original_image, | |
0, 0, | |
0, 0, | |
$new_width, $new_height, | |
$width, $height | |
); | |
return $thumbnail_image; | |
} | |
private function _nextImg() { | |
$exp_path = explode("/", $this->getURL()); | |
$project_id = $exp_path[0]; | |
unset($exp_path[0]); | |
$name = "/" . implode("/", $exp_path); | |
// get next id from uploads table | |
$img_query = new myQuery(sprintf( | |
"INSERT INTO img (user_id, dt, name, project_id) | |
VALUES ('%d', NOW(), '%s', '%s') | |
ON DUPLICATE KEY UPDATE | |
user_id='%d', dt=NOW()", | |
$_SESSION['user_id'], | |
$name, | |
$project_id, | |
$_SESSION['user_id'] | |
)); | |
$this->_id = $img_query->get_insert_id(); | |
return $this->_id; | |
} | |
private function _readExif() { | |
$filename = $this->getPath(); | |
if (file_exists($filename) && exif_imagetype($filename) == IMAGETYPE_JPEG) { | |
$exif = @exif_read_data($filename); | |
return $exif; | |
} | |
return false; | |
} | |
private function _addExif($filename) { | |
//if ($_SERVER['SERVER_NAME'] == 'test.psychomorph') return true; | |
try { | |
$jpeg = new PelJpeg($filename); | |
if (!$exif = $jpeg->getExif()) { | |
// Create and add empty Exif data to the image (this throws away any old Exif data in the image). | |
$exif = new PelExif(); | |
$jpeg->setExif($exif); | |
} | |
if (!$tiff = $exif->getTiff()) { | |
// Create and add TIFF data to the Exif data (Exif data is actually stored in a TIFF format). | |
$tiff = new PelTiff(); | |
$exif->setTiff($tiff); | |
} | |
if (!$ifd0 = $tiff->getIfd()) { | |
// Create first Image File Directory and associate it with the TIFF data. | |
$ifd0 = new PelIfd(PelIfd::IFD0); | |
$tiff->setIfd($ifd0); | |
} | |
if (!$exif_ifd = $ifd0->getSubIfd(PelIfd::EXIF)) { | |
// Create exif Image File Directory and associate it with the TIFF data. | |
$exif_ifd = new PelIfd(PelIfd::EXIF); | |
$ifd0->addSubIfd($exif_ifd); | |
} | |
if (!$ifd1 = $ifd0->getNextIfd()) { | |
// thumbnail does not exist | |
$ifd1 = new PelIfd(1); | |
$ifd0->setNextIfd($ifd1); | |
//$original = ImageCreateFromString($jpeg->getBytes()); # create image resource of original | |
//$thumb = makeThumb($original); | |
$thumb = $this->_makeThumb($this->getImage()); | |
// start writing output to buffer | |
ob_start(); | |
// outputs thumb resource contents to buffer | |
ImageJpeg($thumb); | |
// create PelDataWindow from buffer thumb contents (and end output to buffer) | |
$window = new PelDataWindow(ob_get_clean()); | |
if ($window) { | |
$ifd1->setThumbnail($window); # set window data as thumbnail in ifd1 | |
} | |
//imagedestroy($original); | |
imagedestroy($thumb); | |
} | |
$exifdata = array( | |
PelTag::IMAGE_DESCRIPTION => $this->getDescription(), | |
PelTag::COPYRIGHT => "webmorph.org: " | |
. $_SESSION['user_id'] | |
. ': IMG_ID: ' , | |
//. $this->_id, | |
PelTag::USER_COMMENT => $this->_embeddedTem, | |
); | |
foreach ($exifdata as $PelTag => $val) { | |
if ($PelTag == PelTag::USER_COMMENT) { | |
if (!$entry = $exif_ifd->getEntry($PelTag)) { | |
$exif_ifd->addEntry(new PelEntryUserComment($val)); | |
} else { | |
$entry->setValue($val); | |
} | |
} else { | |
if (!$entry = $ifd0->getEntry($PelTag)) { | |
$ifd0->addEntry(new PelEntryAscii($PelTag, $val)); | |
} else { | |
$entry->setValue($val); | |
} | |
} | |
} | |
$jpeg->saveFile($filename); | |
return true; | |
} catch (Throwable $e) { | |
// Handle exception | |
echo $e; | |
} | |
} | |
public function resize($xResize, $yResize = null) { | |
if ($yResize == null) { $yResize = $xResize; } | |
if ($xResize <= 0 || $yResize<=0 || $xResize > 10 || $yResize > 10 || !$this->_image) { | |
// resize is too small or too big or image doesn't exist | |
return false; | |
} | |
// resize image | |
$width = $this->getWidth(); | |
$height = $this->getHeight(); | |
$new_width = $width * $xResize; | |
$new_height = $height * $yResize; | |
$resized_image = imagecreatetruecolor($new_width, $new_height); | |
// make sure you don't loose transparency | |
imagealphablending($resized_image, false); | |
imagesavealpha($resized_image, true); | |
//$transparent = imagecolorallocatealpha($resized_image, 255, 255, 255, 127); | |
//imagefilledrectangle($resized_image, 0, 0, $new_width, $new_height, $transparent); | |
imagecopyresampled( | |
$resized_image, $this->_image, | |
0, 0, | |
0, 0, | |
$new_width, $new_height, | |
$width, $height | |
); | |
$this->setImage($resized_image); | |
return $this; | |
} | |
private function colorAlloc(&$image, $rgb) { | |
// get background color from $rgb or upper left corner | |
if (!is_array($rgb) || !count($rgb) == 3) { | |
$cornercolor = imagecolorat($this->_image, 2, 2); | |
$rgb = array( | |
($cornercolor >> 16) & 0xFF, | |
($cornercolor >> 8) & 0xFF, | |
$cornercolor & 0xFF | |
); | |
} | |
$color = imagecolorallocate($image, $rgb[0], $rgb[1], $rgb[2]); | |
return $color; | |
} | |
public function rotate($degrees, $rgb = null) { | |
// positive numbers rotate counter-clockwise, | |
// so reverse because clockwise seems more natural | |
$deg = -1 * $degrees; | |
if (empty($deg) || !$this->_image) { return false; } | |
$color = $this->colorAlloc($this->_image, $rgb); | |
$rotated_image = imagerotate($this->_image, $deg, $color); | |
$this->setImage($rotated_image); | |
return $this; | |
} | |
public function crop($xOffset, $yOffset, $width, $height, $rgb = null) { | |
$newimg = imagecreatetruecolor($width, $height); | |
$color = $this->colorAlloc($newimg, $rgb); | |
imagefill($newimg, 0, 0, $color); | |
$w = $this->getWidth(); | |
$h = $this->getHeight(); | |
$dst_x = ($xOffset < 0) ? -1*$xOffset : 0; | |
$dst_y = ($yOffset < 0) ? -1*$yOffset : 0; | |
$src_x = ($xOffset < 0) ? 0 : $xOffset; | |
$src_y = ($yOffset < 0) ? 0 : $yOffset; | |
$src_w = min($width, $w - $src_x); | |
$src_h = min($height, $h - $src_y); | |
imagecopy($newimg, $this->_image, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); | |
$this->setImage($newimg); | |
return $this; | |
} | |
public function mirror($sym = null) { | |
// create the mirror-reversed version of the file | |
// doesn't use the sym file in argument1, but included for consistency | |
$width = $this->getWidth(); | |
$height = $this->getHeight(); | |
$newimg = imagecreatetruecolor($width, $height); | |
imagecopyresampled( | |
$newimg, $this->_image, | |
0, 0, | |
$width-1, 0, | |
$width, $height, | |
-$width, $height | |
); | |
$this->setImage($newimg); | |
return $this; | |
} | |
public function scramble($scramble_data) { | |
ini_set('memory_limit','1024M'); | |
$gridsize = 25; // number of pixels between each grid | |
$x_offset = 0; // x-coordinate at which to start the first vertical gridline | |
$y_offset = 0; // y-coordinate at which to start the first horizontal gridline | |
if (is_numeric($scramble_data['grid']) && $scramble_data['grid']>0) $gridsize = $scramble_data['grid']; | |
if (is_numeric($scramble_data['x'])) $x_offset = $scramble_data['x']; | |
if (is_numeric($scramble_data['y'])) $y_offset = $scramble_data['y']; | |
$original_image = $this->getImage(); | |
$imgwidth = $this->getWidth(); | |
$imgheight = $this->getHeight(); | |
// copy over the whole original image | |
$new_image = imagecreatetruecolor($imgwidth, $imgheight); | |
imagecopy($new_image, $original_image, 0, 0, 0, 0, $imgwidth, $imgheight); | |
//set up grid structure | |
$means = array(); | |
if ($scramble_data['chosen'] == 'all') { | |
// scramble all | |
// get number of rows and columns | |
$xx = floor(($imgwidth-$x_offset)/$gridsize); | |
$yy = floor(($imgheight-$y_offset)/$gridsize); | |
for ($x = 0; $x < $xx; $x++) { | |
for ($y = 0; $y < $yy; $y++) { | |
$grids[] = array($x, $y); | |
} | |
} | |
// set mean to middle column | |
$means = array(($xx-1)/2); | |
} else { | |
// scramble only chosen squares | |
//$grids = $_POST['chosen']; | |
foreach ($scramble_data['chosen'] as $y => $xx) { | |
if ($xx !== '') { | |
$xx = explode(",", $xx); | |
$means[] = array_sum($xx)/count($xx); | |
foreach ($xx as $x) { | |
$grids[] = array($x, $y); | |
} | |
} | |
} | |
} | |
// symmetric shuffling | |
if ($scramble_data['sym'] == 'true' && | |
$means == array_fill(0, count($means), $means[0]) | |
) { | |
$symgrid = $grids; | |
$grids = array(); | |
$random_grids = array(); | |
// check if there is a centre column | |
$center = $means[0]; | |
if ($center == floor($center)) { | |
foreach ($symgrid as $g) { | |
if ($g[0] == $center) { | |
$center_grid[] = $g; | |
} | |
} | |
if (count($center_grid)) { | |
$grids = array_merge($grids, $center_grid); | |
shuffle($center_grid); | |
$random_grids = array_merge($random_grids, $center_grid); | |
} | |
} | |
// shuffle left side and mirror right shuffle order | |
foreach ($symgrid as $g) { | |
if ($g[0] < $center) { | |
$left_grid[] = $g; | |
$right_grid[] = array($g[0] + 2*($center - $g[0]), $g[1]); | |
} | |
} | |
if (count($left_grid)) { | |
$grids = array_merge($grids, $left_grid); | |
$grids = array_merge($grids, $right_grid); | |
shuffle($left_grid); | |
$random_grids = array_merge($random_grids, $left_grid); | |
foreach($left_grid as $g) { | |
$mirror_right_grid[] = array($g[0] + 2*($center - $g[0]), $g[1]); | |
} | |
$random_grids = array_merge($random_grids, $mirror_right_grid); | |
} | |
} else { | |
// randomise grids | |
$random_grids = $grids; | |
shuffle($random_grids); | |
} | |
foreach($random_grids as $k => $grid) { | |
$dest_x = $grid[0] * $gridsize + $x_offset; | |
$dest_y = $grid[1] * $gridsize + $y_offset; | |
$source_x = $grids[$k][0] * $gridsize + $x_offset; | |
$source_y = $grids[$k][1] * $gridsize + $y_offset; | |
imagecopy($new_image, $original_image, $dest_x, $dest_y, $source_x, $source_y, $gridsize, $gridsize); | |
} | |
//imagedestroy($original_image); | |
// superimpose grid on image | |
if (array_key_exists('line_color', $scramble_data)) { | |
$linecolor = imagecolorallocate( | |
$new_image, | |
$scramble_data['line_color'][0], | |
$scramble_data['line_color'][1], | |
$scramble_data['line_color'][2] | |
); | |
for ($x = $x_offset ; $x <= $imgwidth; $x += $gridsize) { | |
imageline($new_image, $x, 0, $x, $imgheight, $linecolor); | |
} | |
for ($y = $y_offset; $y <= $imgheight; $y += $gridsize) { | |
imageline($new_image, 0, $y, $imgwidth, $y, $linecolor); | |
} | |
} | |
$this->setImage($new_image); | |
// add description | |
$desc = array( | |
"gridsize" => $gridsize, | |
"offset" => $x_offset . ", " . $y_offset, | |
"symmetric" => $scramble_data['sym'] | |
); | |
if (array_key_exists('line_color', $scramble_data)) { | |
$desc['linecolor'] = implode(",",$scramble_data['line_color']); | |
} | |
foreach ($random_grids as $rg) { | |
$scram[] = "{$rg[0]},{$rg[1]}"; | |
} | |
$desc['scramble'] = implode(" ",$scram); | |
$this->addHistory($desc); | |
return $this; | |
} | |
public function colourCalibrate($colours, $expand = 25, $SD = 2) { | |
// $colours lists x-coordinate, y-coordinate, and L, a* and b* values for each colour on the checker chart | |
// $expand = number of pixels plus or minus the reference x and y-corrdinates | |
// $SD = exclude pixels more than $sd standard deviations from the mean for that area | |
if (!imageistruecolor($this->_image)) { return false; } | |
$w = $this->getWidth(); | |
$h = $this->getHeight(); | |
$rgb255 = array(); | |
foreach ($colours as $cname => $c) { | |
// get color from x and y coordinates | |
$imgcolor = array(); | |
for ($x = $c[0] - $expand; $x <= $c[0] + $expand; $x++) { | |
for ($y = $c[1] - $expand; $y <= $c[1] + $expand; $y++) { | |
$rgb = imagecolorat($this->_image, $x, $y); | |
$imgcolor['r'][] = ($rgb >> 16) & 0xFF; | |
$imgcolor['g'][] = ($rgb >> 8) & 0xFF; | |
$imgcolor['b'][] = $rgb & 0xFF; | |
} | |
} | |
foreach ($imgcolor as $rgb => $valuearray) { | |
$mode = mode($valuearray, .25); | |
$stdev = stdev($valuearray); | |
foreach ($valuearray as $i => $v) { | |
if ($v > ($mode + ($SD * $stdev)) || $v < ($mode - ($SD * $stdev)) ) { | |
// remove from list | |
unset($valuearray[$i]); | |
} | |
} | |
$averages[$rgb] = round(mean($valuearray), 12); | |
$stdevs[$rgb] = round(stdev($valuearray), 4); | |
$counts[$rgb] = count($valuearray); | |
} | |
$rgb255[] = $averages; | |
$lab = rgb2lab($averages['r'], $averages['g'], $averages['b']); | |
$deltaE = deltaE($lab, array($c[2], $c[3], $c[4])); | |
$check[$cname] = sprintf("Lab(%.1f, %.1f, %.1f)\n", | |
round($lab['L'], 1), | |
round($lab['a'], 1), | |
round($lab['b'], 1) | |
); | |
/* | |
$check .= "--myLab: (" . implode(',', $lab['lab']) . ")\n"; | |
$check .= "--chartLab: ($c[2], $c[3], $c[4])\n"; | |
$check .= "--deltaE = $deltaE\n"; | |
$check .= "--RGB: (" . implode(',', $averages) . ")\n"; | |
$check .= "--SD: (" . implode(',', $stdevs) . ")\n"; | |
$check .= "--N: (" . implode(',', $counts) . ")\n"; | |
*/ | |
if ( !is_nan($deltaE) ) $deltaEs[] = $deltaE; | |
} | |
$meanDeltaE = round(mean($deltaEs), 4); | |
$maxDeltaE = round(max($deltaEs), 4); | |
$patch = ($expand * 2) + 1; | |
$this->addHistory(array("colour calibrate" => array( | |
"path dimension" => "$patch x $patch", | |
"SD" => $SD, | |
"deltaE" => array("M" => $meanDeltaE, "max" => $maxDelta), | |
"check" => $check | |
))); | |
/* MATLAB code ************************************ | |
% Calculate camera Characterisation - Least Squares fit of rgb to Lab patches: | |
rgb = Rgb_vals/255; | |
for i = 1:length(rgb) | |
train(i,:) = rgb2rgbpoly(rgb(i,:),11); | |
end | |
R=train\spectrod65; | |
% Calculate predicted lab values from characterisation | |
lab_calc = train*R; | |
squaredDifference = (lab_calc-spectrod65).^2; | |
meanDeltaE = mean(sqrt(sum(squaredDifference'))) | |
maxDeltaE = max(sqrt(sum(squaredDifference'))) | |
**************************************************/ | |
//include_once "Math/Matrix.php"; | |
include_once $_SERVER['DOCUMENT_ROOT'] . "/include/classes/Math/Matrix.php"; | |
foreach ($colours as $v) { | |
$spectrod65[] = array($v[2], $v[3], $v[4]); | |
} | |
foreach($rgb255 as $i => $v) { | |
foreach ($v as $j => $c) { | |
$rgb1[$i][] = $c/255; | |
} | |
} | |
foreach ($rgb1 as $v) { | |
$train[] = rgb2rgbpoly($v, 11); | |
} | |
$rgbM = new Math_Matrix($rgb1); | |
$trainM = new Math_matrix($train); | |
return $this; | |
} | |
public function convert($ext) { | |
$allowed_ext = array('jpg', 'png', 'gif'); | |
if (in_array($ext, $allowed_ext)) { | |
$oldname = $this->getPath(); | |
$newname = preg_replace('@\.(jpg|png|gif)$@', '.' . $ext, $oldname); | |
$this->addHistory("convert: {$ext}"); | |
return $this->save($newname); | |
} else { | |
return false; | |
} | |
} | |
public function _saveFile($filepath = '', $overWrite = false) { | |
$png_compression = 0; | |
$jpg_compression = 100; | |
if (!$this->_image) { | |
//echo '{"error": "no image (' . $filepath . ')"},'; | |
return false; | |
} | |
if (empty($filepath)) { | |
$filepath = $this->getPath(); | |
} | |
$success = false; | |
$ext = pathinfo($filepath, PATHINFO_EXTENSION); | |
if ('png' == $ext) { | |
$success = imagepng($this->_image, $filepath, $png_compression); | |
} else if ('gif' == $ext) { | |
$success = imagegif($this->_image, $filepath); | |
} else { | |
// default to jpeg if no extension given | |
if ('jpg' !== $ext) { $filepath .= '.jpg'; } | |
if (imagejpeg($this->_image, $filepath, $jpg_compression)) { | |
// add exif data to jpegs | |
$this->_addExif($filepath); | |
$success = true; | |
} else { | |
//echo '{"error": "no jpeg"},'; | |
} | |
} | |
if ($success) { | |
chmod($filepath, IMGPERMS); // make sure the file is only readable by the web user | |
touch(IMAGEBASEDIR . $this->getProject()); // update filemtime for the project directory | |
$this->_setPath($filepath); | |
$this->_nextImg(); // add to or update img table | |
return true; | |
} | |
return false; | |
} | |
} |