ppu-ocv 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/contours.d.ts CHANGED
@@ -63,6 +63,21 @@ export declare class Contours {
63
63
  points: Points;
64
64
  bbox: BoundingBox;
65
65
  };
66
+ /**
67
+ * Approximates a rectangular contour from a given contour using the Douglas-Peucker algorithm.
68
+ *
69
+ * This method simplifies the contour by reducing the number of points,
70
+ * which is useful for detecting rectangle-like shapes.
71
+ *
72
+ * @param options.threshold - Approximation accuracy as a factor of arc length.
73
+ * A lower value results in a more accurate approximation with more points. (default: 0.02)
74
+ * @param options.contour - Optional input contour. If not provided, the largest contour area will be used.
75
+ * @returns The approximated contour as a `cv.Mat`. Returns an empty `cv.Mat` if no contour is available.
76
+ */
77
+ getApproximateRectangleContour(options?: {
78
+ threshold?: number;
79
+ contour?: cv.Mat;
80
+ }): cv.Mat | undefined;
66
81
  /**
67
82
  * Delete the contours object.
68
83
  */
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}}getApproximateRectangleContour(options){const{threshold=0.02,contour=this.getLargestContourArea()}=options??{};if(!contour)return;let epsilon=threshold*cv.arcLength(contour,true);let approxContour=new cv.Mat;cv.approxPolyDP(contour,approxContour,epsilon,true);contour.delete();return approxContour}destroy(){try{this.contours.delete()}catch(error){}}}import{cv}from"./index";function defaultOptions(){return{mode:cv.RETR_EXTERNAL,method:cv.CHAIN_APPROX_SIMPLE}}
@@ -21,15 +21,15 @@ export interface CalculateMeanLightnessOptions {
21
21
  * Lightness is normalized based on the image's own maximum lightness value before averaging.
22
22
  *
23
23
  * @param options - Configuration options.
24
- * @returns A promise resolving to the mean normalized lightness (0-1).
24
+ * @returns Mean normalized lightness (0-1).
25
25
  * @throws Error if OpenCV operations fail.
26
26
  */
27
- export declare function calculateMeanNormalizedLabLightness(options: CalculateMeanLightnessOptions): Promise<number>;
27
+ export declare function calculateMeanNormalizedLabLightness(options: CalculateMeanLightnessOptions): number;
28
28
  /**
29
29
  * Calculates the mean pixel value of the image after converting it to grayscale.
30
30
  *
31
31
  * @param canvas - The source canvas to be processed.
32
- * @returns A promise resolving to the mean grayscale value (typically 0-255).
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): Promise<number>;
35
+ export declare function calculateMeanGrayscaleValue(canvas: Canvas): number;
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 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()}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ppu-ocv",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
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",