From 0bff1a979d8571a7468f3fea4a1a9343c20a979d Mon Sep 17 00:00:00 2001 From: nahojjjen Date: Sat, 20 Oct 2018 14:39:10 +0200 Subject: [PATCH 1/5] Only scan moveset on full-scan --- .../pokeflycomponents/ocrhelper/OcrHelper.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java index 6be45cc95..79a225944 100644 --- a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java +++ b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java @@ -4,6 +4,7 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Rect; +import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.Pair; @@ -24,6 +25,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.Map; +import java.util.stream.IntStream; import timber.log.Timber; @@ -1084,10 +1086,14 @@ public ScanData scanPokemon(@NonNull GoIVSettings settings, } Optional evolutionCost = getPokemonEvolutionCostFromImg(pokemonImage, ScanArea.calibratedFromSettings(POKEMON_EVOLUTION_COST_AREA, settings, luckyOffset)); - Pair moveset = getMovesetFromImg(pokemonImage, - estimatedLevelRange, - ScanArea.calibratedFromSettings(POKEMON_POWER_UP_CANDY_COST, settings, luckyOffset), - ScanArea.calibratedFromSettings(POKEMON_EVOLUTION_COST_AREA, settings, luckyOffset)); + Pair moveset = null; + if (requestFullScan){ + moveset = getMovesetFromImg(pokemonImage, + estimatedLevelRange, + ScanArea.calibratedFromSettings(POKEMON_POWER_UP_CANDY_COST, settings, luckyOffset), + ScanArea.calibratedFromSettings(POKEMON_EVOLUTION_COST_AREA, settings, luckyOffset)); + } + String moveFast = null; String moveCharge = null; if (moveset != null) { From 77b739c41e8f4af22defdd2aac8c5de7fa6c2821 Mon Sep 17 00:00:00 2001 From: nahojjjen Date: Sat, 20 Oct 2018 14:40:05 +0200 Subject: [PATCH 2/5] Makes moveset replaceColor parallel --- .../ocrhelper/OcrHelper.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java index 79a225944..4160c79b2 100644 --- a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java +++ b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java @@ -177,6 +177,27 @@ private static Bitmap replaceColors(Bitmap srcBitmap, boolean mutateSrc, Color.RGBToHSV(r, g, b, targetHsv); float[] currentHsv = new float[3]; + + + //Use parallel loop if user is on android N or above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + IntStream.range(0, allPixels.length).parallel().forEach(i ->{ + if (allPixels[i] == bgColor) { + //Do nothing + } else{ + Color.colorToHSV(allPixels[i], currentHsv); + if (dH != null && Math.abs(targetHsv[0] - currentHsv[0]) > dH) { // Check hue + allPixels[i] = bgColor; + + } else if (dS != null && Math.abs(targetHsv[1] - currentHsv[1]) > dS) { // Check saturation + allPixels[i] = bgColor; + + } else if (dV != null && Math.abs(targetHsv[2] - currentHsv[2]) > dV) { // Check value + allPixels[i] = bgColor; + } + } + }); + } for (int i = 0; i < allPixels.length; i++) { if (allPixels[i] == bgColor) { continue; From c4e30c574f97dd85f83f68613b763c26f17fccb0 Mon Sep 17 00:00:00 2001 From: nahojjjen Date: Sat, 20 Oct 2018 15:04:04 +0200 Subject: [PATCH 3/5] Removes normalizedPokemonNameMap that took 2 seconds to create Every time someone pressed the IV button, the inputfraction created a new normalizedPokemonMap - which took 2 seconds on my samsung s7. And it's only used in the very rare case that the user wants to manually type in the pokemon name in the dropdown. This changes to an alternate implementation where it uses levenshteinDistance to just pick whatever pokemon name is closest instead. Functionally the same as far as the user can tell, but takes 2 seconds less time to load. --- .../fractions/InputFraction.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java index ad679ef1b..6e04066bb 100644 --- a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java +++ b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java @@ -74,16 +74,12 @@ public class InputFraction extends Fraction { private Pokefly pokefly; private PokeInfoCalculator pokeInfoCalculator; - private final Map normalizedPokemonNameMap; public InputFraction(@NonNull Pokefly pokefly) { this.pokefly = pokefly; this.pokeInfoCalculator = PokeInfoCalculator.getInstance(); - Map pokemap = new HashMap<>(); - for (Pokemon pokemon : pokeInfoCalculator.getPokedex()) { - pokemap.put(StringUtils.normalize(pokemon.toString()), pokemon); // set display pokemon name as key - } - this.normalizedPokemonNameMap = pokemap; + + } @Override public int getLayoutResId() { @@ -294,13 +290,20 @@ public String apply(T input) { */ private Pokemon interpretWhichPokemonUserInput() { //below picks a pokemon from either the pokemon spinner or the user text input - Pokemon pokemon; + Pokemon pokemon = null; if (pokeInputSpinner.getVisibility() == View.VISIBLE) { //user picked pokemon from spinner //This could be pokemon = pokeInputSpinner.getSelectedItem(); if they didn't give it type Object. pokemon = pokeInputAdapter.getItem(pokeInputSpinner.getSelectedItemPosition()); } else { //user typed manually String userInput = autoCompleteTextView1.getText().toString(); - pokemon = normalizedPokemonNameMap.get(StringUtils.normalize(userInput)); + int lowestDist = Integer.MAX_VALUE; + for (Pokemon poke : pokeInfoCalculator.getPokedex()){ + int dist = Data.levenshteinDistance(poke.name, userInput); + if (dist < lowestDist){ + lowestDist = dist; + pokemon = poke; + } + } if (pokemon == null) { //no such pokemon was found, show error toast and abort showing results Toast.makeText(pokefly, userInput + pokefly.getString(R.string.wrong_pokemon_name_input), Toast.LENGTH_SHORT).show(); From 4df22f377c4cd76877886be1136c1bec87c48f1b Mon Sep 17 00:00:00 2001 From: nahojjjen Date: Sat, 20 Oct 2018 15:25:25 +0200 Subject: [PATCH 4/5] movesetscan uses normal replaceColor method that is x200 faster It was using a replacecolor method which coverted each pixel in the bitmap to a HSV pixel, which cost a lot of performance. Approxemately the same result could be achieved by using the normal replaceColor method with finely tuned parameters. --- .../ocrhelper/OcrHelper.java | 67 +------------------ 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java index 4160c79b2..df9c376c4 100644 --- a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java +++ b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java @@ -160,71 +160,6 @@ private static Bitmap replaceColors(Bitmap srcBitmap, boolean mutateSrc, int kee return dstBitmap; } - private static Bitmap replaceColors(Bitmap srcBitmap, boolean mutateSrc, - int r, int g, int b, @Nullable Integer replaceColor, - @Nullable Float dH, @Nullable Float dS, @Nullable Float dV) { - int[] allPixels = new int[srcBitmap.getHeight() * srcBitmap.getWidth()]; - srcBitmap.getPixels(allPixels, 0, srcBitmap.getWidth(), 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight()); - - final int bgColor; - if (replaceColor != null) { - bgColor = replaceColor; - } else { - bgColor = allPixels[0]; // Sample the top left color to use as background - } - - float[] targetHsv = new float[3]; - Color.RGBToHSV(r, g, b, targetHsv); - - float[] currentHsv = new float[3]; - - - //Use parallel loop if user is on android N or above - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - IntStream.range(0, allPixels.length).parallel().forEach(i ->{ - if (allPixels[i] == bgColor) { - //Do nothing - } else{ - Color.colorToHSV(allPixels[i], currentHsv); - if (dH != null && Math.abs(targetHsv[0] - currentHsv[0]) > dH) { // Check hue - allPixels[i] = bgColor; - - } else if (dS != null && Math.abs(targetHsv[1] - currentHsv[1]) > dS) { // Check saturation - allPixels[i] = bgColor; - - } else if (dV != null && Math.abs(targetHsv[2] - currentHsv[2]) > dV) { // Check value - allPixels[i] = bgColor; - } - } - }); - } - for (int i = 0; i < allPixels.length; i++) { - if (allPixels[i] == bgColor) { - continue; - } - - Color.colorToHSV(allPixels[i], currentHsv); - - if (dH != null && Math.abs(targetHsv[0] - currentHsv[0]) > dH) { // Check hue - allPixels[i] = bgColor; - - } else if (dS != null && Math.abs(targetHsv[1] - currentHsv[1]) > dS) { // Check saturation - allPixels[i] = bgColor; - - } else if (dV != null && Math.abs(targetHsv[2] - currentHsv[2]) > dV) { // Check value - allPixels[i] = bgColor; - } - } - - Bitmap dstBitmap; - if (mutateSrc) { - dstBitmap = srcBitmap; - } else { - dstBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig()); - } - dstBitmap.setPixels(allPixels, 0, srcBitmap.getWidth(), 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight()); - return dstBitmap; - } /** * Scans the arc and tries to determine the pokemon level, returns 1 if nothing found. @@ -447,7 +382,7 @@ private static Optional getPokemonEvolutionCostFromImg(@NonNull Bitmap } } - movesetImage = replaceColors(movesetImage, true, 68, 105, 108, null, 3f, null, 0.1f); + movesetImage = replaceColors(movesetImage, true, 68, 105, 108, Color.BLACK, 50, false); tesseract.setImage(movesetImage); tesseract.setPageSegMode(TessBaseAPI.PageSegMode.PSM_SINGLE_BLOCK); From 97f3d63dd4b36cce526a3a8f8c1c0865920954e6 Mon Sep 17 00:00:00 2001 From: nahojjjen Date: Sat, 20 Oct 2018 18:44:43 +0200 Subject: [PATCH 5/5] Auto reformat code --- .../pokeflycomponents/fractions/InputFraction.java | 9 +++------ .../pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java | 4 +--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java index 6e04066bb..dd7d05724 100644 --- a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java +++ b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/fractions/InputFraction.java @@ -27,13 +27,10 @@ import com.kamron.pogoiv.scanlogic.Pokemon; import com.kamron.pogoiv.scanlogic.PokemonNameCorrector; import com.kamron.pogoiv.utils.LevelRange; -import com.kamron.pogoiv.utils.StringUtils; import com.kamron.pogoiv.utils.fractions.Fraction; import com.kamron.pogoiv.widgets.PokemonSpinnerAdapter; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; import butterknife.BindView; import butterknife.ButterKnife; @@ -297,9 +294,9 @@ private Pokemon interpretWhichPokemonUserInput() { } else { //user typed manually String userInput = autoCompleteTextView1.getText().toString(); int lowestDist = Integer.MAX_VALUE; - for (Pokemon poke : pokeInfoCalculator.getPokedex()){ - int dist = Data.levenshteinDistance(poke.name, userInput); - if (dist < lowestDist){ + for (Pokemon poke : pokeInfoCalculator.getPokedex()) { + int dist = Data.levenshteinDistance(poke.name, userInput); + if (dist < lowestDist) { lowestDist = dist; pokemon = poke; } diff --git a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java index df9c376c4..01851e08d 100644 --- a/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java +++ b/app/src/main/java/com/kamron/pogoiv/pokeflycomponents/ocrhelper/OcrHelper.java @@ -4,7 +4,6 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Rect; -import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.Pair; @@ -25,7 +24,6 @@ import java.util.Arrays; import java.util.Iterator; import java.util.Map; -import java.util.stream.IntStream; import timber.log.Timber; @@ -1043,7 +1041,7 @@ public ScanData scanPokemon(@NonNull GoIVSettings settings, Optional evolutionCost = getPokemonEvolutionCostFromImg(pokemonImage, ScanArea.calibratedFromSettings(POKEMON_EVOLUTION_COST_AREA, settings, luckyOffset)); Pair moveset = null; - if (requestFullScan){ + if (requestFullScan) { moveset = getMovesetFromImg(pokemonImage, estimatedLevelRange, ScanArea.calibratedFromSettings(POKEMON_POWER_UP_CANDY_COST, settings, luckyOffset),