Improve OCR preprocessing and normalize merchant names
This commit is contained in:
+1
-1
@@ -78,7 +78,7 @@ export function parseStoreHeaderText(text) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
side: match[1].toLowerCase(),
|
side: match[1].toLowerCase(),
|
||||||
merchant: match[2].trim(),
|
merchant: match[2].replace(/\s+/g, ""),
|
||||||
rawText: normalized,
|
rawText: normalized,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-1
@@ -4,6 +4,16 @@ import { normalizeOcrText } from "./parser.js";
|
|||||||
let cvPromise;
|
let cvPromise;
|
||||||
let workerPromise;
|
let workerPromise;
|
||||||
let progressListener = () => {};
|
let progressListener = () => {};
|
||||||
|
const WHITE_TEXT_MIN_CHANNEL = 150;
|
||||||
|
const WHITE_TEXT_MAX_SPREAD = 55;
|
||||||
|
|
||||||
|
export function isWhiteTextPixel(red, green, blue, alpha = 255) {
|
||||||
|
return (
|
||||||
|
alpha >= 128 &&
|
||||||
|
Math.min(red, green, blue) >= WHITE_TEXT_MIN_CHANNEL &&
|
||||||
|
Math.max(red, green, blue) - Math.min(red, green, blue) <= WHITE_TEXT_MAX_SPREAD
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function onOcrProgress(listener) {
|
export function onOcrProgress(listener) {
|
||||||
progressListener = listener;
|
progressListener = listener;
|
||||||
@@ -79,7 +89,6 @@ function prepareOcrCrop(sourceCanvas, rect) {
|
|||||||
|
|
||||||
const context = canvas.getContext("2d", { willReadFrequently: true });
|
const context = canvas.getContext("2d", { willReadFrequently: true });
|
||||||
context.imageSmoothingEnabled = false;
|
context.imageSmoothingEnabled = false;
|
||||||
context.filter = "grayscale(1) contrast(2)";
|
|
||||||
context.drawImage(
|
context.drawImage(
|
||||||
sourceCanvas,
|
sourceCanvas,
|
||||||
rect.x,
|
rect.x,
|
||||||
@@ -92,6 +101,23 @@ function prepareOcrCrop(sourceCanvas, rect) {
|
|||||||
canvas.height,
|
canvas.height,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const image = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
for (let index = 0; index < image.data.length; index += 4) {
|
||||||
|
const value = isWhiteTextPixel(
|
||||||
|
image.data[index],
|
||||||
|
image.data[index + 1],
|
||||||
|
image.data[index + 2],
|
||||||
|
image.data[index + 3],
|
||||||
|
)
|
||||||
|
? 0
|
||||||
|
: 255;
|
||||||
|
image.data[index] = value;
|
||||||
|
image.data[index + 1] = value;
|
||||||
|
image.data[index + 2] = value;
|
||||||
|
image.data[index + 3] = 255;
|
||||||
|
}
|
||||||
|
context.putImageData(image, 0, 0);
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ import {
|
|||||||
rectFromPoints,
|
rectFromPoints,
|
||||||
resolveFieldRect,
|
resolveFieldRect,
|
||||||
} from "../src/parser.js";
|
} from "../src/parser.js";
|
||||||
|
import { isWhiteTextPixel } from "../src/vision.js";
|
||||||
|
|
||||||
|
test("keeps white text pixels and removes colored or dark pixels", () => {
|
||||||
|
assert.equal(isWhiteTextPixel(220, 215, 195), true);
|
||||||
|
assert.equal(isWhiteTextPixel(210, 165, 80), false);
|
||||||
|
assert.equal(isWhiteTextPixel(120, 120, 120), false);
|
||||||
|
});
|
||||||
|
|
||||||
test("keeps only letters, digits and spaces in OCR item names", () => {
|
test("keeps only letters, digits and spaces in OCR item names", () => {
|
||||||
assert.equal(cleanItemName(" ~~ Soulshot: S-grade ` "), "Soulshot S grade");
|
assert.equal(cleanItemName(" ~~ Soulshot: S-grade ` "), "Soulshot S grade");
|
||||||
@@ -139,5 +146,6 @@ test("parses trade side and merchant from the store header", () => {
|
|||||||
merchant: "Dwa",
|
merchant: "Dwa",
|
||||||
rawText: "Private Store({Sell) - Dwa",
|
rawText: "Private Store({Sell) - Dwa",
|
||||||
});
|
});
|
||||||
|
assert.equal(parseStoreHeaderText("Private Store(Buy) - Hik vision")?.merchant, "Hikvision");
|
||||||
assert.equal(parseStoreHeaderText("Items on Sale"), null);
|
assert.equal(parseStoreHeaderText("Items on Sale"), null);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user