Skip to content

Commit

Permalink
fix #1 (#29)
Browse files Browse the repository at this point in the history
/intput 画像認識 カラースポイトで文字色を抽出して前処理する機能
  • Loading branch information
usagi authored Oct 8, 2023
1 parent 193e3a9 commit 46ed331
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 22 deletions.
15 changes: 9 additions & 6 deletions input/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
<script type="module" src="/resources/js/input.image.js"></script>

<div class="text">
<input data-vac-input="user" name="content" autocomplete="off" class="content" placeholder=" -> Virtual Avatar Connect">
<input data-vac-input="user" name="content" autocomplete="off" class="content"
placeholder=" -> Virtual Avatar Connect">
<div></div>
<input autocomplete="off" class="channel" placeholder="user" value="user">
<button></button>
Expand Down Expand Up @@ -43,14 +44,16 @@
<label><input autocomplete="off" class="lang" placeholder="jpn" value="jpn"></label>
<a href="https://tesseract-ocr.github.io/tessdoc/Data-Files#data-files-for-version-400-november-29-2016"
target="tesseract/lang-code">🔗lang code</button></a>
<select>
<option value="">(preprocessor:none)</option>
<option value="arknights-story-text">Arknights Story Text</option>
</select>
<div>
<label><input autocomplete="off" class="color-filter" type="checkbox"></label>
<div class="color"></div>
<label><input autocomplete="off" class="tolerance" type="number" min="0" max="255" value="144"></label>
</div>
</div>

<div class="image-result">
<input data-vac-input="user" name="content" autocomplete="off" placeholder="(recognized text here if paste or drop the image.)">
<input data-vac-input="user" name="content" autocomplete="off"
placeholder="(recognized text here if paste or drop the image.)">
<div></div>
<input autocomplete="off" class="channel" placeholder="user" value="user">
<button></button>
Expand Down
23 changes: 23 additions & 0 deletions resources/css/input.css
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,29 @@ div.image label:has(.lang)::before {
content: "認識言語";
}

div.image label:has(.color-filter)::after {
content: "色フィルター";
}

div.image label:has(.tolerance)::before {
content: "±";
margin: 0 0.2em;
}

div.image .color {
width: 2em;
height: 1em;
border: 0.1em solid gray;
background: #fff;
display: inline-block;
vertical-align: sub;
}

div.image .tolerance {
width: 3em;
text-align: center;
}

div.image input.lang {
width: 4em;
text-align: center;
Expand Down
24 changes: 22 additions & 2 deletions resources/js/common/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,34 @@ export function trim_colors(canvas, colors)
ctx.putImageData(image_data, 0, 0);
}

export function pick_color(img, click_event)
{
let click_x = click_event.clientX - img.getBoundingClientRect().left
let click_y = click_event.clientY - img.getBoundingClientRect().top

let pixel_x = Math.floor((click_x / img.clientWidth) * img.naturalWidth)
let pixel_y = Math.floor((click_y / img.clientHeight) * img.naturalHeight)

let canvas = document.createElement('canvas')
canvas.width = img.naturalWidth
canvas.height = img.naturalHeight

let ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight)

window.c = canvas
let data = ctx.getImageData(pixel_x, pixel_y, 1, 1).data

return [...data]
}

// img を編集する:
// - 効果1: colors で与えられた色のピクセルだけを残して、他のピクセルを透明にする
// - 効果2: colors で与えられた色のピクセルの範囲を検出して、その範囲でクロップする
// args:
// img : <img>
// colors: [[r,g,b,d], ...]]
export function extract_colors(img, colors = [[255, 255, 255]])
export function extract_colors(img, colors = [[255, 255, 255, 144]])
{
let canvas = document.createElement('canvas')
canvas.width = img.naturalWidth
Expand All @@ -47,7 +68,6 @@ export function extract_colors(img, colors = [[255, 255, 255]])
Math.abs(data[data_index] - color[0]) <= color[3]
&& Math.abs(data[data_index + 1] - color[1]) <= color[3]
&& Math.abs(data[data_index + 2] - color[2]) <= color[3]
// && data[data_index + 3] === 255

// 上から下へ検索
for (let y = 0; y < height; y++)
Expand Down
69 changes: 55 additions & 14 deletions resources/js/input.image.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import VacApi from './api.js'
import { ISO639_ALPHA3 } from './common/lang_code.js'
import { unorm_to_percent } from './common/number.js'
import { extract_colors } from './common/image.js'
import { extract_colors, pick_color } from './common/image.js'

// v: value of color element, d: delta of color element
let c = (v, d) => [v, v, v, d]

export const ARKNIGHTS_SENARIO_TEXT = { colors: [c(255, 2), c(146, 2)], min_length: 2, confidence_filter: 80 }
const DEFAULT_FILTER_COLOR = [255, 255, 255, 144]

export default class VacInputImage
{
Expand All @@ -22,6 +19,9 @@ export default class VacInputImage
{
this.elements = {}
this.elements.img = root_element.querySelector('img')
this.elements.color_filter = root_element.querySelector('.image .color-filter')
this.elements.color = root_element.querySelector('.image .color')
this.elements.tolerance = root_element.querySelector('.image .tolerance')
this.elements.auto_input = root_element.querySelector('.image .auto-input')
this.elements.continuous = root_element.querySelector('.image .continuous')
this.elements.one_shot = root_element.querySelector('.image .one-shot')
Expand All @@ -39,6 +39,11 @@ export default class VacInputImage
this.elements.lang.addEventListener('change', () => this.lang_changed())
this.elements.lang.addEventListener('keydown', () => this.lang_changed())

this.elements.img.addEventListener('click', e => this.pick_color(e))
this.elements.color_filter.addEventListener('change', () => this.save())
this.elements.color.addEventListener('click', () => this.activate_pick_color())
this.elements.tolerance.addEventListener('change', () => this.input_tolerance())

// paste したら画像を読み込み
document.onpaste = e =>
{
Expand Down Expand Up @@ -83,8 +88,6 @@ export default class VacInputImage
this.image_recognizer()
}
})

this.elements.preprocessor.addEventListener('input', () => this.save())
}

lang_changed()
Expand All @@ -107,7 +110,9 @@ export default class VacInputImage
continuous: this.elements.continuous.checked,
lang: this.elements.lang.value,

preprocessor: this.elements.preprocessor.value
is_enabled_color_filter: this.elements.color_filter.checked,

filter_color: this.filter_color,
}))
}

Expand All @@ -122,8 +127,11 @@ export default class VacInputImage
this.elements.continuous.checked = s.continuous
this.elements.lang.value = s.lang

if (s.preprocessor)
this.elements.preprocessor.value = s.preprocessor
this.elements.color_filter.checked = s.is_enabled_color_filter || false

this.filter_color = s.filter_color || DEFAULT_FILTER_COLOR
this.elements.color.style.backgroundColor = `rgb(${this.filter_color[0]},${this.filter_color[1]},${this.filter_color[2]})`
this.elements.tolerance.value = this.filter_color[3]
}
}

Expand All @@ -139,10 +147,8 @@ export default class VacInputImage
let l = this.elements.lang.value

// pre process
switch (this.elements.preprocessor.value.toLowerCase())
{
case 'arknights-story-text': extract_colors(this.elements.img, ARKNIGHTS_SENARIO_TEXT.colors); break
}
if (this.elements.color_filter.checked)
extract_colors(this.elements.img, [this.filter_color])

// recognize
let r = await Tesseract.recognize(
Expand Down Expand Up @@ -198,6 +204,41 @@ export default class VacInputImage

reader.readAsDataURL(file)
}


filter_color = DEFAULT_FILTER_COLOR
pick_color = e =>
{
if (!this.is_activated_pick_color)
return

this.is_activated_pick_color = false
this.elements.img.style.objectFit = ''
this.elements.img.style.cursor = ''
this.elements.color.style.cursor = ''

let color = pick_color(this.elements.img, e)
this.filter_color = [...color.slice(0, 3), this.filter_color[3]]
this.elements.color.style.backgroundColor = `rgb(${color[0]},${color[1]},${color[2]})`

this.save()
}

is_activated_pick_color = false
activate_pick_color = () =>
{
this.is_activated_pick_color = true
this.elements.img.style.objectFit = 'fill'
this.elements.img.style.cursor = 'crosshair'
this.elements.color.style.cursor = 'crosshair'
}

input_tolerance = () =>
{
this.filter_color[3] = this.elements.tolerance.value
this.save()
}

}

window.VacInputImage = VacInputImage
Expand Down

0 comments on commit 46ed331

Please sign in to comment.