ppu-ocv 3.1.4 → 3.2.0
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.
- package/LICENSE +21 -0
- package/README.md +17 -16
- package/canvas-factory.d.ts +17 -6
- package/canvas-factory.js +1 -1
- package/canvas-processor.d.ts +2 -2
- package/canvas-processor.js +1 -1
- package/canvas-toolkit.base.d.ts +3 -3
- package/contours.d.ts +2 -2
- package/deskew.d.ts +2 -2
- package/image-analysis.d.ts +2 -2
- package/image-processor.d.ts +7 -1
- package/image-processor.js +1 -1
- package/index.d.ts +1 -1
- package/index.interface.d.ts +6 -6
- package/index.web.d.ts +1 -1
- package/operations/adaptive-threshold.d.ts +2 -2
- package/operations/blur.d.ts +2 -2
- package/operations/border.d.ts +2 -2
- package/operations/canny.d.ts +2 -2
- package/operations/convert.d.ts +2 -2
- package/operations/dilate.d.ts +2 -2
- package/operations/equalize.d.ts +34 -0
- package/operations/equalize.js +1 -0
- package/operations/erode.d.ts +2 -2
- package/operations/grayscale.d.ts +1 -2
- package/operations/invert.d.ts +1 -2
- package/operations/morphological-gradient.d.ts +2 -2
- package/operations/resize.d.ts +2 -2
- package/operations/rotate.d.ts +2 -2
- package/operations/threshold.d.ts +2 -2
- package/operations/warp.d.ts +2 -2
- package/package.json +2 -30
- package/pipeline/index.d.ts +2 -0
- package/pipeline/index.js +1 -1
- package/pipeline/types.d.ts +13 -10
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 PT. Perkasa Pilar Utama
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ppu-ocv
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/ppu-ocv) [](https://jsr.io/@snowfluke/ppu-ocv)
|
|
3
|
+
[](https://www.npmjs.com/package/ppu-ocv) [](https://jsr.io/@snowfluke/ppu-ocv) [](https://www.npmjs.com/package/ppu-ocv) [](https://www.npmjs.com/package/ppu-ocv#provenance) [](./LICENSE) [](https://scorecard.dev/viewer/?uri=github.com/PT-Perkasa-Pilar-Utama/ppu-ocv) [](https://socket.dev/npm/package/ppu-ocv) [](https://www.bestpractices.dev/projects/12961)
|
|
4
4
|
|
|
5
5
|
A type-safe, modular, chainable image processing library built on top of OpenCV.js with a fluent API leveraging pipeline processing. Decoupled canvas utilities run anywhere — Node, Bun, browsers, browser extensions, and service workers — with or without OpenCV.
|
|
6
6
|
|
|
@@ -231,21 +231,22 @@ setPlatform(myPlatform);
|
|
|
231
231
|
|
|
232
232
|
To avoid bloat, we only ship essential operations for chaining. Currently shipped operations are:
|
|
233
233
|
|
|
234
|
-
| Operation | Depends on… | Why
|
|
235
|
-
| ------------------------- | ------------------------------------------- |
|
|
236
|
-
| **grayscale** | – | Converts to single‐channel; many ops expect a gray image first.
|
|
237
|
-
| **blur** | _(ideally after)_ grayscale | Noise reduction works best on 1-channel data.
|
|
238
|
-
| **
|
|
239
|
-
| **
|
|
240
|
-
| **
|
|
241
|
-
| **
|
|
242
|
-
| **
|
|
243
|
-
| **
|
|
244
|
-
| **
|
|
245
|
-
| **
|
|
246
|
-
| **
|
|
247
|
-
| **
|
|
248
|
-
| **
|
|
234
|
+
| Operation | Depends on… | Why |
|
|
235
|
+
| ------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
236
|
+
| **grayscale** | – | Converts to single‐channel; many ops expect a gray image first. |
|
|
237
|
+
| **blur** | _(ideally after)_ grayscale | Noise reduction works best on 1-channel data. |
|
|
238
|
+
| **equalize** | _(after)_ grayscale | Histogram equalisation (CLAHE or global) for contrast normalisation before thresholding. |
|
|
239
|
+
| **threshold** | _(after)_ grayscale | Produces a binary image; needs gray levels. |
|
|
240
|
+
| **adaptiveThreshold** | _(after)_ grayscale (and optionally blur) | Local thresholding on gray values (smoother if blurred first). |
|
|
241
|
+
| **invert** | _(after)_ threshold or adaptiveThreshold | Inverting a binary mask flips foreground/background. |
|
|
242
|
+
| **canny** | _(after)_ grayscale + blur | Edge detection expects a smoothed gray image. |
|
|
243
|
+
| **dilate** | _(after)_ threshold or edge detection | Expands foreground regions—usually on a binary mask. |
|
|
244
|
+
| **erode** | _(after)_ threshold or edge detection | Shrinks or cleans up binary regions. |
|
|
245
|
+
| **morphologicalGradient** | _(after)_ dilation + erosion (or threshold) | Highlights boundaries by subtracting eroded from dilated image. |
|
|
246
|
+
| **warp** | – | Geometric transform; can be applied at any point. |
|
|
247
|
+
| **resize** | – | Also independent; purely geometry. |
|
|
248
|
+
| **border** | – | Independent; purely geometry. |
|
|
249
|
+
| **rotate** | – | Independent. |
|
|
249
250
|
|
|
250
251
|
## Extending operations
|
|
251
252
|
|
package/canvas-factory.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Allows ppu-ocv to work with both @napi-rs/canvas (Node) and browser canvas APIs.
|
|
4
4
|
*/
|
|
5
5
|
/** Structural type satisfied by both @napi-rs/canvas Canvas and HTMLCanvasElement/OffscreenCanvas. */
|
|
6
|
-
export
|
|
6
|
+
export type CanvasLike = {
|
|
7
7
|
/** Canvas width in pixels. */
|
|
8
8
|
width: number;
|
|
9
9
|
/** Canvas height in pixels. */
|
|
@@ -14,9 +14,9 @@ export interface CanvasLike {
|
|
|
14
14
|
toBuffer?: (...args: any[]) => Buffer;
|
|
15
15
|
/** Serialize the canvas to a data-URL string (browser canvases). Absent on Node-side `@napi-rs/canvas`. */
|
|
16
16
|
toDataURL?: (...args: any[]) => string;
|
|
17
|
-
}
|
|
17
|
+
};
|
|
18
18
|
/** Structural type for 2D rendering context, matching the cross-runtime subset used by ppu-ocv. */
|
|
19
|
-
export
|
|
19
|
+
export type Context2DLike = {
|
|
20
20
|
/** The canvas this context is bound to. */
|
|
21
21
|
canvas: any;
|
|
22
22
|
/** Draw an image, canvas, or bitmap onto the context. Signature follows the standard Canvas2D `drawImage`. */
|
|
@@ -59,17 +59,28 @@ export interface Context2DLike {
|
|
|
59
59
|
translate(x: number, y: number): void;
|
|
60
60
|
/** Rotate the coordinate system clockwise by `angle` radians. */
|
|
61
61
|
rotate(angle: number): void;
|
|
62
|
-
}
|
|
62
|
+
};
|
|
63
63
|
/** Platform-specific canvas operations. Each runtime entry point registers an implementation via {@link setPlatform}. */
|
|
64
|
-
export
|
|
64
|
+
export type CanvasPlatform = {
|
|
65
65
|
/** Create a blank canvas of the given width and height. */
|
|
66
66
|
createCanvas(width: number, height: number): CanvasLike;
|
|
67
67
|
/** Decode an image from a buffer or URL and draw it onto a fresh canvas. */
|
|
68
68
|
loadImage(source: ArrayBuffer | string): Promise<CanvasLike>;
|
|
69
69
|
/** Type guard for "is this value a canvas of this platform?". */
|
|
70
70
|
isCanvas(value: unknown): value is CanvasLike;
|
|
71
|
-
}
|
|
71
|
+
};
|
|
72
72
|
/** Register the platform-specific canvas implementation */
|
|
73
73
|
export declare function setPlatform(platform: CanvasPlatform): void;
|
|
74
74
|
/** Get the registered platform. Throws if none has been set. */
|
|
75
75
|
export declare function getPlatform(): CanvasPlatform;
|
|
76
|
+
/**
|
|
77
|
+
* Structural ("duck-typed") canvas check, independent of the registered
|
|
78
|
+
* platform. A value is canvas-like if it exposes `width`/`height` numbers and a
|
|
79
|
+
* `getContext` function — true for both `@napi-rs/canvas` (Node) and browser
|
|
80
|
+
* `HTMLCanvasElement`/`OffscreenCanvas`.
|
|
81
|
+
*
|
|
82
|
+
* Unlike {@link CanvasPlatform.isCanvas}, this does not depend on which platform
|
|
83
|
+
* is globally registered, so it stays correct when the Node and web entry
|
|
84
|
+
* points are loaded in the same process (e.g. a dual-target test suite).
|
|
85
|
+
*/
|
|
86
|
+
export declare function isCanvasLike(value: unknown): value is CanvasLike;
|
package/canvas-factory.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let _platform=null;export function setPlatform(platform){_platform=platform}export function getPlatform(){if(!_platform){throw new Error("No canvas platform registered. "+'Import "ppu-ocv" (Node), "ppu-ocv/web" (browser), '+'"ppu-ocv/canvas" (Node canvas-only), or "ppu-ocv/canvas-web" (browser canvas-only) to auto-register.')}return _platform}
|
|
1
|
+
let _platform=null;export function setPlatform(platform){_platform=platform}export function getPlatform(){if(!_platform){throw new Error("No canvas platform registered. "+'Import "ppu-ocv" (Node), "ppu-ocv/web" (browser), '+'"ppu-ocv/canvas" (Node canvas-only), or "ppu-ocv/canvas-web" (browser canvas-only) to auto-register.')}return _platform}export function isCanvasLike(value){return typeof value==="object"&&value!==null&&typeof value.getContext==="function"&&typeof value.width==="number"&&typeof value.height==="number"}
|
package/canvas-processor.d.ts
CHANGED
|
@@ -3,12 +3,12 @@ import type { CanvasLike } from "./canvas-factory.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* A detected region returned by {@link CanvasProcessor.findRegions}.
|
|
5
5
|
*/
|
|
6
|
-
export
|
|
6
|
+
export type DetectedRegion = {
|
|
7
7
|
/** Axis-aligned bounding box of the region (x1/y1 are exclusive). */
|
|
8
8
|
bbox: BoundingBox;
|
|
9
9
|
/** Number of foreground pixels in the region. */
|
|
10
10
|
area: number;
|
|
11
|
-
}
|
|
11
|
+
};
|
|
12
12
|
/**
|
|
13
13
|
* Canvas-native image processing with no OpenCV dependency.
|
|
14
14
|
*
|
package/canvas-processor.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export class CanvasProcessor{_canvas;constructor(source){this._canvas=source}get width(){return this._canvas.width}get height(){return this._canvas.height}resize(options){const{width,height}=options;let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").drawImage(this._canvas,0,0,width,height);this._canvas=dst;return this}grayscale(){const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){let luma=Math.round(0.299*(d[i]??0)+0.587*(d[i+1]??0)+0.114*(d[i+2]??0));d[i]=luma;d[i+1]=luma;d[i+2]=luma}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}convert(options={}){const{alpha=1,beta=0}=options;if(alpha===1&&beta===0)return this;const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){d[i]=Math.round((d[i]??0)*alpha+beta);d[i+1]=Math.round((d[i+1]??0)*alpha+beta);d[i+2]=Math.round((d[i+2]??0)*alpha+beta)}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}invert(){const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){d[i]=255-(d[i]??0);d[i+1]=255-(d[i+1]??0);d[i+2]=255-(d[i+2]??0)}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}threshold(options={}){const{thresh=127,maxValue=255}=options;const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){let luma=d[i]===d[i+1]&&d[i+1]===d[i+2]?d[i]??0:Math.round(0.299*(d[i]??0)+0.587*(d[i+1]??0)+0.114*(d[i+2]??0));let val=luma>thresh?maxValue:0;d[i]=val;d[i+1]=val;d[i+2]=val}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}border(options={}){const{size=10,color="white"}=options;const{width,height}=this._canvas;let dst=getPlatform().createCanvas(width+size*2,height+size*2);let ctx=dst.getContext("2d");ctx.fillStyle=color;ctx.fillRect(0,0,dst.width,dst.height);ctx.drawImage(this._canvas,size,size);this._canvas=dst;return this}rotate(options){const{angle,cx=this._canvas.width/2,cy=this._canvas.height/2}=options;if(angle===0)return this;const{width,height}=this._canvas;let dst=getPlatform().createCanvas(width,height);let ctx=dst.getContext("2d");ctx.save();ctx.translate(cx,cy);ctx.rotate(-angle*Math.PI/180);ctx.drawImage(this._canvas,-cx,-cy);ctx.restore();this._canvas=dst;return this}findRegions(options={}){const{foreground="light",thresh=127,minArea=1,maxArea=1/0,padding,scale=1}=options;const{width,height}=this._canvas;let data=this._canvas.getContext("2d").getImageData(0,0,width,height).data;let visited=new Uint8Array(width*height);let regions=[];let neighbours=[[-1,-1],[0,-1],[1,-1],[-1,0],[1,0],[-1,1],[0,1],[1,1]];let isForeground=(pixelIdx)=>{let r=data[pixelIdx]??0;return foreground==="light"?r>thresh:r<=thresh};for(let startY=0;startY<height;startY++){for(let startX=0;startX<width;startX++){let startFlat=startY*width+startX;if(visited[startFlat])continue;visited[startFlat]=1;if(!isForeground(startFlat*4))continue;let stack=[startFlat];let minX=startX,maxX=startX;let minY=startY,maxY=startY;let area=0;while(stack.length>0){let flat=stack.pop();if(flat===undefined)break;area++;let x=flat%width;let y=(flat-x)/width;if(x<minX)minX=x;else if(x>maxX)maxX=x;if(y<minY)minY=y;else if(y>maxY)maxY=y;for(const[dx,dy]of neighbours){let nx=x+dx;let ny=y+dy;if(nx<0||nx>=width||ny<0||ny>=height)continue;let nFlat=ny*width+nx;if(visited[nFlat])continue;visited[nFlat]=1;if(isForeground(nFlat*4))stack.push(nFlat)}}if(area>=minArea&&area<=maxArea){let x0=minX;let y0=minY;let x1=maxX+1;let y1=maxY+1;if(padding){let bboxH=y1-y0;let vPad=Math.round(bboxH*(padding.vertical??0));let hPad=Math.round(bboxH*(padding.horizontal??0));x0=Math.max(0,x0-hPad);y0=Math.max(0,y0-vPad);x1=Math.min(width,x1+hPad);y1=Math.min(height,y1+vPad)}if(scale!==1){x0=Math.max(0,Math.round(x0*scale));y0=Math.max(0,Math.round(y0*scale));x1=Math.round(x1*scale);y1=Math.round(y1*scale)}regions.push({bbox:{x0,y0,x1,y1},area})}}}return regions}toCanvas(){return this._canvas}static async prepareCanvas(file){if(
|
|
1
|
+
export class CanvasProcessor{_canvas;constructor(source){this._canvas=source}get width(){return this._canvas.width}get height(){return this._canvas.height}resize(options){const{width,height}=options;let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").drawImage(this._canvas,0,0,width,height);this._canvas=dst;return this}grayscale(){const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){let luma=Math.round(0.299*(d[i]??0)+0.587*(d[i+1]??0)+0.114*(d[i+2]??0));d[i]=luma;d[i+1]=luma;d[i+2]=luma}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}convert(options={}){const{alpha=1,beta=0}=options;if(alpha===1&&beta===0)return this;const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){d[i]=Math.round((d[i]??0)*alpha+beta);d[i+1]=Math.round((d[i+1]??0)*alpha+beta);d[i+2]=Math.round((d[i+2]??0)*alpha+beta)}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}invert(){const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){d[i]=255-(d[i]??0);d[i+1]=255-(d[i+1]??0);d[i+2]=255-(d[i+2]??0)}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}threshold(options={}){const{thresh=127,maxValue=255}=options;const{width,height}=this._canvas;let imageData=this._canvas.getContext("2d").getImageData(0,0,width,height);let d=imageData.data;for(let i=0;i<d.length;i+=4){let luma=d[i]===d[i+1]&&d[i+1]===d[i+2]?d[i]??0:Math.round(0.299*(d[i]??0)+0.587*(d[i+1]??0)+0.114*(d[i+2]??0));let val=luma>thresh?maxValue:0;d[i]=val;d[i+1]=val;d[i+2]=val}let dst=getPlatform().createCanvas(width,height);dst.getContext("2d").putImageData(imageData,0,0);this._canvas=dst;return this}border(options={}){const{size=10,color="white"}=options;const{width,height}=this._canvas;let dst=getPlatform().createCanvas(width+size*2,height+size*2);let ctx=dst.getContext("2d");ctx.fillStyle=color;ctx.fillRect(0,0,dst.width,dst.height);ctx.drawImage(this._canvas,size,size);this._canvas=dst;return this}rotate(options){const{angle,cx=this._canvas.width/2,cy=this._canvas.height/2}=options;if(angle===0)return this;const{width,height}=this._canvas;let dst=getPlatform().createCanvas(width,height);let ctx=dst.getContext("2d");ctx.save();ctx.translate(cx,cy);ctx.rotate(-angle*Math.PI/180);ctx.drawImage(this._canvas,-cx,-cy);ctx.restore();this._canvas=dst;return this}findRegions(options={}){const{foreground="light",thresh=127,minArea=1,maxArea=1/0,padding,scale=1}=options;const{width,height}=this._canvas;let data=this._canvas.getContext("2d").getImageData(0,0,width,height).data;let visited=new Uint8Array(width*height);let regions=[];let neighbours=[[-1,-1],[0,-1],[1,-1],[-1,0],[1,0],[-1,1],[0,1],[1,1]];let isForeground=(pixelIdx)=>{let r=data[pixelIdx]??0;return foreground==="light"?r>thresh:r<=thresh};for(let startY=0;startY<height;startY++){for(let startX=0;startX<width;startX++){let startFlat=startY*width+startX;if(visited[startFlat])continue;visited[startFlat]=1;if(!isForeground(startFlat*4))continue;let stack=[startFlat];let minX=startX,maxX=startX;let minY=startY,maxY=startY;let area=0;while(stack.length>0){let flat=stack.pop();if(flat===undefined)break;area++;let x=flat%width;let y=(flat-x)/width;if(x<minX)minX=x;else if(x>maxX)maxX=x;if(y<minY)minY=y;else if(y>maxY)maxY=y;for(const[dx,dy]of neighbours){let nx=x+dx;let ny=y+dy;if(nx<0||nx>=width||ny<0||ny>=height)continue;let nFlat=ny*width+nx;if(visited[nFlat])continue;visited[nFlat]=1;if(isForeground(nFlat*4))stack.push(nFlat)}}if(area>=minArea&&area<=maxArea){let x0=minX;let y0=minY;let x1=maxX+1;let y1=maxY+1;if(padding){let bboxH=y1-y0;let vPad=Math.round(bboxH*(padding.vertical??0));let hPad=Math.round(bboxH*(padding.horizontal??0));x0=Math.max(0,x0-hPad);y0=Math.max(0,y0-vPad);x1=Math.min(width,x1+hPad);y1=Math.min(height,y1+vPad)}if(scale!==1){x0=Math.max(0,Math.round(x0*scale));y0=Math.max(0,Math.round(y0*scale));x1=Math.round(x1*scale);y1=Math.round(y1*scale)}regions.push({bbox:{x0,y0,x1,y1},area})}}}return regions}toCanvas(){return this._canvas}static async prepareCanvas(file){if(isCanvasLike(file))return file;return getPlatform().loadImage(file)}static async prepareBuffer(canvas){if(canvas instanceof ArrayBuffer)return canvas;if(typeof canvas.toBuffer==="function"){let buffer=canvas.toBuffer("image/png");let arrayBuffer=new ArrayBuffer(buffer.byteLength);new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));return arrayBuffer}if(typeof canvas.toDataURL==="function"){let dataURL=canvas.toDataURL("image/png");let base64Data=dataURL.replace(/^data:image\/png;base64,/,"");let binaryString=atob(base64Data);let arrayBuffer=new ArrayBuffer(binaryString.length);let bytes=new Uint8Array(arrayBuffer);for(let i=0;i<binaryString.length;i++){bytes[i]=binaryString.charCodeAt(i)}return arrayBuffer}let ctx=canvas.getContext("2d");let imageData=ctx.getImageData(0,0,canvas.width,canvas.height);let canvasBuffer=new ArrayBuffer(imageData.data.byteLength);new Uint8Array(canvasBuffer).set(new Uint8Array(imageData.data.buffer,imageData.data.byteOffset,imageData.data.byteLength));return canvasBuffer}}import{getPlatform,isCanvasLike}from"./canvas-factory.js";
|
package/canvas-toolkit.base.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { BoundingBox } from "./index.interface.js";
|
|
2
2
|
import type { CanvasLike, Context2DLike } from "./canvas-factory.js";
|
|
3
|
-
/** Structural
|
|
4
|
-
export
|
|
3
|
+
/** Structural type for contour-like objects with 32-bit signed integer point data. */
|
|
4
|
+
export type ContourLike = {
|
|
5
5
|
/** Flat `[x0, y0, x1, y1, ...]` point array. Matches `cv.Mat.data32S` for contour Mats. */
|
|
6
6
|
data32S: Int32Array | number[];
|
|
7
|
-
}
|
|
7
|
+
};
|
|
8
8
|
/**
|
|
9
9
|
* Cross-platform base class for canvas manipulation utilities.
|
|
10
10
|
* Contains only methods that work in both Node and browser environments.
|
package/contours.d.ts
CHANGED
|
@@ -2,12 +2,12 @@ import type { CanvasLike } from "./canvas-factory.js";
|
|
|
2
2
|
import { cv } from "./cv-provider.js";
|
|
3
3
|
import type { BoundingBox, Points } from "./index.interface.js";
|
|
4
4
|
/** Options for configuring contour detection. */
|
|
5
|
-
export
|
|
5
|
+
export type ContoursOptions = {
|
|
6
6
|
/** The contour retrieval mode. (cv.RETR_...) */
|
|
7
7
|
mode: cv.RetrievalModes;
|
|
8
8
|
/** The contour approximation method. (cv.CHAIN_...) */
|
|
9
9
|
method: cv.ContourApproximationModes;
|
|
10
|
-
}
|
|
10
|
+
};
|
|
11
11
|
/**
|
|
12
12
|
* Wrapper around OpenCV's `findContours` that provides convenient accessors
|
|
13
13
|
* for iterating, filtering, and analyzing contours in a binary image.
|
package/deskew.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { CanvasLike } from "./canvas-factory.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Options for configuring the deskew service
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
5
|
+
export type DeskewOptions = {
|
|
6
6
|
/**
|
|
7
7
|
* Enable detailed logging of each processing step.
|
|
8
8
|
* @default false
|
|
@@ -14,7 +14,7 @@ export interface DeskewOptions {
|
|
|
14
14
|
* @default 20
|
|
15
15
|
*/
|
|
16
16
|
minimumAreaThreshold?: number;
|
|
17
|
-
}
|
|
17
|
+
};
|
|
18
18
|
/**
|
|
19
19
|
* Service for calculating the skew angle of an image containing text.
|
|
20
20
|
*
|
package/image-analysis.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { CanvasLike } from "./canvas-factory.js";
|
|
|
7
7
|
/**
|
|
8
8
|
* Options for calculating mean Lab lightness.
|
|
9
9
|
*/
|
|
10
|
-
export
|
|
10
|
+
export type CalculateMeanLightnessOptions = {
|
|
11
11
|
/** The canvas containing the image to be processed. */
|
|
12
12
|
canvas: CanvasLike;
|
|
13
13
|
/** The target dimensions for analysis (resizes internally). */
|
|
@@ -15,7 +15,7 @@ export interface CalculateMeanLightnessOptions {
|
|
|
15
15
|
width: number;
|
|
16
16
|
height: number;
|
|
17
17
|
};
|
|
18
|
-
}
|
|
18
|
+
};
|
|
19
19
|
/**
|
|
20
20
|
* Calculates the mean normalized lightness of an image using the L channel of the Lab color space.
|
|
21
21
|
* Lightness is normalized based on the image's own maximum lightness value before averaging.
|
package/image-processor.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CanvasLike } from "./canvas-factory.js";
|
|
2
2
|
import { cv } from "./cv-provider.js";
|
|
3
|
-
import type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, ConvertOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationName, OperationOptions, RequiredOptions, ResizeOptions, RotateOptions, ThresholdOptions, WarpOptions } from "./pipeline/index.js";
|
|
3
|
+
import type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, ConvertOptions, DilateOptions, EqualizeOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationName, OperationOptions, RequiredOptions, ResizeOptions, RotateOptions, ThresholdOptions, WarpOptions } from "./pipeline/index.js";
|
|
4
4
|
type NameWithRequiredOptions = {
|
|
5
5
|
[N in OperationName]: OperationOptions<N> extends RequiredOptions ? N : never;
|
|
6
6
|
}[OperationName];
|
|
@@ -83,6 +83,12 @@ export declare class ImageProcessor {
|
|
|
83
83
|
* @param options Optional configuration for inversion
|
|
84
84
|
*/
|
|
85
85
|
invert(options?: Partial<InvertOptions>): this;
|
|
86
|
+
/**
|
|
87
|
+
* Equalise image contrast using histogram equalization
|
|
88
|
+
* @description Usage order: (after) grayscale — input must be single-channel
|
|
89
|
+
* @param options Equalization configuration options
|
|
90
|
+
*/
|
|
91
|
+
equalize(options?: Partial<EqualizeOptions>): this;
|
|
86
92
|
/**
|
|
87
93
|
* Canny edge detection to detect edges in the image
|
|
88
94
|
* @description Usage order: (after) grayscale + blur
|
package/image-processor.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export class ImageProcessor{img;width;height;constructor(source){if(
|
|
1
|
+
export class ImageProcessor{img;width;height;constructor(source){if(isCanvasLike(source)){let ctx=source.getContext("2d");let imageData=ctx.getImageData(0,0,source.width,source.height);this.img=cv.matFromImageData(imageData);this.width=source.width;this.height=source.height}else if(source instanceof cv.Mat){this.img=source;this.width=source.cols;this.height=source.rows}else{throw new Error("Invalid source type. Must be either Canvas or cv.Mat.")}}static async initRuntime(){return new Promise((res)=>{if(cv&&cv.Mat){res()}else{cv["onRuntimeInitialized"]=()=>{res()}}})}execute(operationName,options){let result=executeOperation(operationName,this.img,options);this.img=result.img;this.width=result.width;this.height=result.height;return this}grayscale(options){return this.execute("grayscale",options)}blur(options){return this.execute("blur",options)}threshold(options){return this.execute("threshold",options)}adaptiveThreshold(options){return this.execute("adaptiveThreshold",options)}invert(options){return this.execute("invert",options)}equalize(options){return this.execute("equalize",options)}canny(options){return this.execute("canny",options)}dilate(options){return this.execute("dilate",options)}erode(options){return this.execute("erode",options)}border(options){return this.execute("border",options)}resize(options){return this.execute("resize",options)}rotate(options){return this.execute("rotate",options)}warp(options){return this.execute("warp",options)}convert(options){return this.execute("convert",options)}morphologicalGradient(options){return this.execute("morphologicalGradient",options)}toMat(){return this.img}toCanvas(){let platform=getPlatform();let canvas=platform.createCanvas(this.width,this.height);try{cv.imshow(canvas,this.img)}catch{let ctx=canvas.getContext("2d");if(!ctx)throw new Error("Could not get 2d context from canvas");let imgData=ctx.createImageData(this.width,this.height);if(this.img.channels()===1){let data=imgData.data;let gray=new Uint8Array(this.img.data);for(let i=0;i<gray.length;i++){data[i*4]=gray[i];data[i*4+1]=gray[i];data[i*4+2]=gray[i];data[i*4+3]=255}}else{imgData.data.set(new Uint8ClampedArray(this.img.data))}ctx.putImageData(imgData,0,0)}return canvas}destroy(){try{this.img.delete()}catch{}}}import{getPlatform,isCanvasLike}from"./canvas-factory.js";import{cv}from"./cv-provider.js";import{executeOperation}from"./pipeline/index.js";
|
package/index.d.ts
CHANGED
|
@@ -13,4 +13,4 @@ export { Contours } from "./contours.js";
|
|
|
13
13
|
export { calculateMeanGrayscaleValue, calculateMeanNormalizedLabLightness, type CalculateMeanLightnessOptions, } from "./image-analysis.js";
|
|
14
14
|
export { ImageProcessor } from "./image-processor.js";
|
|
15
15
|
export { DeskewService, type DeskewOptions } from "./deskew.js";
|
|
16
|
-
export type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationFunction, OperationName, OperationOptions, OperationResult, PartialOptions, RegisteredOperations, RequiredOptions, ResizeOptions, RotateOptions, ThresholdOptions, WarpOptions, } from "./pipeline/index.js";
|
|
16
|
+
export type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, EqualizeOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationFunction, OperationName, OperationOptions, OperationResult, PartialOptions, RegisteredOperations, RequiredOptions, ResizeOptions, RotateOptions, ThresholdOptions, WarpOptions, } from "./pipeline/index.js";
|
package/index.interface.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/** A 2D point in canvas pixel coordinates. */
|
|
2
|
-
export
|
|
2
|
+
export type Coordinate = {
|
|
3
3
|
/** X coordinate in pixels, measured from the left edge. */
|
|
4
4
|
x: number;
|
|
5
5
|
/** Y coordinate in pixels, measured from the top edge. */
|
|
6
6
|
y: number;
|
|
7
|
-
}
|
|
7
|
+
};
|
|
8
8
|
/** The four corner points of an axis-aligned rectangle, e.g. a contour bounding box. */
|
|
9
|
-
export
|
|
9
|
+
export type Points = {
|
|
10
10
|
/** Top-left corner. */
|
|
11
11
|
topLeft: Coordinate;
|
|
12
12
|
/** Top-right corner. */
|
|
@@ -15,12 +15,12 @@ export interface Points {
|
|
|
15
15
|
bottomLeft: Coordinate;
|
|
16
16
|
/** Bottom-right corner. */
|
|
17
17
|
bottomRight: Coordinate;
|
|
18
|
-
}
|
|
18
|
+
};
|
|
19
19
|
/**
|
|
20
20
|
* An axis-aligned bounding box with exclusive `x1` / `y1`.
|
|
21
21
|
* Width is `x1 - x0`; height is `y1 - y0`.
|
|
22
22
|
*/
|
|
23
|
-
export
|
|
23
|
+
export type BoundingBox = {
|
|
24
24
|
/** Left edge, inclusive. */
|
|
25
25
|
x0: number;
|
|
26
26
|
/** Top edge, inclusive. */
|
|
@@ -29,4 +29,4 @@ export interface BoundingBox {
|
|
|
29
29
|
x1: number;
|
|
30
30
|
/** Bottom edge, exclusive. */
|
|
31
31
|
y1: number;
|
|
32
|
-
}
|
|
32
|
+
};
|
package/index.web.d.ts
CHANGED
|
@@ -35,4 +35,4 @@ export { Contours } from "./contours.js";
|
|
|
35
35
|
export { calculateMeanGrayscaleValue, calculateMeanNormalizedLabLightness, type CalculateMeanLightnessOptions, } from "./image-analysis.js";
|
|
36
36
|
export { ImageProcessor } from "./image-processor.js";
|
|
37
37
|
export { DeskewService, type DeskewOptions } from "./deskew.js";
|
|
38
|
-
export type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationFunction, OperationName, OperationOptions, OperationResult, PartialOptions, RegisteredOperations, RequiredOptions, ResizeOptions, RotateOptions, ThresholdOptions, WarpOptions, } from "./pipeline/index.js";
|
|
38
|
+
export type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, EqualizeOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationFunction, OperationName, OperationOptions, OperationResult, PartialOptions, RegisteredOperations, RequiredOptions, ResizeOptions, RotateOptions, ThresholdOptions, WarpOptions, } from "./pipeline/index.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cv } from "../cv-provider.js";
|
|
2
2
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
3
3
|
/** Options for the adaptive threshold operation. */
|
|
4
|
-
export
|
|
4
|
+
export type AdaptiveThresholdOptions = PartialOptions & {
|
|
5
5
|
/** Upper threshold value (0-255) */
|
|
6
6
|
upper: number;
|
|
7
7
|
/** Adaptive threshold method (cv.ADAPTIVE_THRESH_...) */
|
|
@@ -12,6 +12,6 @@ export interface AdaptiveThresholdOptions extends PartialOptions {
|
|
|
12
12
|
size: number;
|
|
13
13
|
/** Constant subtracted from the mean or weighted mean */
|
|
14
14
|
constant: number;
|
|
15
|
-
}
|
|
15
|
+
};
|
|
16
16
|
/** Apply adaptive thresholding to convert a grayscale image to binary. */
|
|
17
17
|
export declare function adaptiveThreshold(img: cv.Mat, options: AdaptiveThresholdOptions): OperationResult;
|
package/operations/blur.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { cv } from "../cv-provider.js";
|
|
2
2
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
3
3
|
/** Options for the Gaussian blur operation. */
|
|
4
|
-
export
|
|
4
|
+
export type BlurOptions = PartialOptions & {
|
|
5
5
|
/** Size of the blur [x, y] */
|
|
6
6
|
size: [number, number];
|
|
7
7
|
/** Gaussian kernel standard deviation on x axis */
|
|
8
8
|
sigma: number;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
/** Apply Gaussian blur to reduce noise. */
|
|
11
11
|
export declare function blur(img: cv.Mat, options: BlurOptions): OperationResult;
|
package/operations/border.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for adding a constant-color border around the image. */
|
|
4
|
-
export
|
|
4
|
+
export type BorderOptions = PartialOptions & {
|
|
5
5
|
/** Size of the border in pixels */
|
|
6
6
|
size: number;
|
|
7
7
|
/** Border type (e.g., cv.BORDER_CONSTANT) */
|
|
8
8
|
borderType: cv.BorderTypes;
|
|
9
9
|
/** Border color in [B, G, R, A] format */
|
|
10
10
|
borderColor: [cv.int, cv.int, cv.int, cv.int];
|
|
11
|
-
}
|
|
11
|
+
};
|
|
12
12
|
/** Add a uniform border around the image using `cv.copyMakeBorder`. */
|
|
13
13
|
export declare function border(img: cv.Mat, options: BorderOptions): OperationResult;
|
package/operations/canny.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for the Canny edge-detection operation. */
|
|
4
|
-
export
|
|
4
|
+
export type CannyOptions = PartialOptions & {
|
|
5
5
|
/** Lower threshold for the hysteresis procedure (0-255) */
|
|
6
6
|
lower: number;
|
|
7
7
|
/** Upper threshold for the hysteresis procedure (0-255) */
|
|
8
8
|
upper: number;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
/** Detect edges using the Canny algorithm. */
|
|
11
11
|
export declare function canny(img: cv.Mat, options: CannyOptions): OperationResult;
|
package/operations/convert.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { OperationResult, RequiredOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for converting a Mat to a different depth/channel type. */
|
|
4
|
-
export
|
|
4
|
+
export type ConvertOptions = RequiredOptions & {
|
|
5
5
|
/** Desired matrix type (cv.CV_...) if negative, it will be the same as input */
|
|
6
6
|
rtype: number;
|
|
7
|
-
}
|
|
7
|
+
};
|
|
8
8
|
/** Convert the image matrix to a new type via `Mat.convertTo`. */
|
|
9
9
|
export declare function convert(img: cv.Mat, options: ConvertOptions): OperationResult;
|
package/operations/dilate.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for the morphological dilation operation. */
|
|
4
|
-
export
|
|
4
|
+
export type DilateOptions = PartialOptions & {
|
|
5
5
|
/** Size of the block [x, y] */
|
|
6
6
|
size: [number, number];
|
|
7
7
|
/** Number of iterations for the dilation operation */
|
|
8
8
|
iter: number;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
/** Dilate the image to expand foreground regions. */
|
|
11
11
|
export declare function dilate(img: cv.Mat, options: DilateOptions): OperationResult;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
|
+
import { cv } from "../cv-provider.js";
|
|
3
|
+
/** Options for the histogram equalization operation. */
|
|
4
|
+
export type EqualizeOptions = PartialOptions & {
|
|
5
|
+
/**
|
|
6
|
+
* Equalization algorithm to use.
|
|
7
|
+
* - `"clahe"` (default) — Contrast Limited Adaptive Histogram Equalization;
|
|
8
|
+
* preserves local contrast and avoids over-amplification in bright regions.
|
|
9
|
+
* - `"global"` — Standard global histogram equalization via `cv.equalizeHist`;
|
|
10
|
+
* faster but may blow out highlights.
|
|
11
|
+
*/
|
|
12
|
+
method: "clahe" | "global";
|
|
13
|
+
/**
|
|
14
|
+
* CLAHE only — clip limit for contrast limiting (default `2.0`).
|
|
15
|
+
* Higher values allow more contrast; lower values are closer to global equalization.
|
|
16
|
+
*/
|
|
17
|
+
clipLimit: number;
|
|
18
|
+
/**
|
|
19
|
+
* CLAHE only — tile grid size in pixels (default `8` → 8×8 tiles).
|
|
20
|
+
* The image is divided into this many tiles in each dimension.
|
|
21
|
+
*/
|
|
22
|
+
tileGridSize: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Equalise histogram contrast on a single-channel (grayscale) image.
|
|
26
|
+
*
|
|
27
|
+
* Supports two algorithms selectable via {@link EqualizeOptions.method}:
|
|
28
|
+
* - `"clahe"` (default) — locally adaptive, clip-limited equalization.
|
|
29
|
+
* - `"global"` — standard whole-image histogram spreading.
|
|
30
|
+
*
|
|
31
|
+
* Input `img` must be an 8-bit single-channel `cv.Mat` (run `.grayscale()` first).
|
|
32
|
+
* The input Mat is deleted by this operation.
|
|
33
|
+
*/
|
|
34
|
+
export declare function equalize(img: cv.Mat, options: EqualizeOptions): OperationResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{method:"clahe",clipLimit:2,tileGridSize:8}}export function equalize(img,options){let dst=new cv.Mat;if(options.method==="global"){cv.equalizeHist(img,dst)}else{let tileSize=new cv.Size(options.tileGridSize,options.tileGridSize);let clahe=new cv.CLAHE(options.clipLimit,tileSize);clahe.apply(img,dst);clahe.delete()}img.delete();return{img:dst,width:dst.cols,height:dst.rows}}registry.register("equalize",equalize,defaultOptions);
|
package/operations/erode.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for the morphological erosion operation. */
|
|
4
|
-
export
|
|
4
|
+
export type ErodeOptions = PartialOptions & {
|
|
5
5
|
/** Size of the block [x, y] */
|
|
6
6
|
size: [number, number];
|
|
7
7
|
/** Number of iterations for the erosion operation */
|
|
8
8
|
iter: number;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
/** Erode the image to shrink foreground regions and remove small noise. */
|
|
11
11
|
export declare function erode(img: cv.Mat, options: ErodeOptions): OperationResult;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for the grayscale conversion operation (no configurable fields). */
|
|
4
|
-
export
|
|
5
|
-
}
|
|
4
|
+
export type GrayscaleOptions = PartialOptions;
|
|
6
5
|
/** Convert the image to grayscale using `COLOR_RGBA2GRAY`. */
|
|
7
6
|
export declare function grayscale(img: cv.Mat, _options: GrayscaleOptions): OperationResult;
|
package/operations/invert.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for the bitwise-NOT color inversion operation (no configurable fields). */
|
|
4
|
-
export
|
|
5
|
-
}
|
|
4
|
+
export type InvertOptions = PartialOptions;
|
|
6
5
|
/** Invert all pixel values using `cv.bitwise_not`. */
|
|
7
6
|
export declare function invert(img: cv.Mat, _options: InvertOptions): OperationResult;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for the morphological gradient operation. */
|
|
4
|
-
export
|
|
4
|
+
export type MorphologicalGradientOptions = PartialOptions & {
|
|
5
5
|
/** Kernel size for the morphological gradient operation [x, y] */
|
|
6
6
|
size: [number, number];
|
|
7
|
-
}
|
|
7
|
+
};
|
|
8
8
|
/** Apply morphological gradient to highlight edges (dilation minus erosion). */
|
|
9
9
|
export declare function morphologicalGradient(img: cv.Mat, options: MorphologicalGradientOptions): OperationResult;
|
package/operations/resize.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { OperationResult, RequiredOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for resizing the image to exact pixel dimensions. */
|
|
4
|
-
export
|
|
4
|
+
export type ResizeOptions = RequiredOptions & {
|
|
5
5
|
/** Width of the resized image */
|
|
6
6
|
width: number;
|
|
7
7
|
/** Height of the resized image */
|
|
8
8
|
height: number;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
/** Resize the image to the given width and height. */
|
|
11
11
|
export declare function resize(img: cv.Mat, options: ResizeOptions): OperationResult;
|
package/operations/rotate.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { OperationResult, RequiredOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for rotating the image around a pivot point. */
|
|
4
|
-
export
|
|
4
|
+
export type RotateOptions = RequiredOptions & {
|
|
5
5
|
/** Angle of rotation in degrees (positive for counter-clockwise) */
|
|
6
6
|
angle: number;
|
|
7
7
|
/** Optional center of rotation. Defaults to the image center. */
|
|
8
8
|
center?: cv.Point;
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
/** Rotate the image by the given angle around its centre (or a custom pivot). */
|
|
11
11
|
export declare function rotate(img: cv.Mat, options: RotateOptions): OperationResult;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { OperationResult, PartialOptions } from "../pipeline/types.js";
|
|
2
2
|
import { cv } from "../cv-provider.js";
|
|
3
3
|
/** Options for the global threshold operation. */
|
|
4
|
-
export
|
|
4
|
+
export type ThresholdOptions = PartialOptions & {
|
|
5
5
|
/** Lower threshold value (0-255) */
|
|
6
6
|
lower: number;
|
|
7
7
|
/** Upper threshold value (0-255) */
|
|
8
8
|
upper: number;
|
|
9
9
|
/** Type of thresholding (cv.THRESH_...) */
|
|
10
10
|
type: cv.ThresholdTypes;
|
|
11
|
-
}
|
|
11
|
+
};
|
|
12
12
|
/** Apply a global threshold to convert a grayscale image to binary. */
|
|
13
13
|
export declare function threshold(img: cv.Mat, options: ThresholdOptions): OperationResult;
|
package/operations/warp.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { cv } from "../cv-provider.js";
|
|
|
2
2
|
import type { BoundingBox, Points } from "../index.interface.js";
|
|
3
3
|
import type { OperationResult, RequiredOptions } from "../pipeline/types.js";
|
|
4
4
|
/** Options for the perspective warp (four-point transform) operation. */
|
|
5
|
-
export
|
|
5
|
+
export type WarpOptions = RequiredOptions & {
|
|
6
6
|
/** Four points of the source image containing x and y point in
|
|
7
7
|
* topLeft, topRight, bottomLeft and BottomRight.
|
|
8
8
|
* Use Contours class instance to get the points
|
|
@@ -10,6 +10,6 @@ export interface WarpOptions extends RequiredOptions {
|
|
|
10
10
|
points: Points;
|
|
11
11
|
/** A destination canvas bounding box for cropping the original canvas */
|
|
12
12
|
bbox: BoundingBox;
|
|
13
|
-
}
|
|
13
|
+
};
|
|
14
14
|
/** Apply a perspective warp using four source/destination corner points. */
|
|
15
15
|
export declare function warp(img: cv.Mat, options: WarpOptions): OperationResult;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ppu-ocv",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "A type-safe, modular, chainable image processing library built on top of OpenCV.js with a fluent API leveraging pipeline processing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"open-cv",
|
|
@@ -43,40 +43,12 @@
|
|
|
43
43
|
"default": "./index.canvas-web.js"
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
-
"scripts": {
|
|
47
|
-
"task": "bun scripts/task.ts",
|
|
48
|
-
"build": "bun task build",
|
|
49
|
-
"build:test": "bun task build && bun test",
|
|
50
|
-
"build:publish": "bun task build && bun task report-size && bun task publish",
|
|
51
|
-
"type-check": "bunx tsgo --noEmit",
|
|
52
|
-
"test": "bun test --parallel=$(ls tests/*.test.ts | wc -l | tr -d ' ')",
|
|
53
|
-
"lint": "oxlint",
|
|
54
|
-
"lint:fix": "oxlint --fix",
|
|
55
|
-
"fmt": "oxfmt --check",
|
|
56
|
-
"fmt:fix": "oxfmt .",
|
|
57
|
-
"demo": "bunx -y serve -l 4567 .",
|
|
58
|
-
"prepare": "husky"
|
|
59
|
-
},
|
|
60
|
-
"devDependencies": {
|
|
61
|
-
"@types/bun": "latest",
|
|
62
|
-
"@types/uglify-js": "latest",
|
|
63
|
-
"@typescript/native-preview": "^7.0.0-dev.20260513.1",
|
|
64
|
-
"canvas": "^3.2.3",
|
|
65
|
-
"husky": "^9.1.7",
|
|
66
|
-
"lint-staged": "^16.0.0",
|
|
67
|
-
"mitata": "latest",
|
|
68
|
-
"oxfmt": "^0.48.0",
|
|
69
|
-
"oxlint": "^1.63.0",
|
|
70
|
-
"tsx": "latest",
|
|
71
|
-
"typescript": "latest",
|
|
72
|
-
"uglify-js": ">=2.4.24"
|
|
73
|
-
},
|
|
74
46
|
"repository": {
|
|
75
47
|
"type": "git",
|
|
76
48
|
"url": "https://github.com/PT-Perkasa-Pilar-Utama/ppu-ocv.git"
|
|
77
49
|
},
|
|
78
50
|
"dependencies": {
|
|
79
|
-
"@napi-rs/canvas": "^0.
|
|
51
|
+
"@napi-rs/canvas": "^1.0.0",
|
|
80
52
|
"@techstark/opencv-js": "^4.10.0-release.1"
|
|
81
53
|
}
|
|
82
54
|
}
|
package/pipeline/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import "../operations/canny.js";
|
|
|
7
7
|
import "../operations/convert.js";
|
|
8
8
|
import "../operations/dilate.js";
|
|
9
9
|
import "../operations/erode.js";
|
|
10
|
+
import "../operations/equalize.js";
|
|
10
11
|
import "../operations/grayscale.js";
|
|
11
12
|
import "../operations/invert.js";
|
|
12
13
|
import "../operations/morphological-gradient.js";
|
|
@@ -21,6 +22,7 @@ export type { CannyOptions } from "../operations/canny.js";
|
|
|
21
22
|
export type { ConvertOptions } from "../operations/convert.js";
|
|
22
23
|
export type { DilateOptions } from "../operations/dilate.js";
|
|
23
24
|
export type { ErodeOptions } from "../operations/erode.js";
|
|
25
|
+
export type { EqualizeOptions } from "../operations/equalize.js";
|
|
24
26
|
export type { GrayscaleOptions } from "../operations/grayscale.js";
|
|
25
27
|
export type { InvertOptions } from "../operations/invert.js";
|
|
26
28
|
export type { MorphologicalGradientOptions } from "../operations/morphological-gradient.js";
|
package/pipeline/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{executeOperation,OperationRegistry,registry}from"./registry.js";import"../operations/adaptive-threshold.js";import"../operations/blur.js";import"../operations/border.js";import"../operations/canny.js";import"../operations/convert.js";import"../operations/dilate.js";import"../operations/erode.js";import"../operations/grayscale.js";import"../operations/invert.js";import"../operations/morphological-gradient.js";import"../operations/resize.js";import"../operations/rotate.js";import"../operations/threshold.js";import"../operations/warp.js";
|
|
1
|
+
export{executeOperation,OperationRegistry,registry}from"./registry.js";import"../operations/adaptive-threshold.js";import"../operations/blur.js";import"../operations/border.js";import"../operations/canny.js";import"../operations/convert.js";import"../operations/dilate.js";import"../operations/erode.js";import"../operations/equalize.js";import"../operations/grayscale.js";import"../operations/invert.js";import"../operations/morphological-gradient.js";import"../operations/resize.js";import"../operations/rotate.js";import"../operations/threshold.js";import"../operations/warp.js";
|
package/pipeline/types.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { CannyOptions } from "../operations/canny.js";
|
|
|
6
6
|
import type { ConvertOptions } from "../operations/convert.js";
|
|
7
7
|
import type { DilateOptions } from "../operations/dilate.js";
|
|
8
8
|
import type { ErodeOptions } from "../operations/erode.js";
|
|
9
|
+
import type { EqualizeOptions } from "../operations/equalize.js";
|
|
9
10
|
import type { GrayscaleOptions } from "../operations/grayscale.js";
|
|
10
11
|
import type { InvertOptions } from "../operations/invert.js";
|
|
11
12
|
import type { MorphologicalGradientOptions } from "../operations/morphological-gradient.js";
|
|
@@ -14,31 +15,31 @@ import type { RotateOptions } from "../operations/rotate.js";
|
|
|
14
15
|
import type { ThresholdOptions } from "../operations/threshold.js";
|
|
15
16
|
import type { WarpOptions } from "../operations/warp.js";
|
|
16
17
|
/** The output produced by every pipeline operation: the transformed Mat plus its dimensions. */
|
|
17
|
-
export
|
|
18
|
+
export type OperationResult = {
|
|
18
19
|
/** Resulting OpenCV Mat after the operation. The caller is responsible for deleting it. */
|
|
19
20
|
img: cv.Mat;
|
|
20
21
|
/** Width of the resulting image in pixels. */
|
|
21
22
|
width: number;
|
|
22
23
|
/** Height of the resulting image in pixels. */
|
|
23
24
|
height: number;
|
|
24
|
-
}
|
|
25
|
+
};
|
|
25
26
|
declare const RequiredBrand: unique symbol;
|
|
26
27
|
/**
|
|
27
|
-
* Marker
|
|
28
|
-
* must be supplied by the caller. Operation option types that
|
|
28
|
+
* Marker type for operation options that have no usable defaults and
|
|
29
|
+
* must be supplied by the caller. Operation option types that intersect this
|
|
29
30
|
* cannot be omitted when calling {@link ImageProcessor.execute}.
|
|
30
31
|
*/
|
|
31
|
-
export
|
|
32
|
+
export type RequiredOptions = {
|
|
32
33
|
[RequiredBrand]?: never;
|
|
33
|
-
}
|
|
34
|
+
};
|
|
34
35
|
declare const PartialBrand: unique symbol;
|
|
35
36
|
/**
|
|
36
|
-
* Marker
|
|
37
|
-
* Operation option types that
|
|
37
|
+
* Marker type for operation options that have sensible defaults.
|
|
38
|
+
* Operation option types that intersect this may be omitted or partially supplied.
|
|
38
39
|
*/
|
|
39
|
-
export
|
|
40
|
+
export type PartialOptions = {
|
|
40
41
|
[PartialBrand]?: never;
|
|
41
|
-
}
|
|
42
|
+
};
|
|
42
43
|
/** Signature every registered operation function must conform to. */
|
|
43
44
|
export type OperationFunction<T> = (img: cv.Mat, options: T) => OperationResult;
|
|
44
45
|
/**
|
|
@@ -66,6 +67,8 @@ export interface RegisteredOperations {
|
|
|
66
67
|
convert: ConvertOptions;
|
|
67
68
|
/** Morphological dilation. See {@link DilateOptions}. */
|
|
68
69
|
dilate: DilateOptions;
|
|
70
|
+
/** Histogram equalisation (CLAHE or global). See {@link EqualizeOptions}. */
|
|
71
|
+
equalize: EqualizeOptions;
|
|
69
72
|
/** Morphological erosion. See {@link ErodeOptions}. */
|
|
70
73
|
erode: ErodeOptions;
|
|
71
74
|
/** Convert to grayscale via `COLOR_RGBA2GRAY`. See {@link GrayscaleOptions}. */
|