Simple but major performance fixes

In particular for level 1 scoring & image loading.
Now that we have a fuller db of images we can be stricker in the range we select.
This commit is contained in:
Ruben van de Ven 2018-11-14 19:00:15 +01:00
parent 7a1dda439e
commit 8b0459c0f6
3 changed files with 85 additions and 65 deletions

View file

@ -30,7 +30,7 @@ class InterfaceControllerProvider implements ControllerProviderInterface
$http_origin = $_SERVER['HTTP_ORIGIN'] ?? null; $http_origin = $_SERVER['HTTP_ORIGIN'] ?? null;
if ($http_origin == "https://emotionhero.com" || $http_origin == "http://emotionhero.com") if ($http_origin == "https://emotionhero.com" || $http_origin == "http://emotionhero.com")
{ {
header("Access-Control-Allow-Origin: $http_origin"); header("Access-Control-Allow-Origin: $http_origin");
// header("Access-Control-Allow-Origin: https://emotionhero.com"); // header("Access-Control-Allow-Origin: https://emotionhero.com");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS"); header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
@ -121,7 +121,7 @@ class InterfaceControllerProvider implements ControllerProviderInterface
$http_origin = $_SERVER['HTTP_ORIGIN'] ?? null; $http_origin = $_SERVER['HTTP_ORIGIN'] ?? null;
if ($http_origin == "https://emotionhero.com" || $http_origin == "http://emotionhero.com") if ($http_origin == "https://emotionhero.com" || $http_origin == "http://emotionhero.com")
{ {
header("Access-Control-Allow-Origin: $http_origin"); header("Access-Control-Allow-Origin: $http_origin");
// header("Access-Control-Allow-Origin: https://emotionhero.com"); // header("Access-Control-Allow-Origin: https://emotionhero.com");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS"); header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
@ -138,7 +138,8 @@ class InterfaceControllerProvider implements ControllerProviderInterface
$hit = $hitRepo->getClosestHitWithImage($emotion, $i); $hit = $hitRepo->getClosestHitWithImage($emotion, $i);
$img = "data:image/x-icon;base64,".$hit->getFeatureImgAsString($feature); $img = "data:image/x-icon;base64,".$hit->getFeatureImgAsString($feature);
$score = $hit->getEmotions()->getEmotionScore($emotion); $score = $hit->getEmotions()->getEmotionScore($emotion);
$percentage = sprintf("%.0f %%",$score); // $percentage = sprintf("%.0f %%",$score);
$percentage = sprintf("%.0f",$score); // use :after to append % character
$blocks[$position] = [ $blocks[$position] = [
'hit_id' => $hit->getId(), 'hit_id' => $hit->getId(),
'img_data' => $img, 'img_data' => $img,

View file

@ -17,6 +17,7 @@ use Doctrine\Common\Collections\ArrayCollection;
* @ORM\Index(name="imgJoy", columns={"hasImage", "joy"}), * @ORM\Index(name="imgJoy", columns={"hasImage", "joy"}),
* @ORM\Index(name="imgSadness", columns={"hasImage", "sadness"}), * @ORM\Index(name="imgSadness", columns={"hasImage", "sadness"}),
* @ORM\Index(name="imgSurprise", columns={"hasImage", "surprise"}), * @ORM\Index(name="imgSurprise", columns={"hasImage", "surprise"}),
* @ORM\Index(name="targetScore", columns={"target", "score"}),
* }) * })
* @ORM\Entity * @ORM\Entity
* @ORM\Entity(repositoryClass="EmotionHero\Models\HitRepository") * @ORM\Entity(repositoryClass="EmotionHero\Models\HitRepository")
@ -190,14 +191,14 @@ class Hit
$this->score = $score; $this->score = $score;
return $this; return $this;
} }
/** /**
* @return boolean * @return boolean
*/ */
public function hasImage() { public function hasImage() {
return (bool) $this->hasImage; return (bool) $this->hasImage;
} }
/** /**
* @param bool $hasImage * @param bool $hasImage
* @return self * @return self
@ -206,9 +207,9 @@ class Hit
$this->hasImage = $hasImage; $this->hasImage = $hasImage;
return $this; return $this;
} }
public static $FEATURES = ['brows','nose','mouth_left','mouth_right']; public static $FEATURES = ['brows','nose','mouth_left','mouth_right'];
/** /**
* @param string $feature * @param string $feature
* @return string|false false if not exists * @return string|false false if not exists
@ -218,11 +219,11 @@ class Hit
if(!in_array($feature, static::$FEATURES)) { if(!in_array($feature, static::$FEATURES)) {
throw new \Exception("Invalid feature!"); throw new \Exception("Invalid feature!");
} }
return realpath(__DIR__ . "/../../files/hits/".$feature) ; return realpath(__DIR__ . "/../../files/hits/".$feature) ;
} }
/** /**
* @param string $feature * @param string $feature
* @return string|false false if not exists * @return string|false false if not exists
@ -230,12 +231,12 @@ class Hit
*/ */
public function getFeatureFilename(string $feature) { public function getFeatureFilename(string $feature) {
$dir = $this->getFeatureDirname($feature); $dir = $this->getFeatureDirname($feature);
return $dir . '/'.$this->getId().'.jpg'; return $dir . '/'.$this->getId().'.jpg';
} }
/** /**
* @param string $feature * @param string $feature
* @return string|null * @return string|null
@ -245,7 +246,7 @@ class Hit
if(!file_exists($filename)) { if(!file_exists($filename)) {
return null; return null;
} }
$contents = file_get_contents($filename); $contents = file_get_contents($filename);
$string = base64_encode($contents); $string = base64_encode($contents);
if ($string === false) { if ($string === false) {
@ -253,7 +254,7 @@ class Hit
} }
return $string; return $string;
} }
} }
@ -802,7 +803,7 @@ class Expressions {
if(in_array($expression, $expressions)) { if(in_array($expression, $expressions)) {
$this->$expression = $value > 100 ? 100 : $value; $this->$expression = $value > 100 ? 100 : $value;
} }
return $this; return $this;
} }
public function getExpressionScore(string $expression){ public function getExpressionScore(string $expression){
@ -816,7 +817,7 @@ class Expressions {
/** /**
* Get difference between two expressions objects * Get difference between two expressions objects
* Get only for those that can be used in 2nd person * Get only for those that can be used in 2nd person
* *
* @param Expressions $expressions To compare wiht * @param Expressions $expressions To compare wiht
* @return array Key: expression, value, diff * @return array Key: expression, value, diff
*/ */
@ -827,7 +828,7 @@ class Expressions {
} }
return $diffs; return $diffs;
} }
/** /**
* @param string $expression * @param string $expression
* @return string * @return string
@ -912,29 +913,29 @@ class Points{
/** @ORM\Embedded(class="Point", columnPrefix="point_33") @JMS\SerializedName("33") */ /** @ORM\Embedded(class="Point", columnPrefix="point_33") @JMS\SerializedName("33") */
private $point33; private $point33;
/* /*
* A full list of facial landmarks from Affectiva docs * A full list of facial landmarks from Affectiva docs
* http://developer.affectiva.com/fpi/ * http://developer.affectiva.com/fpi/
* *
* 0 Right Top Jaw * 0 Right Top Jaw
* 1 Right Jaw Angle * 1 Right Jaw Angle
* 2 Tip of Chin * 2 Tip of Chin
* 3 Left Jaw Angle * 3 Left Jaw Angle
* 4 Left Top Jaw * 4 Left Top Jaw
* 5 Outer Right Brow Corner * 5 Outer Right Brow Corner
* 6 Right Brow Center * 6 Right Brow Center
* 7 Inner Right Brow Corner * 7 Inner Right Brow Corner
* 8 Inner Left Brow Corner * 8 Inner Left Brow Corner
* 9 Left Brow Center * 9 Left Brow Center
* 10 Outer Left Brow Corner * 10 Outer Left Brow Corner
* 11 Nose Root * 11 Nose Root
* 12 Nose Tip * 12 Nose Tip
* 13 Nose Lower Right Boundary * 13 Nose Lower Right Boundary
* 14 Nose Bottom Boundary * 14 Nose Bottom Boundary
* 15 Nose Lower Left Boundary * 15 Nose Lower Left Boundary
* 16 Outer Right Eye * 16 Outer Right Eye
* 17 Inner Right Eye * 17 Inner Right Eye
* 18 Inner Left Eye * 18 Inner Left Eye
* 19 Outer Left Eye * 19 Outer Left Eye
@ -951,9 +952,9 @@ class Points{
* 30 Upper Corner Right Eye * 30 Upper Corner Right Eye
* 31 Lower Corner Right Eye * 31 Lower Corner Right Eye
* 32 Upper Corner Left Eye * 32 Upper Corner Left Eye
* 33 Lower Corner Left Eye * 33 Lower Corner Left Eye
*/ */
/** /**
* Gets the value of point_0y. * Gets the value of point_0y.
@ -1300,9 +1301,9 @@ class Points{
$this->{"point".$nr} = new Point($x, $y); $this->{"point".$nr} = new Point($x, $y);
} }
return $this; return $this;
} }
/** /**
* @return array[Point] * @return array[Point]
*/ */
@ -1313,7 +1314,7 @@ class Points{
} }
return $points; return $points;
} }
/** /**
* Fits points within a 100x100 scale * Fits points within a 100x100 scale
* @return array[Point] * @return array[Point]
@ -1325,13 +1326,13 @@ class Points{
$minx = min($xs); $minx = min($xs);
$maxx = max($xs); $maxx = max($xs);
$miny = min($ys); $miny = min($ys);
$maxy = max($ys); $maxy = max($ys);
$sizex = $maxx-$minx; $sizex = $maxx-$minx;
$sizey = $maxy-$miny; $sizey = $maxy-$miny;
$scale = max($sizex, $sizey); // divide by largest diff. $scale = max($sizex, $sizey); // divide by largest diff.
//used to center the face within the square: //used to center the face within the square:
@ -1342,10 +1343,10 @@ class Points{
foreach($points as $i => $point) { foreach($points as $i => $point) {
$x = (($point->getX() - $minx) / $scale) * 100 + $diffx; $x = (($point->getX() - $minx) / $scale) * 100 + $diffx;
$y = (($point->getY() - $miny) / $scale) * 100 + $diffy; $y = (($point->getY() - $miny) / $scale) * 100 + $diffy;
$normalised_points[$i] = new Point($x, $y); $normalised_points[$i] = new Point($x, $y);
} }
return $normalised_points; return $normalised_points;
} }
} }
@ -1363,25 +1364,25 @@ class Point{
* @var float Facial landmark * @var float Facial landmark
* @ORM\Column(type="float") * @ORM\Column(type="float")
*/ */
private $y; private $y;
public function __construct($x, $y) public function __construct($x, $y)
{ {
$this->x = $x; $this->x = $x;
$this->y = $y; $this->y = $y;
} }
/** /**
* @return float * @return float
*/ */
public function getX() { public function getX() {
return $this->x; return $this->x;
} }
/** /**
* @return float * @return float
*/ */
public function getY() { public function getY() {
return $this->y; return $this->y;
} }
} }

View file

@ -7,27 +7,41 @@ use EmotionHero\Tools\Position;
class HitRepository extends EntityRepository class HitRepository extends EntityRepository
{ {
/** /**
* *
* @param \EmotionHero\Models\Hit $hit * @param \EmotionHero\Models\Hit $hit
* @return Hit The hit that is considered better than the given one (used for hints) * @return Hit The hit that is considered better than the given one (used for hints)
*/ */
public function getBetterHit(Hit $hit) { public function getBetterHit(Hit $hit) {
// we want only the slightly better hit... $targets = $this->getTargetSetForTarget($hit->getTarget());
$query = $this->_em->createQuery( if(count($targets) > 1) {
"SELECT h, SUM(h.score) as HIDDEN totalScore FROM ".Hit::class." h WHERE h.target IN (:targets) GROUP BY h.game HAVING totalScore > :score ORDER BY totalScore DESC" // we want only the slightly better hit...
) $query = $this->_em->createQuery(
->setMaxResults(1) "SELECT h, SUM(h.score) as HIDDEN totalScore FROM ".Hit::class." h WHERE h.target IN (:targets) GROUP BY h.game HAVING totalScore > :score ORDER BY totalScore DESC"
->setParameters([ )
'score' => $this->getTotalScoreForHit($hit), ->setMaxResults(1)
'targets' => $this->getTargetSetForTarget($hit->getTarget()), ->setParameters([
]); 'score' => $this->getTotalScoreForHit($hit),
$betterHit = $query->getOneOrNullResult(); 'targets' => $targets,
]);
$betterHit = $query->getOneOrNullResult();
} else { // run a faster query if there's just on target (no grouping needed)
// we want only the slightly better hit...
$query = $this->_em->createQuery(
"SELECT h FROM ".Hit::class." h WHERE h.target = :target AND h.score > :score ORDER BY h.score DESC"
)
->setMaxResults(1)
->setParameters([
'score' => $this->getTotalScoreForHit($hit),
'target' => array_shift($targets),
]);
$betterHit = $query->getOneOrNullResult();
}
return $betterHit; return $betterHit;
} }
/** /**
* *
* @param string $emotionField * @param string $emotionField
* @param float $score * @param float $score
* @return Hit * @return Hit
@ -38,12 +52,16 @@ class HitRepository extends EntityRepository
throw new \Exception("Invalid emotion!"); throw new \Exception("Invalid emotion!");
} }
$scoreMin = $score < 0.1 ? 0 : $score - 0.3;
$scoreMax = $score < 0.1 ? 0 : $score + 0.3;
$query = $this->_em->createQuery( $query = $this->_em->createQuery(
// add BETWEEN so we can use _some_ keying to improve performance. // add BETWEEN so we can use _some_ keying to improve performance.
"SELECT h, ABS(:score - h.emotions.$emotionField) as HIDDEN distance, RAND() AS HIDDEN lala FROM ".Hit::class." h WHERE h.hasImage = :has AND h.emotions.$emotionField BETWEEN :score - 2 AND :score + 2 ORDER BY distance ASC, lala" "SELECT h, ABS(:score - h.emotions.$emotionField) as HIDDEN distance, RAND() AS HIDDEN lala FROM ".Hit::class." h WHERE h.hasImage = :has AND h.emotions.$emotionField BETWEEN :score_min AND :score_max ORDER BY distance ASC, lala"
) )
->setParameters([ ->setParameters([
'score' => $score, 'score' => $score,
'score_min' => $scoreMin,
'score_max' => $scoreMax,
'has' => true, 'has' => true,
]) ])
->setMaxResults(1); ->setMaxResults(1);
@ -84,4 +102,4 @@ class HitRepository extends EntityRepository
]) ])
->getSingleScalarResult(); ->getSingleScalarResult();
} }
} }