Skip to content

Commit

Permalink
Some minor scanner fixes (#1361)
Browse files Browse the repository at this point in the history
* scanner fixes

* update debug check

* more accurate main stat/set reading
  • Loading branch information
frzyc authored Dec 9, 2023
1 parent ecd37e1 commit 5bf9042
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 74 deletions.
12 changes: 6 additions & 6 deletions apps/frontend/src/app/PageArtifact/ArtifactEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import SubstatInput from './ArtifactEditor/Components/SubstatInput'
import UploadExplainationModal from './ArtifactEditor/Components/UploadExplainationModal'
import { textsFromImage } from './ScanningUtil'
import { LocationAutocomplete } from '../Components/Character/LocationAutocomplete'
import { shouldShowDevComponents } from '../Util/Util'

const allSubstatFilter = new Set(allSubstatKeys)
type ResetMessage = { type: 'reset' }
Expand Down Expand Up @@ -593,12 +594,11 @@ export default function ArtifactEditor({
</Button>
</label>
</Grid>
{process.env.NODE_ENV === 'development' &&
debugImgs && (
<Grid item>
<DebugModal imgs={debugImgs} />
</Grid>
)}
{shouldShowDevComponents && debugImgs && (
<Grid item>
<DebugModal imgs={debugImgs} />
</Grid>
)}
<Grid item>
<Button
color="info"
Expand Down
31 changes: 22 additions & 9 deletions libs/gi-art-scanner/src/lib/findBestArtifact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {
import {
allArtifactRarityKeys,
allArtifactSlotKeys,
artSlotsData,
artSlotMainKeys,
} from '@genshin-optimizer/consts'
import type { IArtifact, ISubstat } from '@genshin-optimizer/gi-good'
import { allStats } from '@genshin-optimizer/gi-stats'
Expand Down Expand Up @@ -54,9 +54,9 @@ export function findBestArtifact(
if (location)
texts.location = detectedText(location, 'Location', (value) => value)

const relevantSetKey = [
...new Set<ArtifactSetKey>([...textSetKeys, 'EmblemOfSeveredFate']),
]
const relevantSetKey: ArtifactSetKey[] = textSetKeys.size
? [...textSetKeys]
: ['EmblemOfSeveredFate']

let bestScore = -1,
bestArtifacts: IArtifact[] = [
Expand Down Expand Up @@ -101,14 +101,16 @@ export function findBestArtifact(

// Test all *probable* combinations
for (const slotKey of allArtifactSlotKeys) {
for (const mainStatKey of artSlotsData[slotKey].stats) {
for (const mainStatKey of artSlotMainKeys[slotKey]) {
const mainStatUnit = unit(mainStatKey)
const mainStatFixed = mainStatUnit === '%' ? 1 : 0
const mainStatOffset = mainStatUnit === '%' ? 0.1 : 1
const mainStatScore =
(slotKeys.has(slotKey) ? 1 : 0) +
(mainStatKeys.has(mainStatKey) ? 1 : 0)
const relevantMainStatValues = mainStatValues
.filter((value) => value.unit !== '%' || unit(mainStatKey) === '%') // Ignore "%" text if key isn't "%"
.map((value) => value.mainStatValue)

for (const [rarityString, rarityIndividualScore] of Object.entries(
rarityRates
)) {
Expand All @@ -124,11 +126,17 @@ export function findBestArtifact(
const values = getMainStatDisplayValues(rarity, mainStatKey)
const level = Math.max(
0,
values.findIndex((level) => level >= minimumMainStatValue)
values.findIndex(
(level) => level + mainStatOffset >= minimumMainStatValue
)
)
const mainStatVal = values[level]
const mainStatValScore =
rarityScore + (mainStatVal === minimumMainStatValue ? 1 : 0)
rarityScore +
(mainStatVal.toFixed(mainStatFixed) ===
minimumMainStatValue.toFixed(mainStatFixed)
? 1
: 0)

for (const setKey of setKeys) {
const score = mainStatValScore + (textSetKeys.has(setKey) ? 1 : 0)
Expand Down Expand Up @@ -314,8 +322,13 @@ export function findBestArtifact(
{unit(result.mainStatKey)}
</>
)
const toFixed = unit(result.mainStatKey) === '%' ? 1 : 0
if (
mainStatValues.find((value) => value.mainStatValue === resultMainStatVal)
mainStatValues.find(
(value) =>
value.mainStatValue.toFixed(toFixed) ===
resultMainStatVal.toFixed(toFixed)
)
) {
if (mainStatKeys.has(result.mainStatKey)) {
texts.level = detectedText(result.level, 'Level', (value) => '+' + value)
Expand Down
63 changes: 35 additions & 28 deletions libs/gi-art-scanner/src/lib/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,58 @@ import type { ISubstat } from '@genshin-optimizer/gi-good'
import { hammingDistance, unit } from '@genshin-optimizer/util'
import { artSlotNames, statMap } from './enStringMap'

/** small utility function used by most string parsing functions below */
export type Ham<T extends string> = [T, number]
export function getBestHamming<T extends string>(hams: Array<Ham<T>>) {
const minHam = Math.min(...hams.map(([, ham]) => ham))
const keys = hams.filter(([, ham]) => ham === minHam).map(([key]) => key)
return new Set(keys)
}

export function parseSetKeys(texts: string[]): Set<ArtifactSetKey> {
const results = new Set<ArtifactSetKey>([])
const hams: Array<Ham<ArtifactSetKey>> = []
for (const text of texts)
for (const key of allArtifactSetKeys)
if (
hams.push([
key,
hammingDistance(
text.replace(/\W/g, ''),
key //TODO: use the translated set name?
) <= 2
)
results.add(key)
return results
),
])
return getBestHamming(hams)
}

export function parseSlotKeys(texts: string[]): Set<ArtifactSlotKey> {
const results = new Set<ArtifactSlotKey>()
const hams: Array<Ham<ArtifactSlotKey>> = []
for (const text of texts)
for (const key of allArtifactSlotKeys)
if (
hams.push([
key,
hammingDistance(
text.replace(/\W/g, ''),
artSlotNames[key].replace(/\W/g, '')
) <= 2
)
results.add(key)
return results
),
])
return getBestHamming(hams)
}
export function parseMainStatKeys(texts: string[]): Set<MainStatKey> {
const results = new Set<MainStatKey>([])
const hams: Array<Ham<MainStatKey>> = []
for (const text of texts)
for (const key of allMainStatKeys) {
if (text.toLowerCase().includes(statMap[key]?.toLowerCase() ?? ''))
results.add(key)
//use fuzzy compare on the ... Bonus texts. heal_ is included.
if (
key.includes('_bonu') &&
hammingDistance(
text.replace(/\W/g, ''),
(statMap[key] ?? '').replace(/\W/g, '')
) <= 1
)
results.add(key)
const statStr = statMap[key]?.toLowerCase()
if (statStr.length <= 3) {
if (text.toLowerCase().includes(statStr ?? '')) hams.push([key, 0])
} else
hams.push([
key,
hammingDistance(
text.replace(/\W/g, ''),
(statMap[key] ?? '').replace(/\W/g, '')
),
])
}
return results
return getBestHamming(hams)
}
export function parseMainStatValues(
texts: string[]
Expand Down Expand Up @@ -108,9 +116,8 @@ export function parseSubstats(texts: string[]): ISubstat[] {
return matches.slice(0, 4)
}

type Ham = [LocationCharacterKey, number]
export function parseLocation(texts: string[]): LocationCharacterKey {
const hams: Array<Ham> = []
const hams: Array<Ham<LocationCharacterKey>> = []
for (let text of texts) {
if (!text) continue
const colonInd = text.indexOf(':')
Expand All @@ -127,7 +134,7 @@ export function parseLocation(texts: string[]): LocationCharacterKey {
])
}
const [key] = hams.reduce(
(accu: Ham, curr: Ham) => {
(accu: Ham<LocationCharacterKey>, curr: Ham<LocationCharacterKey>) => {
const [, val] = accu
const [, curVal] = curr
if (curVal < val) return curr
Expand Down
70 changes: 41 additions & 29 deletions libs/gi-art-scanner/src/lib/processImg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,16 @@ export async function processEntry(
const [goldTitleTop, goldTitleBot] = findHistogramRange(goldTitleHistogram)

const whiteCardHistogram = histogramContAnalysis(
imageData,
artifactCardImageData,
darkerColor(cardWhite),
lighterColor(cardWhite),
false
)
const [whiteCardTop, whiteCardBot] = findHistogramRange(whiteCardHistogram)
const [whiteCardTop, whiteCardBot] = findHistogramRange(
whiteCardHistogram,
0.8,
2
)

const equipHistogram = histogramContAnalysis(
imageData,
Expand All @@ -97,33 +101,7 @@ export async function processEntry(
(i) => i > artifactCardImageData.width * 0.5
)
const [equipTop, equipBot] = findHistogramRange(equipHistogram)
if (debugImgs) {
const canvas = imageDataToCanvas(artifactCardImageData)
drawHistogram(
canvas,
goldTitleHistogram,
{
r: 0,
g: 150,
b: 150,
a: 100,
},
false
)
drawHistogram(
canvas,
whiteCardHistogram,
{ r: 150, g: 0, b: 0, a: 100 },
false
)
drawHistogram(
canvas,
equipHistogram,
{ r: 0, g: 100, b: 100, a: 100 },
false
)
debugImgs['artifactCardAnalysis'] = canvas.toDataURL()
}

const artifactCardCropped = cropHorizontal(
artifactCardCanvas,
goldTitleTop,
Expand Down Expand Up @@ -152,6 +130,40 @@ export async function processEntry(
whiteCardTop
)

if (debugImgs) {
const canvas = imageDataToCanvas(artifactCardImageData)
drawHistogram(
canvas,
goldTitleHistogram,
{
r: 0,
g: 150,
b: 150,
a: 100,
},
false
)

drawHistogram(
canvas,
whiteCardHistogram,
{ r: 150, g: 0, b: 0, a: 100 },
false
)
drawHistogram(canvas, equipHistogram, { r: 0, g: 0, b: 100, a: 100 }, false)

drawline(canvas, goldTitleTop, { r: 0, g: 255, b: 0, a: 200 }, false)
drawline(
canvas,
hasEquip ? equipBot : whiteCardBot,
{ r: 0, g: 0, b: 255, a: 200 },
false
)
drawline(canvas, whiteCardTop, { r: 255, g: 0, b: 200, a: 200 }, false)

debugImgs['artifactCardAnalysis'] = canvas.toDataURL()
}

if (debugImgs)
debugImgs['headerCropped'] = imageDataToCanvas(headerCropped).toDataURL()

Expand Down
2 changes: 1 addition & 1 deletion libs/gi-util/src/artifact/artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export function getMainStatDisplayValues(
statKey: MainStatKey
): number[] {
return allStats.art.main[rarity][statKey].map((k: number) =>
toPercent(k, statKey)
statKey === 'eleMas' ? Math.round(k) : toPercent(k, statKey)
)
}

Expand Down
2 changes: 1 addition & 1 deletion libs/img-util/src/processing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export function findHistogramRange(
const hMax = max * threshold
const length = histogram.length
let a = -window
for (let i = 0; i < histogram.length; i++) {
for (let i = 0; i < length; i++) {
const maxed = histogram[i] > hMax
if (!maxed) a = -window
else if (maxed && a < 0) a = i
Expand Down

0 comments on commit 5bf9042

Please sign in to comment.