edge_det 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,238 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import * as PImage from 'pureimage'
3
- import { detectBorders, detectBordersDefault, Border } from '../src_ts/index'
4
-
5
- function createImage(
6
- w: number,
7
- h: number,
8
- draw: (ctx: PImage.Context) => void
9
- ): Uint8Array {
10
- const img = PImage.make(w, h, {})
11
- const ctx = img.getContext('2d')
12
- ctx.fillStyle = '#ffffff'
13
- ctx.fillRect(0, 0, w, h)
14
- draw(ctx)
15
- const buf = img.data
16
- const rgba = new Uint8Array(w * h * 4)
17
- for (let i = 0; i < w * h; i++) {
18
- rgba[i * 4] = buf[i * 4]
19
- rgba[i * 4 + 1] = buf[i * 4 + 1]
20
- rgba[i * 4 + 2] = buf[i * 4 + 2]
21
- rgba[i * 4 + 3] = buf[i * 4 + 3]
22
- }
23
- return rgba
24
- }
25
-
26
- function drawRect(
27
- ctx: PImage.Context,
28
- x: number,
29
- y: number,
30
- w: number,
31
- h: number,
32
- color: string,
33
- lineWidth?: number
34
- ) {
35
- ctx.strokeStyle = color
36
- ctx.lineWidth = lineWidth ?? 1
37
- ctx.strokeRect(x, y, w, h)
38
- }
39
-
40
- function fillRect(
41
- ctx: PImage.Context,
42
- x: number,
43
- y: number,
44
- w: number,
45
- h: number,
46
- color: string
47
- ) {
48
- ctx.fillStyle = color
49
- ctx.fillRect(x, y, w, h)
50
- }
51
-
52
- function mergeBounds(borders: Border[]) {
53
- const m = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }
54
- for (const b of borders) {
55
- m.x = Math.min(m.x, b.x)
56
- m.y = Math.min(m.y, b.y)
57
- m.x2 = Math.max(m.x2, b.x + b.w)
58
- m.y2 = Math.max(m.y2, b.y + b.h)
59
- }
60
- return m
61
- }
62
-
63
- function areaOf(b: Border) {
64
- return b.w * b.h
65
- }
66
-
67
- function coverage(borders: Border[], expected: { x: number; y: number; w: number; h: number }) {
68
- const merged = mergeBounds(borders)
69
- const ex = expected.x
70
- const ey = expected.y
71
- const ex2 = expected.x + expected.w
72
- const ey2 = expected.y + expected.h
73
- const iw = Math.max(0, Math.min(merged.x2, ex2) - Math.max(merged.x, ex))
74
- const ih = Math.max(0, Math.min(merged.y2, ey2) - Math.max(merged.y, ey))
75
- const inter = iw * ih
76
- const unionArea = (merged.x2 - merged.x) * (merged.y2 - merged.y) + expected.w * expected.h - inter
77
- return inter / unionArea
78
- }
79
-
80
- const TOL = 6
81
-
82
- describe('detectBorders', () => {
83
- it('solid color → no borders', () => {
84
- const w = 80, h = 80
85
- const data = createImage(w, h, () => {})
86
- const borders = detectBorders(data, w, h)
87
- expect(borders.length).toBe(0)
88
- })
89
-
90
- it('white bg + gray filled rect (low contrast)', () => {
91
- const w = 200, h = 200
92
- const rect = { x: 30, y: 40, w: 80, h: 60 }
93
- const data = createImage(w, h, (ctx) => {
94
- fillRect(ctx, rect.x, rect.y, rect.w, rect.h, '#cccccc')
95
- })
96
- const borders = detectBorders(data, w, h, {
97
- lowThreshold: 8,
98
- highThreshold: 25,
99
- minArea: 20,
100
- })
101
- expect(borders.length).toBeGreaterThanOrEqual(1)
102
- const merged = mergeBounds(borders)
103
- expect(merged.x).toBeLessThanOrEqual(rect.x + TOL)
104
- expect(merged.y).toBeLessThanOrEqual(rect.y + TOL)
105
- expect(merged.x2).toBeGreaterThanOrEqual(rect.x + rect.w - TOL)
106
- expect(merged.y2).toBeGreaterThanOrEqual(rect.y + rect.h - TOL)
107
- })
108
-
109
- it('white bg + thin black 1px line rect', () => {
110
- const w = 200, h = 200
111
- const rect = { x: 20, y: 20, w: 100, h: 80 }
112
- const data = createImage(w, h, (ctx) => {
113
- drawRect(ctx, rect.x, rect.y, rect.w, rect.h, '#000000', 1)
114
- })
115
- const borders = detectBorders(data, w, h, {
116
- lowThreshold: 15,
117
- highThreshold: 45,
118
- minArea: 10,
119
- })
120
- expect(borders.length).toBeGreaterThanOrEqual(1)
121
- const merged = mergeBounds(borders)
122
- expect(merged.x).toBeLessThanOrEqual(rect.x + TOL)
123
- expect(merged.y).toBeLessThanOrEqual(rect.y + TOL)
124
- expect(merged.x2).toBeGreaterThanOrEqual(rect.x + rect.w - TOL)
125
- expect(merged.y2).toBeGreaterThanOrEqual(rect.y + rect.h - TOL)
126
- })
127
-
128
- it('white bg + thin black 2px line rect', () => {
129
- const w = 200, h = 200
130
- const rect = { x: 50, y: 30, w: 100, h: 120 }
131
- const data = createImage(w, h, (ctx) => {
132
- drawRect(ctx, rect.x, rect.y, rect.w, rect.h, '#000000', 2)
133
- })
134
- const borders = detectBorders(data, w, h, {
135
- lowThreshold: 15,
136
- highThreshold: 45,
137
- minArea: 10,
138
- })
139
- expect(borders.length).toBeGreaterThanOrEqual(1)
140
- const merged = mergeBounds(borders)
141
- expect(merged.x).toBeLessThanOrEqual(rect.x + TOL)
142
- expect(merged.y).toBeLessThanOrEqual(rect.y + TOL)
143
- expect(merged.x2).toBeGreaterThanOrEqual(rect.x + rect.w - TOL)
144
- expect(merged.y2).toBeGreaterThanOrEqual(rect.y + rect.h - TOL)
145
- })
146
-
147
- it('white bg + gray thin line rect (low contrast + thin)', () => {
148
- const w = 200, h = 200
149
- const rect = { x: 25, y: 25, w: 100, h: 100 }
150
- const data = createImage(w, h, (ctx) => {
151
- drawRect(ctx, rect.x, rect.y, rect.w, rect.h, '#999999', 1)
152
- })
153
- const borders = detectBorders(data, w, h, {
154
- lowThreshold: 5,
155
- highThreshold: 18,
156
- minArea: 10,
157
- })
158
- expect(borders.length).toBeGreaterThanOrEqual(1)
159
- const merged = mergeBounds(borders)
160
- expect(merged.x).toBeLessThanOrEqual(rect.x + TOL)
161
- expect(merged.y).toBeLessThanOrEqual(rect.y + TOL)
162
- expect(merged.x2).toBeGreaterThanOrEqual(rect.x + rect.w - TOL)
163
- expect(merged.y2).toBeGreaterThanOrEqual(rect.y + rect.h - TOL)
164
- })
165
-
166
- it('blue rect on gray bg (color)', () => {
167
- const w = 200, h = 200
168
- const rect = { x: 40, y: 30, w: 80, h: 60 }
169
- const data = createImage(w, h, (ctx) => {
170
- fillRect(ctx, 0, 0, w, h, '#555555')
171
- fillRect(ctx, rect.x, rect.y, rect.w, rect.h, '#0088ff')
172
- })
173
- const borders = detectBorders(data, w, h, {
174
- lowThreshold: 12,
175
- highThreshold: 35,
176
- minArea: 20,
177
- })
178
- expect(borders.length).toBeGreaterThanOrEqual(1)
179
- const merged = mergeBounds(borders)
180
- expect(merged.x).toBeLessThanOrEqual(rect.x + TOL)
181
- expect(merged.y).toBeLessThanOrEqual(rect.y + TOL)
182
- expect(merged.x2).toBeGreaterThanOrEqual(rect.x + rect.w - TOL)
183
- expect(merged.y2).toBeGreaterThanOrEqual(rect.y + rect.h - TOL)
184
- })
185
-
186
- it('two rects — count and area', () => {
187
- const w = 300, h = 300
188
- const r1 = { x: 20, y: 20, w: 60, h: 60 }
189
- const r2 = { x: 150, y: 120, w: 100, h: 80 }
190
- const data = createImage(w, h, (ctx) => {
191
- fillRect(ctx, r1.x, r1.y, r1.w, r1.h, '#cccccc')
192
- fillRect(ctx, r2.x, r2.y, r2.w, r2.h, '#cccccc')
193
- })
194
- const borders = detectBorders(data, w, h, {
195
- lowThreshold: 8,
196
- highThreshold: 25,
197
- minArea: 20,
198
- })
199
- expect(borders.length).toBe(2)
200
- const areas = borders.map(areaOf).sort((a, b) => a - b)
201
- const expectedAreas = [r1.w * r1.h, r2.w * r2.h].sort((a, b) => a - b)
202
- for (let i = 0; i < 2; i++) {
203
- expect(areas[i]).toBeGreaterThan(expectedAreas[i] * 0.5)
204
- expect(areas[i]).toBeLessThan(expectedAreas[i] * 2.5)
205
- }
206
- })
207
-
208
- it('two thin-line rects — count and area', () => {
209
- const w = 300, h = 300
210
- const r1 = { x: 20, y: 20, w: 80, h: 60 }
211
- const r2 = { x: 160, y: 100, w: 100, h: 80 }
212
- const data = createImage(w, h, (ctx) => {
213
- drawRect(ctx, r1.x, r1.y, r1.w, r1.h, '#000000', 2)
214
- drawRect(ctx, r2.x, r2.y, r2.w, r2.h, '#000000', 2)
215
- })
216
- const borders = detectBorders(data, w, h, {
217
- lowThreshold: 15,
218
- highThreshold: 45,
219
- minArea: 10,
220
- })
221
- expect(borders.length).toBeGreaterThanOrEqual(2)
222
- const sorted = [...borders].sort((a, b) => areaOf(a) - areaOf(b))
223
- const r1Area = r1.w * r1.h
224
- const r2Area = r2.w * r2.h
225
- expect(areaOf(sorted[sorted.length - 1])).toBeGreaterThan(r2Area * 0.3)
226
- expect(areaOf(sorted[sorted.length - 1])).toBeLessThan(r2Area * 3)
227
- })
228
-
229
- it('detectBordersDefault works', () => {
230
- const w = 200, h = 200
231
- const rect = { x: 30, y: 30, w: 100, h: 100 }
232
- const data = createImage(w, h, (ctx) => {
233
- fillRect(ctx, rect.x, rect.y, rect.w, rect.h, '#cccccc')
234
- })
235
- const borders = detectBordersDefault(data, w, h)
236
- expect(borders.length).toBeGreaterThanOrEqual(1)
237
- })
238
- })
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "declaration": true,
7
- "outDir": "dist",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true
11
- },
12
- "include": ["src_ts"],
13
- "exclude": ["tests", "node_modules"]
14
- }
package/vite.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from 'vite'
2
-
3
- export default defineConfig({
4
- build: {
5
- lib: {
6
- entry: 'src_ts/index.ts',
7
- formats: ['es'],
8
- },
9
- },
10
- })
package/vitest.config.ts DELETED
@@ -1,7 +0,0 @@
1
- import { defineConfig } from 'vitest/config'
2
-
3
- export default defineConfig({
4
- test: {
5
- include: ['tests/**/*.test.ts'],
6
- },
7
- })