Ignore:
Timestamp:
May 13, 2010, 10:21:05 PM (15 years ago)
Author:
grum
Message:

Improve algorythm for colors analysis + use GPCRequestBuilder interface instead of a local interface

File:
1 edited

Legend:

Unmodified
Added
Removed
  • extensions/ColorStat/cstat_colorstat.class.inc.php

    r6107 r6176  
    4646  --------------------------------------------------------------------------- */
    4747
    48   if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
     48if(!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
     49
     50/**
     51 * if DEBUG_MODE is set to true, the getFileColors function save a jpg file of
     52 * the 'viewed' image :
     53 *  - resampled file
     54 *  - color from the color table
     55 *
     56 * use it only for debug, or if you are curious about what the function really
     57 * see
     58 */
     59define('DEBUG_MODE', false);
     60
     61
    4962
    5063/**
     
    5972  }
    6073
     74  /**
     75   * set the R,G and B values
     76   *
     77   * @param Byte $R : the red value, between [0..255]
     78   * @param Byte $G : the green value, between [0..255]
     79   * @param Byte $B : the blue value, between [0..255]
     80   * @return Array('R'=>$R, 'G'=>$G, 'B'=>$B)
     81   */
    6182  public function set($R, $G, $B)
    6283  {
     
    6788  }
    6889
     90  /**
     91   * set RGB values from an Integer (0xFFFFFF : white value)
     92   *
     93   * @param Integer $value : the RGB value
     94   * @return Array('R'=>$R, 'G'=>$G, 'B'=>$B)
     95   */
    6996  public function setInt($value)
    7097  {
     
    76103  }
    77104
     105  /**
     106   * returns the current RGB values as array
     107   *
     108   * @param Boolean $floatValue : if set to true, values are returned as float
     109   *                              values between [0..1] otherwise values are
     110   *                              returned as integer between [0..255]
     111   * @return Array('R'=>$R, 'G'=>$G, 'B'=>$B)
     112   */
    78113  public function get($floatValue=false)
    79114  {
     
    94129  }
    95130
     131
     132  /**
     133   * returns the current RGB values as hex string  ('FFFFFF' : white)
     134   *
     135   * @return String
     136   */
    96137  public function getHexString()
    97138  {
     
    99140  }
    100141
     142  /**
     143   * returns the current RGB values as integer  (0xFFFFFF : white)
     144   *
     145   * @return Integer
     146   */
    101147  public function getInt()
    102148  {
     
    104150  }
    105151
     152
     153  /**
     154   * returns the current RGB values as a HSV object
     155   *
     156   * @return HSV
     157   */
    106158  public function getHSV()
    107159  {
     
    109161  }
    110162
     163  /**
     164   * set the RGB values from a HSV ojbect
     165   *
     166   * @param HSV $hsv : a HSV object
     167   */
    111168  public function setHSV(HSV $hsv)
    112169  {
     
    118175  }
    119176
     177  /**
     178   * set the RGB property
     179   *
     180   * @param String $property : 'R', 'G', 'B'
     181   * @param Integer $value : value between [0..255]
     182   * @return Integer : value of the property
     183   */
    120184  private function setProperty($property, $value)
    121185  {
     
    143207  }
    144208
     209  /**
     210   * set the H, S and V values
     211   *
     212   * @param Integer $H : the hue value, between [0..360]
     213   * @param Byte $S    : the saturation value, between [0..100]
     214   * @param Byte $V    : the value value, between [0..100]
     215   * @return Array('H'=>$H, 'S'=>$S, 'V'=>$V)
     216   */
    145217  public function set($H, $S, $V)
    146218  {
     
    151223  }
    152224
     225  /**
     226   * returns the current HSV values as array
     227   *
     228   * @return Array('H'=>$H, 'S'=>$S, 'V'=>$V)
     229   */
    153230  public function get()
    154231  {
     
    156233  }
    157234
     235  /**
     236   * returns the current HSV values as a RGB object
     237   *
     238   * @return RGB
     239   */
    158240  public function getRGB()
    159241  {
     
    161243  }
    162244
     245
     246
     247  /**
     248   * set the HSV values from a RGB ojbect
     249   *
     250   * @param RGB $rgb : a RGB object
     251   */
    163252  public function setRGB(RGB $rgb)
    164253  {
     
    170259  }
    171260
     261  /**
     262   * set the HSV property
     263   *
     264   * @param String $property : 'H', 'S', 'V'
     265   * @param Integer $value : value between [0..255]
     266   * @return Integer : value of the property
     267   */
    172268  private function setProperty($property, $value)
    173269  {
     
    203299
    204300  /**
     301   * returns colors of an image file
     302   *
     303   * return :
     304   *
     305   *
    205306   *
    206307   * @param String $fileName : the name of picture to scan
     
    212313   *                          if 'maxTime' and 'pps' are greater than zero, the
    213314   *                          quality parameter is computed automatically
    214    * @return Array : an array of HSV objects
     315   * @return : -1 if file doesn't exist
     316   *           -2 if file is not a PNG, a JPEG or a GIF file
     317   *           -3 if a fatal error occurs
     318   *            array of HSV objects if everthing is Ok
    215319   */
    216320  static function getFileColors($fileName, $colorTable, $options=array())
     
    229333      $time=microtime(true);
    230334
    231       if(preg_match('/.*\.gif$/i', $fileName))
     335      try
    232336      {
    233         $image = imagecreatefromgif($fileName);
     337        if(preg_match('/.*\.gif$/i', $fileName))
     338        {
     339          $image = imagecreatefromgif($fileName);
     340        }
     341        elseif(preg_match('/.*\.(jpg|jpeg)$/i', $fileName))
     342        {
     343          $image = imagecreatefromjpeg($fileName);
     344        }
     345        elseif(preg_match('/.*\.png$/i', $fileName))
     346        {
     347          $image = imagecreatefrompng($fileName);
     348        }
     349        else
     350        {
     351          return(-2);
     352        }
     353
     354
     355        $imageWidth=imagesx($image);
     356        $imageHeight=imagesy($image);
     357
     358        if($options['pps']>0 && $options['maxTime']>0)
     359        {
     360          $quality=round(sqrt($imageWidth*$imageHeight/($options['pps']*$options['maxTime'])), 0);
     361        }
     362        else
     363        {
     364          $quality=$options['quality'];
     365        }
     366
     367        $imageWorkWidth=round($imageWidth/$quality,0);
     368        $imageWorkHeight=round($imageHeight/$quality,0);
     369        $imageWork=imagecreatetruecolor($imageWorkWidth,$imageWorkHeight);
     370        imagecopyresampled($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
     371        //imagecopyresized($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
     372        imagedestroy($image);
     373
     374        $returned=Array();
     375
     376        $i=0;
     377        for($px=0;$px<$imageWorkWidth;$px++)
     378        {
     379          for($py=0;$py<$imageWorkHeight;$py++)
     380          {
     381            $i++;
     382            $value=imagecolorat($imageWork, $px, $py);
     383
     384            $rgb=self::IntToRGB($value);
     385            //echo sprintf("%06x", $value)." => ".$rgb->getHexString();
     386
     387
     388            //echo " ($i) ".$color->getHexString()."<br>";
     389
     390            if(DEBUG_MODE)
     391            {
     392              $color=self::getColorFromTable($rgb->getHSV(), $colorTable);
     393              $newRGB=$color->get();
     394              $col=imagecolorallocate($imageWork, $newRGB['R'], $newRGB['G'], $newRGB['B']);
     395              imagesetpixel($imageWork, $px, $py, $col);
     396              imagecolordeallocate($imageWork, $col);
     397              $color=$color->getHexString();
     398              unset($newRGB);
     399            }
     400            else
     401            {
     402              $color=self::getColorFromTable($rgb->getHSV(), $colorTable)->getHexString();
     403            }
     404
     405
     406            if(array_key_exists($color, $returned))
     407            {
     408              $returned[$color]['num']++;
     409            }
     410            else
     411            {
     412              $returned[$color]=Array(
     413                'hsv' => $rgb->getHSV()->get(),
     414                'num' => 1,
     415                'pct' => 0,
     416              );
     417            }
     418            unset($rgb);
     419          }
     420        }
     421
     422
     423        if(DEBUG_MODE)
     424        {
     425          $fName="q".$quality."_c".$options['numColors']."_nb".count($returned)."_".$fileName.".png";
     426          imagepng($imageWork, $fName);
     427        }
     428
     429
     430        imagedestroy($imageWork);
     431        uasort($returned, Array('ColorStat', 'sortTones'));
     432
     433        if($options['numColors']>0)
     434        {
     435          foreach($returned as $key=>$val)
     436          {
     437            $returnedColors[$key]=$val;
     438            $options['numColors']--;
     439            if($options['numColors']<=0) break;
     440          }
     441        }
     442        else
     443        {
     444          $returnedColors=$returned;
     445        }
     446
     447        self::$fileColorsStat=Array(
     448          'pixels'   => $imageWidth*$imageHeight,
     449          'analyzed' => $i,
     450          'time'     => microtime(true)-$time,
     451          'colors'   => count($returned),
     452          'pps'      => $i/(microtime(true)-$time),
     453          'quality'  => $quality,
     454        );
     455
     456        if(DEBUG_MODE)
     457        {
     458          self::$fileColorsStat['fileName']=$fName;
     459        }
     460
     461        unset($returned);
     462
     463        foreach($returnedColors as $key => $val)
     464        {
     465          $returnedColors[$key]['pct']=round(100*$val['num']/self::$fileColorsStat['analyzed'],2);
     466        }
     467
     468        return($returnedColors);
    234469      }
    235       elseif(preg_match('/.*\.(jpg|jpeg)$/i', $fileName))
     470      catch (Exception $e)
    236471      {
    237         $image = imagecreatefromjpeg($fileName);
     472        echo "ERROR!<br>".print_r($e, true);
     473        return(-3);
    238474      }
    239       elseif(preg_match('/.*\.png$/i', $fileName))
    240       {
    241         $image = imagecreatefrompng($fileName);
    242       }
    243       else
    244       {
    245         return(-2);
    246       }
    247 
    248       $imageWidth=imagesx($image);
    249       $imageHeight=imagesy($image);
    250 
    251       if($options['pps']>0 && $options['maxTime']>0)
    252       {
    253         $quality=round(sqrt($imageWidth*$imageHeight/($options['pps']*$options['maxTime'])), 0);
    254       }
    255       else
    256       {
    257         $quality=$options['quality'];
    258       }
    259 
    260       $imageWorkWidth=round($imageWidth/$quality,0);
    261       $imageWorkHeight=round($imageHeight/$quality,0);
    262       $imageWork=imagecreatetruecolor($imageWorkWidth,$imageWorkHeight);
    263       imagecopyresampled($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
    264       //imagecopyresized($imageWork, $image, 0, 0, 0, 0, $imageWorkWidth, $imageWorkHeight, $imageWidth, $imageHeight);
    265       imagedestroy($image);
    266 
    267       $returned=Array();
    268 
    269       $i=0;
    270       for($px=0;$px<$imageWorkWidth;$px++)
    271       {
    272         for($py=0;$py<$imageWorkHeight;$py++)
    273         {
    274           $i++;
    275           $value=imagecolorat($imageWork, $px, $py);
    276 
    277           $rgb=self::IntToRGB($value);
    278           //echo sprintf("%06x", $value)." => ".$rgb->getHexString();
    279 
    280           $color=self::getColorFromTable($rgb->getHSV(), $colorTable)->getHexString();
    281           //echo " ($i) $color<br>";
    282 
    283           if(array_key_exists($color, $returned))
    284           {
    285             $returned[$color]['num']=$returned[$color]['num']+1;
    286           }
    287           else
    288           {
    289             $returned[$color]=Array(
    290               'hsv' => $rgb->getHSV()->get(),
    291               'num' => 1,
    292               'pct' => 0,
    293             );
    294           }
    295           unset($rgb);
    296         }
    297       }
    298 
    299       /*
    300       $fName="q".$quality."_c".$options['numColors']."_".$fileName.".png";
    301       imagepng($imageWork, $fName);
    302       */
    303 
    304       imagedestroy($imageWork);
    305       uasort($returned, Array('ColorStat', 'sortTones'));
    306 
    307       if($options['numColors']>0)
    308       {
    309         foreach($returned as $key=>$val)
    310         {
    311           $returnedColors[$key]=$val;
    312           $options['numColors']--;
    313           if($options['numColors']<=0) break;
    314         }
    315       }
    316       else
    317       {
    318         $returnedColors=$returned;
    319       }
    320 
    321       self::$fileColorsStat=Array(
    322         'pixels'   => $imageWidth*$imageHeight,
    323         'analyzed' => $i,
    324         'time'     => microtime(true)-$time,
    325         'colors'   => count($returned),
    326         'pps'      => $i/(microtime(true)-$time),
    327         'quality'  => $quality,
    328         //'fileName' => $fName,
    329       );
    330 
    331       unset($returned);
    332 
    333       foreach($returnedColors as $key => $val)
    334       {
    335         $returnedColors[$key]['pct']=round(100*$val['num']/self::$fileColorsStat['analyzed'],2);
    336       }
    337 
    338       return($returnedColors);
     475
    339476    }
    340477    else
     
    432569  /**
    433570   * return a color table
    434    *  $table = Array(
    435    *              Array(),
    436    *              Array(),
    437    *              ...
    438    *              Array(),
    439    *              Array(),
    440    *           )
    441    *  $table[n]    => Array of all colors for a given hue value
    442    *  $table[n][m] => HSV object or a color string RRGGBB
    443    *
     571   *  $table[h][s][v] => HSV object or string 'RRGGBB'
    444572   *
    445573   * @param Int $huePrec : degree of precision for hue [1..360]
    446574   * @param Float $prec    : precision step for saturation & value [1..100]
    447575   * @param String $returnedType : 'HSV'   => return a HSV object
    448    *                               'color' => return a color string RRGGBB
     576   *                               'color' => return a color string 'RRGGBB'
    449577   * @return Array : the color table
    450578   */
     
    452580  {
    453581    $returned=Array();
    454     for($hue=0;$hue<=360;$hue+=$huePrec)
     582    for($hue=0;$hue<360;$hue+=$huePrec)
    455583    {
    456584      $hueValues=Array();
    457585
    458       $saturation=100;
    459       for($value=0;$value<100;$value=$value+=$prec)
     586      for($saturation=0;$saturation<=100;$saturation+=$prec)
    460587      {
    461         $hsv=new HSV($hue, $saturation, $value);
    462         if($returnedType=='HSV')
    463         {
    464           $hueValues[]=$hsv;
    465         }
    466         else
    467         {
    468           $hueValues[]=$hsv->getRGB()->getHexString();
    469         }
    470         unset($hsv);
     588        $saturationValues=Array();
     589
     590        for($value=0;$value<=100;$value+=$prec)
     591        {
     592          $hsv=new HSV($hue, $saturation, $value);
     593          if($returnedType=='HSV')
     594          {
     595            $saturationValues[$value]=$hsv;
     596          }
     597          else
     598          {
     599            $saturationValues[$value]=$hsv->getRGB()->getHexString();
     600          }
     601          unset($hsv);
     602        }
     603
     604        $hueValues[$saturation]=$saturationValues;
     605        unset($saturationValues);
    471606      }
    472 
    473       $value=100;
    474       for($saturation=100;$saturation>=0;$saturation-=$prec)
    475       {
    476         $hsv=new HSV($hue, $saturation, $value);
    477         if($returnedType=='HSV')
    478         {
    479           $hueValues[]=$hsv;
    480         }
    481         else
    482         {
    483           $hueValues[]=$hsv->getRGB()->getHexString();
    484         }
    485         unset($hsv);
    486       }
    487 
    488 
    489       for($tmp=$prec;$tmp<=100;$tmp+=$prec)
    490       {
    491         $hsv=new HSV($hue, $tmp, 100-$tmp);
    492         if($returnedType=='HSV')
    493         {
    494           $hueValues[]=$hsv;
    495         }
    496         else
    497         {
    498           $hueValues[]=$hsv->getRGB()->getHexString();
    499         }
    500         unset($hsv);
    501       }
    502       for($tmp=$prec;$tmp<=100;$tmp+=$prec)
    503       {
    504         $hsv=new HSV($hue, $tmp, $tmp);
    505         if($returnedType=='HSV')
    506         {
    507           $hueValues[]=$hsv;
    508         }
    509         else
    510         {
    511           $hueValues[]=$hsv->getRGB()->getHexString();
    512         }
    513         unset($hsv);
    514       }
    515 
    516       $returned[]=$hueValues;
     607      $returned[$hue]=$hueValues;
    517608      unset($hueValues);
    518609    }
    519610
    520     $hue=0;
    521     $saturation=0;
    522     $hueValues=Array();
    523     //$prec=1/(count($returned[0])-2);
    524     for($value=0;$value<=100;$value+=$prec/4)
    525     {
    526       $hsv=new HSV($hue, $saturation, round($value,0));
    527       if($returnedType=='HSV')
    528       {
    529         $hueValues[]=$hsv;
    530       }
    531       else
    532       {
    533         $hueValues[]=$hsv->getRGB()->getHexString();
    534       }
    535       unset($hsv);
    536     }
    537 
    538     $returned[]=$hueValues;
    539     unset($hueValues);
    540611
    541612    return($returned);
     
    621692  }
    622693
    623   static public function getColorFromTable(HSV $hsvObject, $colorTable)
    624   {
    625     $hue=360/(count($colorTable)-2);
    626     $step=count($colorTable[0]);
    627 //echo "*hue:$hue<br>";
    628 //echo "*step:$step<br>";
    629 
     694  /**
     695   * for the given color, return the nearest color of the color table
     696   *
     697   * @param HSV $hsvObject    : the color, as HSV object
     698   * @param Array $colorTable : the colorTable
     699   * @param String $mode      : 'HSV' or 'RGB' to define the returned object
     700   * @return HSV or RGB       : the color
     701   */
     702  static public function getColorFromTable(HSV $hsvObject, $colorTable, $mode='RGB')
     703  {
    630704    $hsv=$hsvObject->get();
    631 
     705//echo "*H:".$hsv['H']." ";
     706//echo "*S:".$hsv['S']." ";
     707//echo "*V:".$hsv['V']."<br>";
     708
     709    $hue=360/count($colorTable);
    632710    $hueNumber=round($hsv['H']/$hue,0);
    633 //echo "*hueNumber:$hueNumber<br>";
    634 
    635 //echo "*H:".$hsv['H']."<br>";
    636 //echo "*S:".$hsv['S']."<br>";
     711    $step=100/(count($colorTable[0])-1);
     712//echo "*H_Step:$hue<br>";
     713//echo "*SV_Step:$step<br>";
     714
     715    $hsv['S']=round((100/$step)*$hsv['S']/100,0)*$step;
     716    $hsv['V']=round((100/$step)*$hsv['V']/100,0)*$step;
     717    $hsv['H']=($hueNumber*$hue)%360;
     718//echo "*H:".$hsv['H']." ";
     719//echo "*S:".$hsv['S']." ";
    637720//echo "*V:".$hsv['V']."<br>";
    638721
    639     if($hsv['V']==0)
    640     {
    641 //echo "-black-<br>";
    642       // black
    643       return(new RGB(0,0,0));
    644     }
    645     elseif($hsv['S']==0 && $hsv['V']==100)
    646     {
    647 //echo "-white-<br>";
    648       // white
    649       return(new RGB(255,255,255));
    650     }
    651     elseif($hsv['S']==0 && $hsv['V']<100 && $hsv['V']>0)
    652     {
    653 //echo "-grey-<br>";
    654       // grey
    655       $stepNumber=round($hsv['V']*($step-1)/100,0);
    656       return($colorTable[count($colorTable)-1][$stepNumber]->getRGB());
    657     }
    658     elseif($hsv['S']==100 && $hsv['V']<100 && $hsv['V']>0)
    659     {
    660 //echo "-value-<br>";
    661       //color 'value'
    662       $stepNumber=round($hsv['V']*$step/400,0);
    663       return($colorTable[$hueNumber][$stepNumber]->getRGB());
    664     }
    665     elseif($hsv['V']==100 && $hsv['S']<100 && $hsv['S']>0)
    666     {
    667 //echo "-saturation-<br>";
    668       //color 'saturation'
    669       $stepNumber=round(($step/4)+(100-$hsv['S'])*($step/400),0);
    670       return($colorTable[$hueNumber][$stepNumber]->getRGB());
    671     }
    672     elseif($hsv['V']==100 && $hsv['S']==100)
    673     {
    674 //echo "-pure-<br>";
    675       //color 'pure'
    676       $stepNumber=$step/4;
    677       return($colorTable[$hueNumber][$stepNumber]->getRGB());
    678     }
    679     elseif(
    680       ($hsv['V']<100 && $hsv['V']>50 && $hsv['S']<50 && $hsv['S']>0) ||
    681       ($hsv['S']<100 && $hsv['S']>50 && $hsv['V']<50 && $hsv['V']>0))
    682     {
    683 //echo "-desaturated 1-<br>";
    684       //color 'desaturated'
    685       $stepNumber=($step/2)+(100-$hsv['V'])*$step/400;
    686       return($colorTable[$hueNumber][$stepNumber]->getRGB());
    687     }
    688     elseif($hsv['V']<100 && $hsv['V']>0 && $hsv['S']<100 && $hsv['S']>0)
    689     {
    690 //echo "-desaturated 2-<br>";
    691       //color 'desaturated'
    692       $stepNumber=($step*0.75)+$hsv['V']*$step/400;
    693       return($colorTable[$hueNumber][$stepNumber]->getRGB());
    694     }
    695 //echo "-none-<br>";
    696     return(new RGB(0,0,0));
     722    if($mode=='RGB')
     723    {
     724      return($colorTable[$hsv['H']][$hsv['S']][$hsv['V']]->getRGB());
     725    }
     726    else
     727    {
     728      return($colorTable[$hsv['H']][$hsv['S']][$hsv['V']]);
     729    }
    697730  }
    698731
Note: See TracChangeset for help on using the changeset viewer.