ppu-ocv 1.7.0 → 3.0.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.
Files changed (62) hide show
  1. package/README.md +200 -47
  2. package/canvas-factory.d.ts +42 -0
  3. package/canvas-factory.js +1 -0
  4. package/canvas-processor.d.ts +18 -0
  5. package/canvas-processor.js +1 -0
  6. package/canvas-toolkit.base.d.ts +52 -0
  7. package/canvas-toolkit.base.js +1 -0
  8. package/canvas-toolkit.d.ts +8 -87
  9. package/canvas-toolkit.js +1 -1
  10. package/contours.d.ts +4 -3
  11. package/contours.js +1 -1
  12. package/cv-provider.d.ts +45 -0
  13. package/cv-provider.js +1 -0
  14. package/deskew.d.ts +68 -0
  15. package/deskew.js +1 -0
  16. package/image-analysis.d.ts +3 -3
  17. package/image-analysis.js +1 -1
  18. package/image-processor.d.ts +51 -59
  19. package/image-processor.js +1 -1
  20. package/index.canvas-web.d.ts +6 -0
  21. package/index.canvas-web.js +1 -0
  22. package/index.canvas.d.ts +8 -0
  23. package/index.canvas.js +1 -0
  24. package/index.d.ts +6 -1
  25. package/index.js +1 -1
  26. package/index.web.d.ts +14 -0
  27. package/index.web.js +1 -0
  28. package/operations/adaptive-threshold.d.ts +3 -3
  29. package/operations/adaptive-threshold.js +1 -1
  30. package/operations/blur.d.ts +3 -3
  31. package/operations/blur.js +1 -1
  32. package/operations/border.d.ts +3 -3
  33. package/operations/border.js +1 -1
  34. package/operations/canny.d.ts +3 -3
  35. package/operations/canny.js +1 -1
  36. package/operations/convert.d.ts +3 -3
  37. package/operations/convert.js +1 -1
  38. package/operations/dilate.d.ts +3 -3
  39. package/operations/dilate.js +1 -1
  40. package/operations/erode.d.ts +3 -3
  41. package/operations/erode.js +1 -1
  42. package/operations/grayscale.d.ts +3 -3
  43. package/operations/grayscale.js +1 -1
  44. package/operations/invert.d.ts +3 -3
  45. package/operations/invert.js +1 -1
  46. package/operations/morphological-gradient.d.ts +3 -3
  47. package/operations/morphological-gradient.js +1 -1
  48. package/operations/resize.d.ts +3 -3
  49. package/operations/resize.js +1 -1
  50. package/operations/rotate.d.ts +3 -3
  51. package/operations/rotate.js +1 -1
  52. package/operations/threshold.d.ts +3 -3
  53. package/operations/threshold.js +1 -1
  54. package/operations/warp.d.ts +4 -3
  55. package/operations/warp.js +1 -1
  56. package/package.json +26 -7
  57. package/pipeline/registry.d.ts +1 -1
  58. package/pipeline/types.d.ts +1 -1
  59. package/platform/node.d.ts +3 -0
  60. package/platform/node.js +1 -0
  61. package/platform/web.d.ts +3 -0
  62. package/platform/web.js +1 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Lazy OpenCV accessor.
3
+ *
4
+ * In Node (with @techstark/opencv-js installed), `cv` is available after
5
+ * `import cv from "@techstark/opencv-js"`.
6
+ *
7
+ * In the browser, `cv` is set on `globalThis` after OpenCV.js is loaded
8
+ * (either via a <script> tag or dynamically by `initRuntime()`).
9
+ *
10
+ * This module re-exports `cv` as a lazy proxy so that static `import`
11
+ * resolution does NOT require `@techstark/opencv-js` to be present
12
+ * as a resolvable bare specifier at module-load time.
13
+ */
14
+ import type _cvType from "@techstark/opencv-js";
15
+ type CV = typeof _cvType;
16
+ /**
17
+ * Set the cv instance (called by platform entry points).
18
+ */
19
+ export declare function setCv(instance: CV): void;
20
+ /**
21
+ * TypeScript Declaration Merging:
22
+ * By exporting both a `namespace cv` and a `const cv`, consumers importing `{ cv }`
23
+ * get BOTH the types (e.g. `cv.Mat`) AND the runtime Proxy object.
24
+ */
25
+ export declare namespace cv {
26
+ type Mat = _cvType.Mat;
27
+ type MatVector = _cvType.MatVector;
28
+ type Point = _cvType.Point;
29
+ type Rect = _cvType.Rect;
30
+ type Size = _cvType.Size;
31
+ type Scalar = _cvType.Scalar;
32
+ type AdaptiveThresholdTypes = _cvType.AdaptiveThresholdTypes;
33
+ type ThresholdTypes = _cvType.ThresholdTypes;
34
+ type LineTypes = _cvType.LineTypes;
35
+ type RetrievalModes = _cvType.RetrievalModes;
36
+ type ContourApproximationModes = _cvType.ContourApproximationModes;
37
+ type BorderTypes = _cvType.BorderTypes;
38
+ type InterpolationFlags = _cvType.InterpolationFlags;
39
+ type ColorConversionCodes = _cvType.ColorConversionCodes;
40
+ type MorphShapes = _cvType.MorphShapes;
41
+ type MorphTypes = _cvType.MorphTypes;
42
+ type int = number;
43
+ }
44
+ export declare const cv: CV;
45
+ export {};
package/cv-provider.js ADDED
@@ -0,0 +1 @@
1
+ let _cv=null;function getCv(){if(_cv)return _cv;if(typeof globalThis!=="undefined"&&globalThis.cv){_cv=globalThis.cv||null;return _cv}throw new Error("OpenCV is not loaded. Call ImageProcessor.initRuntime() first.")}export function setCv(instance){_cv=instance;if(typeof globalThis!=="undefined"){globalThis.cv=instance}}export let cv=new Proxy({},{get(_target,prop){if(prop===Symbol.toPrimitive||prop===Symbol.toStringTag){return}return getCv()[prop]},set(_target,prop,value){getCv()[prop]=value;return true},has(_target,prop){try{return prop in getCv()}catch{return false}}});
package/deskew.d.ts ADDED
@@ -0,0 +1,68 @@
1
+ import type { CanvasLike } from "./canvas-factory.js";
2
+ /**
3
+ * Options for configuring the deskew service
4
+ */
5
+ export interface DeskewOptions {
6
+ /**
7
+ * Enable detailed logging of each processing step.
8
+ * @default false
9
+ */
10
+ verbose?: boolean;
11
+ /**
12
+ * Remove detected boxes with area below this threshold, in pixels.
13
+ * Used to filter out noise when detecting text regions.
14
+ * @default 20
15
+ */
16
+ minimumAreaThreshold?: number;
17
+ }
18
+ /**
19
+ * Service for calculating the skew angle of an image containing text.
20
+ *
21
+ * This service analyzes text regions in an image to determine its skew angle
22
+ * using multiple methods (minAreaRect, baseline analysis, and Hough transform)
23
+ * to robustly calculate the average text orientation.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { DeskewService } from 'ppu-ocv';
28
+ *
29
+ * const service = new DeskewService({ verbose: true });
30
+ * const canvas = ...; // your canvas with text
31
+ * const angle = await service.calculateSkewAngle(canvas);
32
+ * console.log(`Skew angle: ${angle}°`);
33
+ *
34
+ * // Or deskew the image directly
35
+ * const deskewed = await service.deskewImage(canvas);
36
+ * ```
37
+ */
38
+ export declare class DeskewService {
39
+ private readonly verbose;
40
+ private readonly minimumAreaThreshold;
41
+ constructor(options?: DeskewOptions);
42
+ private log;
43
+ /**
44
+ * Calculate the skew angle of text in a probability map or binary image.
45
+ *
46
+ * This method processes the input image to detect text regions and calculates
47
+ * the average skew angle using multiple robust methods.
48
+ *
49
+ * @param canvas - Canvas containing a probability map or binary image of text regions
50
+ * @returns The calculated skew angle in degrees (positive = clockwise, negative = counter-clockwise)
51
+ */
52
+ calculateSkewAngle(canvas: CanvasLike): Promise<number>;
53
+ /**
54
+ * Deskew an image by detecting its skew angle and rotating it.
55
+ *
56
+ * This is a convenience method that combines `calculateSkewAngle()`
57
+ * with rotation to produce a straightened image.
58
+ *
59
+ * @param canvas - Canvas containing the image to deskew
60
+ * @returns A new canvas with the deskewed image
61
+ */
62
+ deskewImage(canvas: CanvasLike): Promise<CanvasLike>;
63
+ private calculateMinRectAngles;
64
+ private calculateBaselineAngles;
65
+ private calculateHoughAngles;
66
+ private calculateLineAngle;
67
+ private calculateConsensusAngle;
68
+ }
package/deskew.js ADDED
@@ -0,0 +1 @@
1
+ export class DeskewService{verbose;minimumAreaThreshold;constructor(options={}){this.verbose=options.verbose??false;this.minimumAreaThreshold=options.minimumAreaThreshold??20}log(message){if(this.verbose){console.log(`[DeskewService] ${message}`)}}async calculateSkewAngle(canvas){let processor=new ImageProcessor(canvas);let mat=processor.grayscale().threshold({lower:0,upper:255,type:cv.THRESH_BINARY+cv.THRESH_OTSU}).toMat();let contours=new Contours(mat,{mode:cv.RETR_LIST,method:cv.CHAIN_APPROX_SIMPLE});processor.destroy();let minAngle=-20;let maxAngle=20;let minArea=this.minimumAreaThreshold;let textRegions=[];contours.iterate((contour)=>{let rect=contours.getRect(contour);let area=rect.width*rect.height;if(area<minArea)return;let aspectRatio=rect.width/rect.height;if(aspectRatio>0.2&&aspectRatio<10){textRegions.push({rect,contour,area,aspectRatio})}});if(textRegions.length===0){this.log("No valid text regions found for skew calculation.");contours.destroy();return 0}let averageHeight=textRegions.reduce((sum,region)=>sum+region.rect.height,0)/textRegions.length;let filteredRegions=textRegions.filter((region)=>{return region.rect.height<=averageHeight*1.5});this.log(`Found ${filteredRegions.length} text regions for skew analysis.`);let minRectAngles=this.calculateMinRectAngles(filteredRegions,contours);let baselineAngles=this.calculateBaselineAngles(filteredRegions);let houghAngles=this.calculateHoughAngles(mat,minAngle,maxAngle);contours.destroy();let allAngles=[...minRectAngles.map((a)=>({...a,method:"minRect"})),...baselineAngles.map((a)=>({...a,method:"baseline"})),...houghAngles.map((a)=>({...a,method:"hough"}))];if(allAngles.length===0){this.log("No angles detected from any method.");return 0}let consensusAngle=this.calculateConsensusAngle(allAngles,minAngle,maxAngle);this.log(`Calculated skew angle: ${consensusAngle.toFixed(3)}° (from ${allAngles.length} measurements)`);return consensusAngle}async deskewImage(canvas){this.log("Starting image deskewing process");let angle=await this.calculateSkewAngle(canvas);this.log(`Detected skew angle: ${angle.toFixed(2)}°. Rotating image by ${-angle.toFixed(2)}°...`);let processor=new ImageProcessor(canvas);try{let rotatedCanvas=processor.rotate({angle}).toCanvas();return rotatedCanvas}finally{processor.destroy()}}calculateMinRectAngles(textRegions,contours){let angles=[];for(let region of textRegions){try{let minRect=cv.minAreaRect(region.contour);if(!minRect)continue;let angle=minRect.angle;if(angle>45){angle-=90}else if(angle<-45){angle+=90}let areaWeight=Math.log(region.area+1);let aspectWeight=Math.min(region.aspectRatio,1/region.aspectRatio)*2;let weight=areaWeight*aspectWeight;angles.push({angle,weight})}catch(error){continue}}return angles}calculateBaselineAngles(textRegions){let angles=[];for(let region of textRegions){try{let points=region.contour.data32S;if(!points||points.length<8)continue;let bottomPoints=[];for(let i=0;i<points.length;i+=2){let x=points[i];let y=points[i+1];if(x!==undefined&&y!==undefined){bottomPoints.push({x,y})}}if(bottomPoints.length<3)continue;bottomPoints.sort((a,b)=>a.x-b.x);let segments=3;let segmentSize=Math.floor(bottomPoints.length/segments);let baselinePoints=[];for(let seg=0;seg<segments;seg++){let start=seg*segmentSize;let end=seg===segments-1?bottomPoints.length:(seg+1)*segmentSize;let segmentPoints=bottomPoints.slice(start,end);if(segmentPoints.length>0){let maxYPoint=segmentPoints.reduce((max,point)=>point.y>max.y?point:max);baselinePoints.push(maxYPoint)}}if(baselinePoints.length>=2){let angle=this.calculateLineAngle(baselinePoints);let weight=region.area*Math.min(region.aspectRatio,1/region.aspectRatio);angles.push({angle,weight})}}catch(error){continue}}return angles}calculateHoughAngles(mat,minAngle,maxAngle){let angles=[];try{let kernel=cv.getStructuringElement(cv.MORPH_RECT,new cv.Size(3,1));let morphed=new cv.Mat;cv.morphologyEx(mat,morphed,cv.MORPH_CLOSE,kernel);let lines=new cv.Mat;cv.HoughLinesP(morphed,lines,1,Math.PI/180,30,50,10);for(let i=0;i<lines.rows;i++){let line=lines.data32S.subarray(i*4,(i+1)*4);const[x1,y1,x2,y2]=line;if(x1!==undefined&&y1!==undefined&&x2!==undefined&&y2!==undefined){let dx=x2-x1;let dy=y2-y1;if(Math.abs(dx)>1){let angle=Math.atan2(dy,dx)*180/Math.PI;if(angle>45)angle-=90;if(angle<-45)angle+=90;if(angle>=minAngle&&angle<=maxAngle){let lineLength=Math.sqrt(dx*dx+dy*dy);angles.push({angle,weight:lineLength})}}}}morphed.delete();lines.delete();kernel.delete()}catch(error){this.log("Hough transform failed, skipping this method.")}return angles}calculateLineAngle(points){if(points.length<2)return 0;let n=points.length;let sumX=points.reduce((sum,p)=>sum+p.x,0);let sumY=points.reduce((sum,p)=>sum+p.y,0);let sumXY=points.reduce((sum,p)=>sum+p.x*p.y,0);let sumXX=points.reduce((sum,p)=>sum+p.x*p.x,0);let denominator=n*sumXX-sumX*sumX;if(Math.abs(denominator)<0.0000000001)return 0;let slope=(n*sumXY-sumX*sumY)/denominator;let angle=Math.atan(slope)*180/Math.PI;if(angle>45)angle-=90;if(angle<-45)angle+=90;return angle}calculateConsensusAngle(angles,minAngle,maxAngle){if(angles.length===0)return 0;let sortedAngles=[...angles].sort((a,b)=>a.angle-b.angle);let q1Index=Math.floor(sortedAngles.length*0.25);let q3Index=Math.floor(sortedAngles.length*0.75);let q1=sortedAngles[q1Index]?.angle||0;let q3=sortedAngles[q3Index]?.angle||0;let iqr=q3-q1;let lowerBound=q1-1.5*iqr;let upperBound=q3+1.5*iqr;let filteredAngles=angles.filter((a)=>a.angle>=lowerBound&&a.angle<=upperBound&&a.angle>=minAngle&&a.angle<=maxAngle);if(filteredAngles.length===0){this.log("All angles filtered out as outliers, using median of original set.");let medianIndex=Math.floor(sortedAngles.length/2);return sortedAngles[medianIndex]?.angle||0}let totalWeight=filteredAngles.reduce((sum,a)=>sum+a.weight,0);if(totalWeight===0){let average=filteredAngles.reduce((sum,a)=>sum+a.angle,0)/filteredAngles.length;return average}let weightedSum=filteredAngles.reduce((sum,a)=>sum+a.angle*a.weight,0);let weightedAverage=weightedSum/totalWeight;let methodCounts=filteredAngles.reduce((counts,a)=>{counts[a.method]=(counts[a.method]||0)+1;return counts},{});this.log(`Angle methods used: ${Object.entries(methodCounts).map(([method,count])=>`${method}:${count}`).join(", ")}`);return Math.max(minAngle,Math.min(maxAngle,weightedAverage))}}import{Contours}from"./contours.js";import{cv}from"./cv-provider.js";import{ImageProcessor}from"./image-processor.js";
@@ -3,13 +3,13 @@
3
3
  * !IMPORTANT: Ensure ImageProcessor.initRuntime() has been called successfully
4
4
  * once before using any functions from this module.
5
5
  */
6
- import type { Canvas } from "./index.js";
6
+ import type { CanvasLike } from "./canvas-factory.js";
7
7
  /**
8
8
  * Options for calculating mean Lab lightness.
9
9
  */
10
10
  export interface CalculateMeanLightnessOptions {
11
11
  /** The canvas containing the image to be processed. */
12
- canvas: Canvas;
12
+ canvas: CanvasLike;
13
13
  /** The target dimensions for analysis (resizes internally). */
14
14
  dimension: {
15
15
  width: number;
@@ -32,4 +32,4 @@ export declare function calculateMeanNormalizedLabLightness(options: CalculateMe
32
32
  * @returns Mean grayscale value (typically 0-255).
33
33
  * @throws Error if OpenCV operations fail.
34
34
  */
35
- export declare function calculateMeanGrayscaleValue(canvas: Canvas): number;
35
+ export declare function calculateMeanGrayscaleValue(canvas: CanvasLike): number;
package/image-analysis.js CHANGED
@@ -1 +1 @@
1
- import{ImageProcessor,cv}from"./index.js";export function calculateMeanNormalizedLabLightness(options){const{canvas,dimension}=options;let processor=null;let resized=null;let labImg=null;let channels=null;let L=null;let mask=null;let scalarMat=null;try{processor=new ImageProcessor(canvas);resized=processor.execute("resize",{width:dimension.width,height:dimension.height}).toMat();labImg=new cv.Mat;cv.cvtColor(resized,labImg,cv.COLOR_BGR2Lab);channels=new cv.MatVector;cv.split(labImg,channels);L=channels.get(0);mask=new cv.Mat;let maxLocResult=cv.minMaxLoc(L,mask);let maxPixelValue=maxLocResult.maxVal;if(maxPixelValue===0){return 0}scalarMat=new cv.Mat(L.rows,L.cols,L.type(),new cv.Scalar(maxPixelValue));cv.divide(L,scalarMat,L,1,-1);let meanL=cv.mean(L)[0];return meanL??0}finally{processor?.destroy();labImg?.delete();channels?.delete();L?.delete();mask?.delete();scalarMat?.delete()}}export function calculateMeanGrayscaleValue(canvas){let processor=null;let grayscaleImg=null;try{processor=new ImageProcessor(canvas);grayscaleImg=processor.blur().grayscale().toMat();let mean=cv.mean(grayscaleImg)[0];return mean??0}finally{processor?.destroy()}}
1
+ import{cv}from"./cv-provider.js";import{ImageProcessor}from"./image-processor.js";export function calculateMeanNormalizedLabLightness(options){const{canvas,dimension}=options;let processor=null;let resized=null;let labImg=null;let channels=null;let L=null;let mask=null;let scalarMat=null;try{processor=new ImageProcessor(canvas);resized=processor.execute("resize",{width:dimension.width,height:dimension.height}).toMat();labImg=new cv.Mat;cv.cvtColor(resized,labImg,cv.COLOR_BGR2Lab);channels=new cv.MatVector;cv.split(labImg,channels);L=channels.get(0);mask=new cv.Mat;let maxLocResult=cv.minMaxLoc(L,mask);let maxPixelValue=maxLocResult.maxVal;if(maxPixelValue===0){return 0}scalarMat=new cv.Mat(L.rows,L.cols,L.type(),new cv.Scalar(maxPixelValue));cv.divide(L,scalarMat,L,1,-1);let meanL=cv.mean(L)[0];return meanL??0}finally{processor?.destroy();labImg?.delete();channels?.delete();L?.delete();mask?.delete();scalarMat?.delete()}}export function calculateMeanGrayscaleValue(canvas){let processor=null;let grayscaleImg=null;try{processor=new ImageProcessor(canvas);grayscaleImg=processor.blur().grayscale().toMat();let mean=cv.mean(grayscaleImg)[0];return mean??0}finally{processor?.destroy()}}
@@ -1,6 +1,6 @@
1
- import { Canvas, cv } from "./index.js";
2
- import type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationName, OperationOptions, RequiredOptions, ResizeOptions, RotateOptions, ThresholdOptions, WarpOptions } from "./index.js";
3
- import type { ConvertOptions } from "./pipeline/index.js";
1
+ import type { CanvasLike } from "./canvas-factory.js";
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";
4
4
  type NameWithRequiredOptions = {
5
5
  [N in OperationName]: OperationOptions<N> extends RequiredOptions ? N : never;
6
6
  }[OperationName];
@@ -11,19 +11,15 @@ export declare class ImageProcessor {
11
11
  height: number;
12
12
  /**
13
13
  * Create an ImageProcessor instance from a Canvas or cv.Mat
14
- * @param source Source image as Canvas or cv.Mat
14
+ * @param source Source image as CanvasLike or cv.Mat
15
15
  */
16
- constructor(source: Canvas | cv.Mat);
16
+ constructor(source: CanvasLike | cv.Mat);
17
17
  /**
18
- * Convert array buffer to canvas
19
- */
20
- static prepareCanvas(file: ArrayBuffer): Promise<Canvas>;
21
- /**
22
- * Convert canvas to array buffer
23
- */
24
- static prepareBuffer(canvas: Canvas): Promise<ArrayBuffer>;
25
- /**
26
- * Initialize OpenCV runtime, this is recommended to be called before any image processing
18
+ * Initialize OpenCV runtime. Must be called before any image processing.
19
+ *
20
+ * - **Node.js**: Uses `@techstark/opencv-js` from node_modules (loaded by entry point).
21
+ * - **Browser with bundler**: Resolves `@techstark/opencv-js` via the bundler.
22
+ * - **Browser without bundler**: Falls back to loading `@techstark/opencv-js` from npm CDN.
27
23
  */
28
24
  static initRuntime(): Promise<void>;
29
25
  /**
@@ -31,47 +27,43 @@ export declare class ImageProcessor {
31
27
  * @param operationName Name of the operation (e.g., "resize")
32
28
  * @param options Required options for the operation
33
29
  */
34
- execute<Name extends NameWithRequiredOptions>(operationName: Name, options: OperationOptions<Name>): this;
30
+ execute<N extends NameWithRequiredOptions>(operationName: N, options: OperationOptions<N>): this;
35
31
  /**
36
- * Execute a registered pipeline operation where options are optional or have defaults.
37
- * @param operationName Name of the operation (e.g., "blur", "grayscale")
38
- * @param options Optional or partial options for the operation
32
+ * Execute a registered pipeline operation that has default options.
33
+ * @param operationName Name of the operation (e.g., "blur")
34
+ * @param options Optional override of the default options
39
35
  */
40
- execute<Name extends NameWithOptionalOptions>(operationName: Name, options?: Partial<OperationOptions<Name>>): this;
36
+ execute<N extends NameWithOptionalOptions>(operationName: N, options?: Partial<OperationOptions<N>>): this;
41
37
  /**
42
38
  * Convert image to grayscale
43
39
  * @description Usage order: independent
44
40
  * @param options Optional configuration for grayscale conversion
45
41
  */
46
42
  grayscale(options?: Partial<GrayscaleOptions>): this;
47
- /**
48
- * Invert image colors
49
- * @description Usage order: ideally (after) threshold or adaptiveThreshold
50
- * @param options Optional configuration for inversion
51
- */
52
- invert(options?: Partial<InvertOptions>): this;
53
- /**
54
- * Add border to image
55
- * @description Usage order: independent
56
- * @param options Border configuration options
57
- */
58
- border(options?: Partial<BorderOptions>): this;
59
43
  /**
60
44
  * Bluring image to reduce noise using Gaussian Blur
61
45
  * @description Usage order: (ideally after) grayscale
62
46
  * @param options Blur configuration options
63
47
  */
64
48
  blur(options?: Partial<BlurOptions>): this;
65
- /** Thresholding to convert image to binary
49
+ /**
50
+ * Thresholding to convert image to binary
66
51
  * @description Usage order: (after) grayscale (and optionally blur)
67
52
  * @param options Thresholding configuration options
68
53
  */
69
54
  threshold(options?: Partial<ThresholdOptions>): this;
70
- /** Adaptive thresholding to convert image to binary
55
+ /**
56
+ * Adaptive thresholding to convert image to binary
71
57
  * @description Usage order: (after) grayscale (and optionally blur)
72
58
  * @param options Adaptive thresholding configuration options
73
59
  */
74
60
  adaptiveThreshold(options?: Partial<AdaptiveThresholdOptions>): this;
61
+ /**
62
+ * Invert image colors
63
+ * @description Usage order: ideally (after) threshold or adaptiveThreshold
64
+ * @param options Optional configuration for inversion
65
+ */
66
+ invert(options?: Partial<InvertOptions>): this;
75
67
  /**
76
68
  * Canny edge detection to detect edges in the image
77
69
  * @description Usage order: (after) grayscale + blur
@@ -79,11 +71,11 @@ export declare class ImageProcessor {
79
71
  */
80
72
  canny(options?: Partial<CannyOptions>): this;
81
73
  /**
82
- * Morphological gradient to highlight the edges in the image
83
- * @description Usage order: (after) dilation + erosion (or threshold)
84
- * @param options Morphological gradient configuration options
74
+ * Dilate image to increase the size of the foreground object
75
+ * @description Usage order: (after) threshold or edge detection
76
+ * @param options Dilation configuration options
85
77
  */
86
- morphologicalGradient(options?: Partial<MorphologicalGradientOptions>): this;
78
+ dilate(options?: Partial<DilateOptions>): this;
87
79
  /**
88
80
  * Erode image to reduce noise
89
81
  * @description Usage order: (after) threshold or edge detection
@@ -91,29 +83,29 @@ export declare class ImageProcessor {
91
83
  */
92
84
  erode(options?: Partial<ErodeOptions>): this;
93
85
  /**
94
- * Dilate image to increase the size of the foreground object
95
- * @description Usage order: (after) threshold or edge detection
96
- * @param options Dilation configuration options
86
+ * Add border to image
87
+ * @description Usage order: independent
88
+ * @param options Border configuration options
97
89
  */
98
- dilate(options?: Partial<DilateOptions>): this;
90
+ border(options?: Partial<BorderOptions>): this;
99
91
  /**
100
92
  * Resize image to a new width and height
101
93
  * @description Usage order: independent
102
- * @param options Resize configuration options
94
+ * @param options Resize configuration options
103
95
  */
104
96
  resize(options: ResizeOptions): this;
105
- /**
106
- * Warp image to a new perspective
107
- * @description Usage order: independent
108
- * @param options Warp configuration options
109
- */
110
- warp(options: WarpOptions): this;
111
97
  /**
112
98
  * Rotate image by a given angle
113
99
  * @description Usage order: independent
114
100
  * @param options Rotate configuration options
115
101
  */
116
102
  rotate(options: RotateOptions): this;
103
+ /**
104
+ * Warp image to a new perspective
105
+ * @description Usage order: independent
106
+ * @param options Warp configuration options
107
+ */
108
+ warp(options: WarpOptions): this;
117
109
  /**
118
110
  * Convert image matrix into new matrix type
119
111
  * @description Usage order: independent
@@ -121,22 +113,22 @@ export declare class ImageProcessor {
121
113
  */
122
114
  convert(options: ConvertOptions): this;
123
115
  /**
124
- * Destroy the image (cv.Mat) stored in image processor state
125
- * @kind non-chainable
126
- * @returns void
116
+ * Morphological gradient to highlight the edges in the image
117
+ * @description Usage order: (after) dilation + erosion (or threshold)
118
+ * @param options Morphological gradient configuration options
127
119
  */
128
- destroy(): void;
120
+ morphologicalGradient(options?: Partial<MorphologicalGradientOptions>): this;
129
121
  /**
130
- * Convert image to cv.Mat
131
- * @kind non-chainable
132
- * @returns cv.Mat
122
+ * Get the result as a cv.Mat
133
123
  */
134
124
  toMat(): cv.Mat;
135
125
  /**
136
- * Convert image (cv.Mat) to Canvas
137
- * @kind non-chainable
138
- * @returns Canvas
126
+ * Get the result canvas
139
127
  */
140
- toCanvas(): Canvas;
128
+ toCanvas(): CanvasLike;
129
+ /**
130
+ * Clean up cv.Mat to free memory
131
+ */
132
+ destroy(): void;
141
133
  }
142
134
  export {};
@@ -1 +1 @@
1
- export class ImageProcessor{img;width;height;constructor(source){if(source instanceof Canvas){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 prepareCanvas(file){if(file instanceof Canvas)return file;let img=await loadImage(file);let canvas=createCanvas(img.width,img.height);let ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);return canvas}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 buffer=Buffer.from(base64Data,"base64");let arrayBuffer=new ArrayBuffer(buffer.byteLength);new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));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}static async initRuntime(){return new Promise((res)=>{if(cv&&cv.Mat){res()}else{cv["onRuntimeInitialized"]=()=>{res()}}})}execute(operationName,options){if(!registry.hasOperation(operationName)){throw new Error(`Operation "${operationName}" not found`)}try{let result=executeOperation(operationName,this.img,options);this.img=result.img;this.width=result.width;this.height=result.height}catch(error){console.error(`Error executing operation "${operationName}":`,error);throw error}return this}grayscale(options={}){return this.execute("grayscale",options)}invert(options={}){return this.execute("invert",options)}border(options={}){return this.execute("border",options)}blur(options={}){return this.execute("blur",options)}threshold(options={}){return this.execute("threshold",options)}adaptiveThreshold(options={}){return this.execute("adaptiveThreshold",options)}canny(options={}){return this.execute("canny",options)}morphologicalGradient(options={}){return this.execute("morphologicalGradient",options)}erode(options={}){return this.execute("erode",options)}dilate(options={}){return this.execute("dilate",options)}resize(options){return this.execute("resize",options)}warp(options){return this.execute("warp",options)}rotate(options){return this.execute("rotate",options)}convert(options){return this.execute("convert",options)}destroy(){this.img.delete()}toMat(){return this.img}toCanvas(){let canvas=createCanvas(this.width,this.height);let ctx=canvas.getContext("2d");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}}import{Canvas,createCanvas,cv,loadImage}from"./index.js";import{executeOperation,registry}from"./index.js";
1
+ export class ImageProcessor{img;width;height;constructor(source){if(getPlatform().isCanvas(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(){if(globalThis.cv?.Mat){setCv(globalThis.cv);return}try{let mod=await import("@techstark/opencv-js");let _cv=mod.default||mod;setCv(_cv);if(!_cv.Mat){await new Promise((res)=>{_cv["onRuntimeInitialized"]=()=>res()})}return}catch{}if(typeof document!=="undefined"){await new Promise((resolve,reject)=>{let script=document.createElement("script");script.src="https://cdn.jsdelivr.net/npm/@techstark/opencv-js@4.10.0-release.1/dist/opencv.js";script.async=true;script.onload=()=>{let g=globalThis;if(g.cv?.Mat){setCv(g.cv);resolve()}else if(g.cv){g.cv["onRuntimeInitialized"]=()=>{setCv(g.cv);resolve()}}else{reject(new Error("OpenCV.js loaded but cv not found on globalThis"))}};script.onerror=()=>reject(new Error("Failed to load @techstark/opencv-js from CDN"));document.head.appendChild(script)});return}throw new Error("Cannot initialize OpenCV runtime. Install @techstark/opencv-js or run in a browser.")}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)}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(e){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}from"./canvas-factory.js";import{cv,setCv}from"./cv-provider.js";import{executeOperation}from"./pipeline/index.js";
@@ -0,0 +1,6 @@
1
+ export type { BoundingBox, Coordinate, Points } from "./index.interface.js";
2
+ export { getPlatform, setPlatform } from "./canvas-factory.js";
3
+ export type { CanvasLike, CanvasPlatform, Context2DLike, } from "./canvas-factory.js";
4
+ export { webPlatform } from "./platform/web.js";
5
+ export { CanvasToolkitBase as CanvasToolkit, CanvasToolkitBase, type ContourLike, } from "./canvas-toolkit.base.js";
6
+ export { CanvasProcessor } from "./canvas-processor.js";
@@ -0,0 +1 @@
1
+ import{setPlatform}from"./canvas-factory.js";import{webPlatform}from"./platform/web.js";setPlatform(webPlatform);export{getPlatform,setPlatform}from"./canvas-factory.js";export{webPlatform}from"./platform/web.js";export{CanvasToolkitBase as CanvasToolkit,CanvasToolkitBase}from"./canvas-toolkit.base.js";export{CanvasProcessor}from"./canvas-processor.js";
@@ -0,0 +1,8 @@
1
+ export { Canvas, createCanvas, ImageData, loadImage } from "@napi-rs/canvas";
2
+ export type { SKRSContext2D } from "@napi-rs/canvas";
3
+ export type { BoundingBox, Coordinate, Points } from "./index.interface.js";
4
+ export { getPlatform, setPlatform } from "./canvas-factory.js";
5
+ export type { CanvasLike, CanvasPlatform, Context2DLike, } from "./canvas-factory.js";
6
+ export { CanvasToolkitBase, type ContourLike } from "./canvas-toolkit.base.js";
7
+ export { CanvasToolkit } from "./canvas-toolkit.js";
8
+ export { CanvasProcessor } from "./canvas-processor.js";
@@ -0,0 +1 @@
1
+ import{setPlatform}from"./canvas-factory.js";import{nodePlatform}from"./platform/node.js";setPlatform(nodePlatform);export{Canvas,createCanvas,ImageData,loadImage}from"@napi-rs/canvas";export{getPlatform,setPlatform}from"./canvas-factory.js";export{CanvasToolkitBase}from"./canvas-toolkit.base.js";export{CanvasToolkit}from"./canvas-toolkit.js";export{CanvasProcessor}from"./canvas-processor.js";
package/index.d.ts CHANGED
@@ -1,11 +1,16 @@
1
- import cv from "@techstark/opencv-js";
1
+ import { cv } from "./cv-provider.js";
2
2
  export { cv };
3
3
  export { Canvas, createCanvas, ImageData, loadImage } from "@napi-rs/canvas";
4
4
  export type { SKRSContext2D } from "@napi-rs/canvas";
5
5
  export type { BoundingBox, Coordinate, Points } from "./index.interface.js";
6
6
  export { executeOperation, OperationRegistry, registry, } from "./pipeline/index.js";
7
+ export { getPlatform, setPlatform } from "./canvas-factory.js";
8
+ export type { CanvasLike, CanvasPlatform, Context2DLike, } from "./canvas-factory.js";
9
+ export { CanvasToolkitBase, type ContourLike } from "./canvas-toolkit.base.js";
7
10
  export { CanvasToolkit } from "./canvas-toolkit.js";
11
+ export { CanvasProcessor } from "./canvas-processor.js";
8
12
  export { Contours } from "./contours.js";
9
13
  export { calculateMeanGrayscaleValue, calculateMeanNormalizedLabLightness, type CalculateMeanLightnessOptions, } from "./image-analysis.js";
10
14
  export { ImageProcessor } from "./image-processor.js";
15
+ export { DeskewService, type DeskewOptions } from "./deskew.js";
11
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";
package/index.js CHANGED
@@ -1 +1 @@
1
- import cv from"@techstark/opencv-js";export{cv};export{Canvas,createCanvas,ImageData,loadImage}from"@napi-rs/canvas";export{executeOperation,OperationRegistry,registry}from"./pipeline/index.js";export{CanvasToolkit}from"./canvas-toolkit.js";export{Contours}from"./contours.js";export{calculateMeanGrayscaleValue,calculateMeanNormalizedLabLightness}from"./image-analysis.js";export{ImageProcessor}from"./image-processor.js";
1
+ import _cv from"@techstark/opencv-js";import{cv,setCv}from"./cv-provider.js";setCv(_cv);export{cv};import{setPlatform}from"./canvas-factory.js";import{nodePlatform}from"./platform/node.js";setPlatform(nodePlatform);export{Canvas,createCanvas,ImageData,loadImage}from"@napi-rs/canvas";export{executeOperation,OperationRegistry,registry}from"./pipeline/index.js";export{getPlatform,setPlatform}from"./canvas-factory.js";export{CanvasToolkitBase}from"./canvas-toolkit.base.js";export{CanvasToolkit}from"./canvas-toolkit.js";export{CanvasProcessor}from"./canvas-processor.js";export{Contours}from"./contours.js";export{calculateMeanGrayscaleValue,calculateMeanNormalizedLabLightness}from"./image-analysis.js";export{ImageProcessor}from"./image-processor.js";export{DeskewService}from"./deskew.js";
package/index.web.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { cv } from "./cv-provider.js";
2
+ export { cv };
3
+ export { getPlatform, setPlatform } from "./canvas-factory.js";
4
+ export type { CanvasLike, CanvasPlatform, Context2DLike, } from "./canvas-factory.js";
5
+ export { webPlatform } from "./platform/web.js";
6
+ export type { BoundingBox, Coordinate, Points } from "./index.interface.js";
7
+ export { executeOperation, OperationRegistry, registry, } from "./pipeline/index.js";
8
+ export { CanvasToolkitBase as CanvasToolkit, CanvasToolkitBase, type ContourLike, } from "./canvas-toolkit.base.js";
9
+ export { CanvasProcessor } from "./canvas-processor.js";
10
+ export { Contours } from "./contours.js";
11
+ export { calculateMeanGrayscaleValue, calculateMeanNormalizedLabLightness, type CalculateMeanLightnessOptions, } from "./image-analysis.js";
12
+ export { ImageProcessor } from "./image-processor.js";
13
+ export { DeskewService, type DeskewOptions } from "./deskew.js";
14
+ 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";
package/index.web.js ADDED
@@ -0,0 +1 @@
1
+ import{cv}from"./cv-provider.js";export{cv};import{setPlatform}from"./canvas-factory.js";import{webPlatform}from"./platform/web.js";setPlatform(webPlatform);export{getPlatform,setPlatform}from"./canvas-factory.js";export{webPlatform}from"./platform/web.js";export{executeOperation,OperationRegistry,registry}from"./pipeline/index.js";export{CanvasToolkitBase as CanvasToolkit,CanvasToolkitBase}from"./canvas-toolkit.base.js";export{CanvasProcessor}from"./canvas-processor.js";export{Contours}from"./contours.js";export{calculateMeanGrayscaleValue,calculateMeanNormalizedLabLightness}from"./image-analysis.js";export{ImageProcessor}from"./image-processor.js";export{DeskewService}from"./deskew.js";
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import { cv } from "../cv-provider.js";
2
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  adaptiveThreshold: AdaptiveThresholdOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{upper:255,method:cv.ADAPTIVE_THRESH_GAUSSIAN_C,type:cv.THRESH_BINARY_INV,size:7,constant:2}}export function adaptiveThreshold(img,options){let imgAdaptiveThreshold=new cv.Mat;cv.adaptiveThreshold(img,imgAdaptiveThreshold,options.upper,options.method,options.type,options.size,options.constant);img.delete();return{img:imgAdaptiveThreshold,width:imgAdaptiveThreshold.cols,height:imgAdaptiveThreshold.rows}}registry.register("adaptiveThreshold",adaptiveThreshold,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{upper:255,method:cv.ADAPTIVE_THRESH_GAUSSIAN_C,type:cv.THRESH_BINARY_INV,size:7,constant:2}}export function adaptiveThreshold(img,options){let imgAdaptiveThreshold=new cv.Mat;cv.adaptiveThreshold(img,imgAdaptiveThreshold,options.upper,options.method,options.type,options.size,options.constant);img.delete();return{img:imgAdaptiveThreshold,width:imgAdaptiveThreshold.cols,height:imgAdaptiveThreshold.rows}}registry.register("adaptiveThreshold",adaptiveThreshold,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import { cv } from "../cv-provider.js";
2
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  blur: BlurOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{size:[5,5],sigma:0}}export function blur(img,options){let imgBlur=new cv.Mat;cv.GaussianBlur(img,imgBlur,new cv.Size(options.size[0],options.size[1]),options.sigma);img.delete();return{img:imgBlur,width:imgBlur.cols,height:imgBlur.rows}}registry.register("blur",blur,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{size:[5,5],sigma:0}}export function blur(img,options){let imgBlur=new cv.Mat;cv.GaussianBlur(img,imgBlur,new cv.Size(options.size[0],options.size[1]),options.sigma);img.delete();return{img:imgBlur,width:imgBlur.cols,height:imgBlur.rows}}registry.register("blur",blur,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  border: BorderOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{size:10,borderType:cv.BORDER_CONSTANT,borderColor:[255,255,255,255]}}export function border(img,options){let imgBorder=new cv.Mat;cv.copyMakeBorder(img,imgBorder,options.size,options.size,options.size,options.size,options.borderType,options.borderColor);img.delete();return{img:imgBorder,width:imgBorder.cols,height:imgBorder.rows}}registry.register("border",border,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{size:10,borderType:cv.BORDER_CONSTANT,borderColor:[255,255,255,255]}}export function border(img,options){let imgBorder=new cv.Mat;cv.copyMakeBorder(img,imgBorder,options.size,options.size,options.size,options.size,options.borderType,options.borderColor);img.delete();return{img:imgBorder,width:imgBorder.cols,height:imgBorder.rows}}registry.register("border",border,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  canny: CannyOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{lower:50,upper:150}}export function canny(img,options){let imgCanny=new cv.Mat;cv.Canny(img,imgCanny,options.lower,options.upper);img.delete();return{img:imgCanny,width:imgCanny.cols,height:imgCanny.rows}}registry.register("canny",canny,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{lower:50,upper:150}}export function canny(img,options){let imgCanny=new cv.Mat;cv.Canny(img,imgCanny,options.lower,options.upper);img.delete();return{img:imgCanny,width:imgCanny.cols,height:imgCanny.rows}}registry.register("canny",canny,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, RequiredOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, RequiredOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  convert: ConvertOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";export function convert(img,options){if(options.rtype===undefined){throw new Error("Invalid options: rtype is required")}let imgConvert=new cv.Mat;img.convertTo(imgConvert,options.rtype);img.delete();return{img:imgConvert,width:imgConvert.cols,height:imgConvert.rows}}registry.register("convert",convert);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";export function convert(img,options){if(options.rtype===undefined){throw new Error("Invalid options: rtype is required")}let imgConvert=new cv.Mat;img.convertTo(imgConvert,options.rtype);img.delete();return{img:imgConvert,width:imgConvert.cols,height:imgConvert.rows}}registry.register("convert",convert);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  dilate: DilateOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{size:[5,5],iter:1}}export function dilate(img,options){let imgDilate=new cv.Mat;let kernel=cv.getStructuringElement(cv.MORPH_RECT,new cv.Size(options.size[0],options.size[1]));cv.dilate(img,imgDilate,kernel,new cv.Point(-1,-1),options.iter);img.delete();return{img:imgDilate,width:imgDilate.cols,height:imgDilate.rows}}registry.register("dilate",dilate,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{size:[5,5],iter:1}}export function dilate(img,options){let imgDilate=new cv.Mat;let kernel=cv.getStructuringElement(cv.MORPH_RECT,new cv.Size(options.size[0],options.size[1]));cv.dilate(img,imgDilate,kernel,new cv.Point(-1,-1),options.iter);img.delete();return{img:imgDilate,width:imgDilate.cols,height:imgDilate.rows}}registry.register("dilate",dilate,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  erode: ErodeOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{size:[5,5],iter:1}}export function erode(img,options){let imgErode=new cv.Mat;let kernel=cv.getStructuringElement(cv.MORPH_RECT,new cv.Size(options.size[0],options.size[1]));cv.erode(img,imgErode,kernel,new cv.Point(-1,-1),options.iter);img.delete();return{img:imgErode,width:imgErode.cols,height:imgErode.rows}}registry.register("erode",erode,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{size:[5,5],iter:1}}export function erode(img,options){let imgErode=new cv.Mat;let kernel=cv.getStructuringElement(cv.MORPH_RECT,new cv.Size(options.size[0],options.size[1]));cv.erode(img,imgErode,kernel,new cv.Point(-1,-1),options.iter);img.delete();return{img:imgErode,width:imgErode.cols,height:imgErode.rows}}registry.register("erode",erode,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  grayscale: GrayscaleOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{}}export function grayscale(img,options){let imgGrayscale=new cv.Mat;cv.cvtColor(img,imgGrayscale,cv.COLOR_RGBA2GRAY);img.delete();return{img:imgGrayscale,width:imgGrayscale.cols,height:imgGrayscale.rows}}registry.register("grayscale",grayscale,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{}}export function grayscale(img,options){let imgGrayscale=new cv.Mat;cv.cvtColor(img,imgGrayscale,cv.COLOR_RGBA2GRAY);img.delete();return{img:imgGrayscale,width:imgGrayscale.cols,height:imgGrayscale.rows}}registry.register("grayscale",grayscale,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  invert: InvertOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"../index.js";function defaultOptions(){return{}}export function invert(img,options){let imgInvert=new cv.Mat;cv.bitwise_not(img,imgInvert);img.delete();return{img:imgInvert,width:imgInvert.cols,height:imgInvert.rows}}registry.register("invert",invert,defaultOptions);
1
+ import{cv}from"../cv-provider.js";import{registry}from"../pipeline/registry.js";function defaultOptions(){return{}}export function invert(img,options){let imgInvert=new cv.Mat;cv.bitwise_not(img,imgInvert);img.delete();return{img:imgInvert,width:imgInvert.cols,height:imgInvert.rows}}registry.register("invert",invert,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "../index.js";
2
- import { cv } from "../index.js";
3
- declare module "../index" {
1
+ import type { OperationResult, PartialOptions } from "../pipeline/types.js";
2
+ import { cv } from "../cv-provider.js";
3
+ declare module "../pipeline/types" {
4
4
  interface RegisteredOperations {
5
5
  morphologicalGradient: MorphologicalGradientOptions;
6
6
  }