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:
parent
7a1dda439e
commit
8b0459c0f6
3 changed files with 85 additions and 65 deletions
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue