ppu-ocv 0.0.2 → 1.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.
@@ -1,5 +1,5 @@
1
- import type { BoundingBox, SKRSContext2D } from "@/index";
2
- import { Canvas, cv } from "@/index";
1
+ import type { BoundingBox, SKRSContext2D } from "./index";
2
+ import { Canvas, cv } from "./index";
3
3
  export declare class CanvasToolkit {
4
4
  private step;
5
5
  /**
package/canvas-toolkit.js CHANGED
@@ -1 +1 @@
1
- export class CanvasToolkit{step=0;crop(options){const{bbox,canvas}=options;let croppedCanvas=createCanvas(bbox.x1-bbox.x0,bbox.y1-bbox.y0);let croppedCtx=croppedCanvas.getContext("2d");croppedCtx.drawImage(canvas,bbox.x0,bbox.y0,bbox.x1-bbox.x0,bbox.y1-bbox.y0,0,0,croppedCanvas.width,croppedCanvas.height);return croppedCanvas}isDirty(options){const{canvas,threshold=127.5,majorColorThreshold=0.97}=options;let whiteCount=0;let blackCount=0;let borderlessCanvas=this.crop({bbox:{x0:canvas.width*0.1,y0:canvas.height*0.1,x1:canvas.width*0.9,y1:canvas.height*0.9},canvas});let ctx=borderlessCanvas.getContext("2d");let colorData=ctx.getImageData(0,0,borderlessCanvas.width,borderlessCanvas.height).data;for(let i=0;i<colorData.length;i+=4){let red=colorData[i];let green=colorData[i+1];let blue=colorData[i+2];if(red>=threshold&&green>=threshold&&blue>=threshold){whiteCount++}else{blackCount++}}let majorColorRatio=Math.max(whiteCount,blackCount)/(blackCount+whiteCount);return majorColorRatio<majorColorThreshold}saveImage(options){const{canvas,filename,path="out"}=options;let folderPath=join(process.cwd(),path);if(!existsSync(folderPath)){mkdirSync(folderPath,{recursive:true})}let filePath=join(folderPath,`${this.step++}. ${filename}.png`);let out=createWriteStream(filePath);let buffer=canvas.toBuffer("image/png");return new Promise((res,rej)=>{out.write(buffer,(err)=>{if(err){rej(err)}else{res()}})})}clearOutput(path="out"){let folderPath=join(process.cwd(),path);if(existsSync(folderPath)){let files=readdirSync(folderPath);for(let file of files){if(file===".gitignore")continue;let filePath=join(folderPath,file);unlinkSync(filePath)}}}drawLine(options){const{ctx,x,y,width,height,lineWidth=2,color="blue"}=options;ctx.beginPath();ctx.strokeStyle=color;ctx.lineWidth=lineWidth;ctx.strokeRect(x,y,width,height);ctx.closePath()}drawContour(options){const{ctx,contour,strokeStyle="red",lineWidth=2}=options;let pts=contour.data32S;if(pts.length<4)return;ctx.strokeStyle=strokeStyle;ctx.lineWidth=lineWidth;ctx.beginPath();ctx.moveTo(pts[0],pts[1]);for(let i=2;i<pts.length;i+=2){ctx.lineTo(pts[i],pts[i+1])}ctx.closePath();ctx.stroke()}}import{createCanvas}from"@/index";import{createWriteStream,existsSync,mkdirSync,readdirSync,unlinkSync}from"fs";import{join}from"path";
1
+ export class CanvasToolkit{step=0;crop(options){const{bbox,canvas}=options;let croppedCanvas=createCanvas(bbox.x1-bbox.x0,bbox.y1-bbox.y0);let croppedCtx=croppedCanvas.getContext("2d");croppedCtx.drawImage(canvas,bbox.x0,bbox.y0,bbox.x1-bbox.x0,bbox.y1-bbox.y0,0,0,croppedCanvas.width,croppedCanvas.height);return croppedCanvas}isDirty(options){const{canvas,threshold=127.5,majorColorThreshold=0.97}=options;let whiteCount=0;let blackCount=0;let borderlessCanvas=this.crop({bbox:{x0:canvas.width*0.1,y0:canvas.height*0.1,x1:canvas.width*0.9,y1:canvas.height*0.9},canvas});let ctx=borderlessCanvas.getContext("2d");let colorData=ctx.getImageData(0,0,borderlessCanvas.width,borderlessCanvas.height).data;for(let i=0;i<colorData.length;i+=4){let red=colorData[i];let green=colorData[i+1];let blue=colorData[i+2];if(red>=threshold&&green>=threshold&&blue>=threshold){whiteCount++}else{blackCount++}}let majorColorRatio=Math.max(whiteCount,blackCount)/(blackCount+whiteCount);return majorColorRatio<majorColorThreshold}saveImage(options){const{canvas,filename,path="out"}=options;let folderPath=join(process.cwd(),path);if(!existsSync(folderPath)){mkdirSync(folderPath,{recursive:true})}let filePath=join(folderPath,`${this.step++}. ${filename}.png`);let out=createWriteStream(filePath);let buffer=canvas.toBuffer("image/png");return new Promise((res,rej)=>{out.write(buffer,(err)=>{if(err){rej(err)}else{res()}})})}clearOutput(path="out"){let folderPath=join(process.cwd(),path);if(existsSync(folderPath)){let files=readdirSync(folderPath);for(let file of files){if(file===".gitignore")continue;let filePath=join(folderPath,file);unlinkSync(filePath)}}}drawLine(options){const{ctx,x,y,width,height,lineWidth=2,color="blue"}=options;ctx.beginPath();ctx.strokeStyle=color;ctx.lineWidth=lineWidth;ctx.strokeRect(x,y,width,height);ctx.closePath()}drawContour(options){const{ctx,contour,strokeStyle="red",lineWidth=2}=options;let pts=contour.data32S;if(pts.length<4)return;ctx.strokeStyle=strokeStyle;ctx.lineWidth=lineWidth;ctx.beginPath();ctx.moveTo(pts[0],pts[1]);for(let i=2;i<pts.length;i+=2){ctx.lineTo(pts[i],pts[i+1])}ctx.closePath();ctx.stroke()}}import{createCanvas}from"./index";import{createWriteStream,existsSync,mkdirSync,readdirSync,unlinkSync}from"fs";import{join}from"path";
package/contours.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { BoundingBox, Canvas, Points } from "@/index";
2
- import { cv } from "@/index";
1
+ import type { BoundingBox, Canvas, Points } from "./index";
2
+ import { cv } from "./index";
3
3
  export interface ContoursOptions {
4
4
  /** The contour retrieval mode. (cv.RETR_...) */
5
5
  mode: cv.RetrievalModes;
package/contours.js CHANGED
@@ -1 +1 @@
1
- export class Contours{contours;constructor(img,options={}){let opts={...defaultOptions(),...options};if(img instanceof cv.Mat){let contours=new cv.MatVector;let hierarchy=new cv.Mat;try{cv.findContours(img,contours,hierarchy,opts.mode,opts.method)}catch(error){throw error}hierarchy.delete();this.contours=contours}else{throw new Error("Invalid img type. Must be cv.Mat.")}}getAll(){return this.contours}getFromIndex(index){if(index<this.contours.size()){return this.contours.get(index)}return new cv.Mat}getRect(contour){return cv.boundingRect(contour)}iterate(callback){for(let i=0,len=this.contours.size();i<len;i++){let contour=this.contours.get(i);callback(contour)}return this}getLargestContourArea(){let maxArea=0;let largestContour=null;this.iterate((contour)=>{let area=cv.contourArea(contour);if(area>maxArea){maxArea=area;largestContour=contour}});return largestContour}getCornerPoints(options){const{canvas,contour=this.getLargestContourArea()}=options;let bbox={x0:0,y0:0,x1:canvas.width,y1:canvas.height};if(!contour){return{points:{topLeft:{x:bbox.x0,y:bbox.y0},topRight:{x:bbox.x1,y:bbox.y0},bottomLeft:{x:bbox.x0,y:bbox.y1},bottomRight:{x:bbox.x1,y:bbox.y1}},bbox}}let rect=cv.minAreaRect(contour);let vertices=cv.RotatedRect.points(rect);let points={topLeft:{x:0,y:0},topRight:{x:0,y:0},bottomRight:{x:0,y:0},bottomLeft:{x:0,y:0}};let sums=vertices.map((pt)=>pt.x+pt.y);let diffs=vertices.map((pt)=>pt.y-pt.x);let topLeftIdx=sums.indexOf(Math.min(...sums));let topRightIdx=diffs.indexOf(Math.min(...diffs));let bottomRightIdx=sums.indexOf(Math.max(...sums));let bottomLeftIdx=diffs.indexOf(Math.max(...diffs));if(!vertices[topLeftIdx]||!vertices[topRightIdx]||!vertices[bottomRightIdx]||!vertices[bottomLeftIdx]){return{points:{topLeft:{x:bbox.x0,y:bbox.y0},topRight:{x:bbox.x1,y:bbox.y0},bottomLeft:{x:bbox.x0,y:bbox.y1},bottomRight:{x:bbox.x1,y:bbox.y1}},bbox}}points.topLeft={x:vertices[topLeftIdx].x,y:vertices[topLeftIdx].y};points.topRight={x:vertices[topRightIdx].x,y:vertices[topRightIdx].y};points.bottomRight={x:vertices[bottomRightIdx].x,y:vertices[bottomRightIdx].y};points.bottomLeft={x:vertices[bottomLeftIdx].x,y:vertices[bottomLeftIdx].y};contour.delete();let ensureInBounds=(p)=>{p.x=Math.max(0,Math.min(canvas.width,p.x));p.y=Math.max(0,Math.min(canvas.height,p.y));return p};points.topLeft=ensureInBounds(points.topLeft);points.topRight=ensureInBounds(points.topRight);points.bottomLeft=ensureInBounds(points.bottomLeft);points.bottomRight=ensureInBounds(points.bottomRight);return{points,bbox}}destroy(){try{this.contours.delete()}catch(error){}}}import{cv}from"@/index";function defaultOptions(){return{mode:cv.RETR_EXTERNAL,method:cv.CHAIN_APPROX_SIMPLE}}
1
+ export class Contours{contours;constructor(img,options={}){let opts={...defaultOptions(),...options};if(img instanceof cv.Mat){let contours=new cv.MatVector;let hierarchy=new cv.Mat;try{cv.findContours(img,contours,hierarchy,opts.mode,opts.method)}catch(error){throw error}hierarchy.delete();this.contours=contours}else{throw new Error("Invalid img type. Must be cv.Mat.")}}getAll(){return this.contours}getFromIndex(index){if(index<this.contours.size()){return this.contours.get(index)}return new cv.Mat}getRect(contour){return cv.boundingRect(contour)}iterate(callback){for(let i=0,len=this.contours.size();i<len;i++){let contour=this.contours.get(i);callback(contour)}return this}getLargestContourArea(){let maxArea=0;let largestContour=null;this.iterate((contour)=>{let area=cv.contourArea(contour);if(area>maxArea){maxArea=area;largestContour=contour}});return largestContour}getCornerPoints(options){const{canvas,contour=this.getLargestContourArea()}=options;let bbox={x0:0,y0:0,x1:canvas.width,y1:canvas.height};if(!contour){return{points:{topLeft:{x:bbox.x0,y:bbox.y0},topRight:{x:bbox.x1,y:bbox.y0},bottomLeft:{x:bbox.x0,y:bbox.y1},bottomRight:{x:bbox.x1,y:bbox.y1}},bbox}}let rect=cv.minAreaRect(contour);let vertices=cv.RotatedRect.points(rect);let points={topLeft:{x:0,y:0},topRight:{x:0,y:0},bottomRight:{x:0,y:0},bottomLeft:{x:0,y:0}};let sums=vertices.map((pt)=>pt.x+pt.y);let diffs=vertices.map((pt)=>pt.y-pt.x);let topLeftIdx=sums.indexOf(Math.min(...sums));let topRightIdx=diffs.indexOf(Math.min(...diffs));let bottomRightIdx=sums.indexOf(Math.max(...sums));let bottomLeftIdx=diffs.indexOf(Math.max(...diffs));if(!vertices[topLeftIdx]||!vertices[topRightIdx]||!vertices[bottomRightIdx]||!vertices[bottomLeftIdx]){return{points:{topLeft:{x:bbox.x0,y:bbox.y0},topRight:{x:bbox.x1,y:bbox.y0},bottomLeft:{x:bbox.x0,y:bbox.y1},bottomRight:{x:bbox.x1,y:bbox.y1}},bbox}}points.topLeft={x:vertices[topLeftIdx].x,y:vertices[topLeftIdx].y};points.topRight={x:vertices[topRightIdx].x,y:vertices[topRightIdx].y};points.bottomRight={x:vertices[bottomRightIdx].x,y:vertices[bottomRightIdx].y};points.bottomLeft={x:vertices[bottomLeftIdx].x,y:vertices[bottomLeftIdx].y};contour.delete();let ensureInBounds=(p)=>{p.x=Math.max(0,Math.min(canvas.width,p.x));p.y=Math.max(0,Math.min(canvas.height,p.y));return p};points.topLeft=ensureInBounds(points.topLeft);points.topRight=ensureInBounds(points.topRight);points.bottomLeft=ensureInBounds(points.bottomLeft);points.bottomRight=ensureInBounds(points.bottomRight);return{points,bbox}}destroy(){try{this.contours.delete()}catch(error){}}}import{cv}from"./index";function defaultOptions(){return{mode:cv.RETR_EXTERNAL,method:cv.CHAIN_APPROX_SIMPLE}}
@@ -3,7 +3,7 @@
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";
6
+ import type { Canvas } from "./index";
7
7
  /**
8
8
  * Options for calculating mean Lab lightness.
9
9
  */
package/image-analysis.js CHANGED
@@ -1 +1 @@
1
- import{ImageProcessor,cv}from"@/index";export async 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 async 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{ImageProcessor,cv}from"./index";export async 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 async 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,5 +1,5 @@
1
- import { Canvas, cv } from "@/index";
2
- import type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationName, OperationOptions, RequiredOptions, ResizeOptions, ThresholdOptions, WarpOptions } from "@/index";
1
+ import { Canvas, cv } from "./index";
2
+ import type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationName, OperationOptions, RequiredOptions, ResizeOptions, ThresholdOptions, WarpOptions } from "./index";
3
3
  type NameWithRequiredOptions = {
4
4
  [N in OperationName]: OperationOptions<N> extends RequiredOptions ? N : never;
5
5
  }[OperationName];
@@ -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){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 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)}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";import{executeOperation,registry}from"@/index";
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){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 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)}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";import{executeOperation,registry}from"./index";
package/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import cv from "@techstark/opencv-js";
2
2
  export { cv };
3
- export type { BoundingBox, Coordinate, Points } from "@/index.interface";
4
- export { executeOperation, OperationRegistry, registry } from "@/pipeline";
5
3
  export { Canvas, createCanvas, loadImage } from "@napi-rs/canvas";
6
4
  export type { SKRSContext2D } from "@napi-rs/canvas";
7
- export { CanvasToolkit } from "@/canvas-toolkit";
8
- export { Contours } from "@/contours";
9
- export { calculateMeanGrayscaleValue, calculateMeanNormalizedLabLightness, type CalculateMeanLightnessOptions, } from "@/image-analysis";
10
- export { ImageProcessor } from "@/image-processor";
11
- export type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationFunction, OperationName, OperationOptions, OperationResult, PartialOptions, RegisteredOperations, RequiredOptions, ResizeOptions, ThresholdOptions, WarpOptions, } from "@/pipeline";
5
+ export type { BoundingBox, Coordinate, Points } from "./index.interface";
6
+ export { executeOperation, OperationRegistry, registry } from "./pipeline";
7
+ export { CanvasToolkit } from "./canvas-toolkit";
8
+ export { Contours } from "./contours";
9
+ export { calculateMeanGrayscaleValue, calculateMeanNormalizedLabLightness, type CalculateMeanLightnessOptions, } from "./image-analysis";
10
+ export { ImageProcessor } from "./image-processor";
11
+ export type { AdaptiveThresholdOptions, BlurOptions, BorderOptions, CannyOptions, DilateOptions, ErodeOptions, GrayscaleOptions, InvertOptions, MorphologicalGradientOptions, OperationFunction, OperationName, OperationOptions, OperationResult, PartialOptions, RegisteredOperations, RequiredOptions, ResizeOptions, ThresholdOptions, WarpOptions, } from "./pipeline";
package/index.js CHANGED
@@ -1 +1 @@
1
- import cv from"@techstark/opencv-js";export{cv};export{executeOperation,OperationRegistry,registry}from"@/pipeline";export{Canvas,createCanvas,loadImage}from"@napi-rs/canvas";export{CanvasToolkit}from"@/canvas-toolkit";export{Contours}from"@/contours";export{calculateMeanGrayscaleValue,calculateMeanNormalizedLabLightness}from"@/image-analysis";export{ImageProcessor}from"@/image-processor";
1
+ import cv from"@techstark/opencv-js";export{cv};export{Canvas,createCanvas,loadImage}from"@napi-rs/canvas";export{executeOperation,OperationRegistry,registry}from"./pipeline";export{CanvasToolkit}from"./canvas-toolkit";export{Contours}from"./contours";export{calculateMeanGrayscaleValue,calculateMeanNormalizedLabLightness}from"./image-analysis";export{ImageProcessor}from"./image-processor";
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "@/index";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  adaptiveThreshold: AdaptiveThresholdOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  blur: BlurOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  border: BorderOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  canny: CannyOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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, PartialOptions } from "@/index";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  dilate: DilateOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  erode: ErodeOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  grayscale: GrayscaleOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  invert: InvertOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";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,registry}from"../index";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";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  morphologicalGradient: MorphologicalGradientOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";function defaultOptions(){return{size:[3,3]}}export function morphologicalGradient(img,options){let imgMorphologicalGradient=new cv.Mat;let kernel=cv.getStructuringElement(cv.MORPH_RECT,new cv.Size(options.size[0],options.size[1]));cv.morphologyEx(img,imgMorphologicalGradient,cv.MORPH_GRADIENT,kernel);img.delete();return{img:imgMorphologicalGradient,width:imgMorphologicalGradient.cols,height:imgMorphologicalGradient.rows}}registry.register("morphologicalGradient",morphologicalGradient,defaultOptions);
1
+ import{cv,registry}from"../index";function defaultOptions(){return{size:[3,3]}}export function morphologicalGradient(img,options){let imgMorphologicalGradient=new cv.Mat;let kernel=cv.getStructuringElement(cv.MORPH_RECT,new cv.Size(options.size[0],options.size[1]));cv.morphologyEx(img,imgMorphologicalGradient,cv.MORPH_GRADIENT,kernel);img.delete();return{img:imgMorphologicalGradient,width:imgMorphologicalGradient.cols,height:imgMorphologicalGradient.rows}}registry.register("morphologicalGradient",morphologicalGradient,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, RequiredOptions } from "@/index";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, RequiredOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  resize: ResizeOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";export function resize(img,options){if(!options.width||!options.height){throw new Error("Invalid options: width and height are required")}let imgResize=new cv.Mat;cv.resize(img,imgResize,new cv.Size(options.width,options.height));img.delete();return{img:imgResize,width:imgResize.cols,height:imgResize.rows}}registry.register("resize",resize);
1
+ import{cv,registry}from"../index";export function resize(img,options){if(!options.width||!options.height){throw new Error("Invalid options: width and height are required")}let imgResize=new cv.Mat;cv.resize(img,imgResize,new cv.Size(options.width,options.height));img.delete();return{img:imgResize,width:imgResize.cols,height:imgResize.rows}}registry.register("resize",resize);
@@ -1,6 +1,6 @@
1
- import type { OperationResult, PartialOptions } from "@/index";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { OperationResult, PartialOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  threshold: ThresholdOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";function defaultOptions(){return{lower:0,upper:255,type:cv.THRESH_BINARY_INV+cv.THRESH_OTSU}}export function threshold(img,options){let imgThreshold=new cv.Mat;cv.threshold(img,imgThreshold,options.lower,options.upper,options.type);img.delete();return{img:imgThreshold,width:imgThreshold.cols,height:imgThreshold.rows}}registry.register("threshold",threshold,defaultOptions);
1
+ import{cv,registry}from"../index";function defaultOptions(){return{lower:0,upper:255,type:cv.THRESH_BINARY_INV+cv.THRESH_OTSU}}export function threshold(img,options){let imgThreshold=new cv.Mat;cv.threshold(img,imgThreshold,options.lower,options.upper,options.type);img.delete();return{img:imgThreshold,width:imgThreshold.cols,height:imgThreshold.rows}}registry.register("threshold",threshold,defaultOptions);
@@ -1,6 +1,6 @@
1
- import type { BoundingBox, OperationResult, Points, RequiredOptions } from "@/index";
2
- import { cv } from "@/index";
3
- declare module "@/pipeline/types" {
1
+ import type { BoundingBox, OperationResult, Points, RequiredOptions } from "../index";
2
+ import { cv } from "../index";
3
+ declare module "../index" {
4
4
  interface RegisteredOperations {
5
5
  warp: WarpOptions;
6
6
  }
@@ -1 +1 @@
1
- import{cv,registry}from"@/index";export function warp(img,options){if(!options.points||!options.bbox){throw new Error("Invalid options: points and bbox are required")}const{points,bbox}=options;let imgWarp=new cv.Mat;let targetWidth=bbox.x1-bbox.x0;let targetHeight=bbox.y1-bbox.y0;let destArray=[0,0,targetWidth-1,0,targetWidth-1,targetHeight-1,0,targetHeight-1];let srcArray=[points.topLeft.x,points.topLeft.y,points.topRight.x,points.topRight.y,points.bottomRight.x,points.bottomRight.y,points.bottomLeft.x,points.bottomLeft.y];let dest=cv.matFromArray(4,1,cv.CV_32FC2,destArray);let src=cv.matFromArray(4,1,cv.CV_32FC2,srcArray);let M=cv.getPerspectiveTransform(src,dest);let dsize=new cv.Size(targetWidth,targetHeight);cv.warpPerspective(img,imgWarp,M,dsize);M.delete();src.delete();dest.delete();img.delete();return{img:imgWarp,width:imgWarp.cols,height:imgWarp.rows}}registry.register("warp",warp);
1
+ import{cv,registry}from"../index";export function warp(img,options){if(!options.points||!options.bbox){throw new Error("Invalid options: points and bbox are required")}const{points,bbox}=options;let imgWarp=new cv.Mat;let targetWidth=bbox.x1-bbox.x0;let targetHeight=bbox.y1-bbox.y0;let destArray=[0,0,targetWidth-1,0,targetWidth-1,targetHeight-1,0,targetHeight-1];let srcArray=[points.topLeft.x,points.topLeft.y,points.topRight.x,points.topRight.y,points.bottomRight.x,points.bottomRight.y,points.bottomLeft.x,points.bottomLeft.y];let dest=cv.matFromArray(4,1,cv.CV_32FC2,destArray);let src=cv.matFromArray(4,1,cv.CV_32FC2,srcArray);let M=cv.getPerspectiveTransform(src,dest);let dsize=new cv.Size(targetWidth,targetHeight);cv.warpPerspective(img,imgWarp,M,dsize);M.delete();src.delete();dest.delete();img.delete();return{img:imgWarp,width:imgWarp.cols,height:imgWarp.rows}}registry.register("warp",warp);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ppu-ocv",
3
- "version": "0.0.2",
3
+ "version": "1.0.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",
@@ -1,26 +1,26 @@
1
1
  export { executeOperation, OperationRegistry, registry } from "./registry";
2
2
  export type { OperationFunction, OperationName, OperationOptions, OperationResult, PartialOptions, RegisteredOperations, RequiredOptions, } from "./types";
3
- import "@/operations/adaptive-threshold";
4
- import "@/operations/blur";
5
- import "@/operations/border";
6
- import "@/operations/canny";
7
- import "@/operations/dilate";
8
- import "@/operations/erode";
9
- import "@/operations/grayscale";
10
- import "@/operations/invert";
11
- import "@/operations/morphological-gradient";
12
- import "@/operations/resize";
13
- import "@/operations/threshold";
14
- import "@/operations/warp";
15
- export type { AdaptiveThresholdOptions } from "@/operations/adaptive-threshold";
16
- export type { BlurOptions } from "@/operations/blur";
17
- export type { BorderOptions } from "@/operations/border";
18
- export type { CannyOptions } from "@/operations/canny";
19
- export type { DilateOptions } from "@/operations/dilate";
20
- export type { ErodeOptions } from "@/operations/erode";
21
- export type { GrayscaleOptions } from "@/operations/grayscale";
22
- export type { InvertOptions } from "@/operations/invert";
23
- export type { MorphologicalGradientOptions } from "@/operations/morphological-gradient";
24
- export type { ResizeOptions } from "@/operations/resize";
25
- export type { ThresholdOptions } from "@/operations/threshold";
26
- export type { WarpOptions } from "@/operations/warp";
3
+ import "../operations/adaptive-threshold";
4
+ import "../operations/blur";
5
+ import "../operations/border";
6
+ import "../operations/canny";
7
+ import "../operations/dilate";
8
+ import "../operations/erode";
9
+ import "../operations/grayscale";
10
+ import "../operations/invert";
11
+ import "../operations/morphological-gradient";
12
+ import "../operations/resize";
13
+ import "../operations/threshold";
14
+ import "../operations/warp";
15
+ export type { AdaptiveThresholdOptions } from "../operations/adaptive-threshold";
16
+ export type { BlurOptions } from "../operations/blur";
17
+ export type { BorderOptions } from "../operations/border";
18
+ export type { CannyOptions } from "../operations/canny";
19
+ export type { DilateOptions } from "../operations/dilate";
20
+ export type { ErodeOptions } from "../operations/erode";
21
+ export type { GrayscaleOptions } from "../operations/grayscale";
22
+ export type { InvertOptions } from "../operations/invert";
23
+ export type { MorphologicalGradientOptions } from "../operations/morphological-gradient";
24
+ export type { ResizeOptions } from "../operations/resize";
25
+ export type { ThresholdOptions } from "../operations/threshold";
26
+ export type { WarpOptions } from "../operations/warp";
package/pipeline/index.js CHANGED
@@ -1 +1 @@
1
- export{executeOperation,OperationRegistry,registry}from"./registry";import"@/operations/adaptive-threshold";import"@/operations/blur";import"@/operations/border";import"@/operations/canny";import"@/operations/dilate";import"@/operations/erode";import"@/operations/grayscale";import"@/operations/invert";import"@/operations/morphological-gradient";import"@/operations/resize";import"@/operations/threshold";import"@/operations/warp";
1
+ export{executeOperation,OperationRegistry,registry}from"./registry";import"../operations/adaptive-threshold";import"../operations/blur";import"../operations/border";import"../operations/canny";import"../operations/dilate";import"../operations/erode";import"../operations/grayscale";import"../operations/invert";import"../operations/morphological-gradient";import"../operations/resize";import"../operations/threshold";import"../operations/warp";
@@ -1,5 +1,5 @@
1
- import type { OperationFunction, OperationName, OperationOptions, OperationResult } from "@/index";
2
- import cv from "@techstark/opencv-js";
1
+ import { cv } from "../index";
2
+ import type { OperationFunction, OperationName, OperationOptions, OperationResult } from "./index";
3
3
  export declare class OperationRegistry {
4
4
  private operations;
5
5
  private defaultOptions;