seg-cam 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/jersey-detector-worker.js +114 -114
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,6 +88,8 @@ export function CameraApp() {
|
|
|
88
88
|
| `onSegmentedImage`| `(images: ImageBitmap[], bboxes?: BoundingBox[]) => void`| - | Throttled (500ms). Returns individual bitmaps and bounding boxes of detected objects (tlbr format). |
|
|
89
89
|
| `bodyPixArchitecture`| `'MobileNetV1' \| 'ResNet50'` | `'MobileNetV1'` | Performance vs Accuracy trade-off. |
|
|
90
90
|
| `verbose` | `boolean` | `false` | Enable detailed console logging. |
|
|
91
|
+
| `className` | `string` | - | Optional CSS class for the canvas element. |
|
|
92
|
+
| `style` | `React.CSSProperties` | - | Optional inline styles for the canvas. Use `transform: 'scaleX(-1)'` for selfie-mode mirroring. |
|
|
91
93
|
|
|
92
94
|
### `DetectionStats` Type
|
|
93
95
|
|
|
@@ -100,6 +102,20 @@ interface DetectionStats {
|
|
|
100
102
|
}
|
|
101
103
|
```
|
|
102
104
|
|
|
105
|
+
### `BoundingBox` Type
|
|
106
|
+
|
|
107
|
+
The `BoundingBox` provides the location of a detected object in **pixel coordinates** relative to the original unmirrored video frame.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
interface BoundingBox {
|
|
111
|
+
top: number; // Y-coordinate of the top edge
|
|
112
|
+
left: number; // X-coordinate of the left edge
|
|
113
|
+
bottom: number; // Y-coordinate of the bottom edge
|
|
114
|
+
right: number; // X-coordinate of the right edge
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
Note: The format is `[top, left, bottom, right]`. Dimensions can be calculated as `height = bottom - top` and `width = right - left`.
|
|
118
|
+
|
|
103
119
|
### `JerseyDetectorHandle` (Inverted Ref)
|
|
104
120
|
|
|
105
121
|
You can use a `ref` on the `JerseyDetector` component to access its internal state imperatively:
|
|
@@ -135,6 +151,12 @@ const currentStats = detectorRef.current?.stats;
|
|
|
135
151
|
- `'mask_with_image'`: Draws the overlay on top of the existing canvas (may trail if not cleared externally).
|
|
136
152
|
- `'none'`: Skips bitmap generation entirely. Use this if you only need `onSegmentedImage` or stats, improving performance.
|
|
137
153
|
- **`threshold`**: (`number`, 0.0-1.0, Default `0.5`) The minimum confidence required for a person pixel to be considered valid.
|
|
154
|
+
- **Mirroring**: Passing `style={{ transform: 'scaleX(-1)' }}` will:
|
|
155
|
+
- Mirror the UI display of the mask/composite using CSS.
|
|
156
|
+
- Automatically tell the worker to mirror the pixels in the internal mask bitmap (for UI display).
|
|
157
|
+
- **Does NOT mirror** the individual `onSegmentedImage` snapshots (kept unmirrored for classification).
|
|
158
|
+
- Keep `capture()` oriented correctly (unmirrored) by automatically un-flipping the mask before export.
|
|
159
|
+
- Keep `bboxes` in original, unmirrored coordinates.
|
|
138
160
|
|
|
139
161
|
## Performance Tips
|
|
140
162
|
|
package/dist/index.d.mts
CHANGED
|
@@ -66,6 +66,7 @@ type WorkerConfig = {
|
|
|
66
66
|
targetPartId?: number;
|
|
67
67
|
imagesToReturn?: ImagesToReturn;
|
|
68
68
|
minDetectionArea?: number;
|
|
69
|
+
mirror?: boolean;
|
|
69
70
|
};
|
|
70
71
|
type BoundingBox = {
|
|
71
72
|
top: number;
|
|
@@ -147,6 +148,8 @@ interface JerseyDetectorProps {
|
|
|
147
148
|
imagesToReturn?: ImagesToReturn;
|
|
148
149
|
minDetectionArea?: number;
|
|
149
150
|
workerUrl?: string;
|
|
151
|
+
className?: string;
|
|
152
|
+
style?: React.CSSProperties;
|
|
150
153
|
}
|
|
151
154
|
declare const JerseyDetector: react.ForwardRefExoticComponent<JerseyDetectorProps & react.RefAttributes<JerseyDetectorHandle>>;
|
|
152
155
|
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ type WorkerConfig = {
|
|
|
66
66
|
targetPartId?: number;
|
|
67
67
|
imagesToReturn?: ImagesToReturn;
|
|
68
68
|
minDetectionArea?: number;
|
|
69
|
+
mirror?: boolean;
|
|
69
70
|
};
|
|
70
71
|
type BoundingBox = {
|
|
71
72
|
top: number;
|
|
@@ -147,6 +148,8 @@ interface JerseyDetectorProps {
|
|
|
147
148
|
imagesToReturn?: ImagesToReturn;
|
|
148
149
|
minDetectionArea?: number;
|
|
149
150
|
workerUrl?: string;
|
|
151
|
+
className?: string;
|
|
152
|
+
style?: React.CSSProperties;
|
|
150
153
|
}
|
|
151
154
|
declare const JerseyDetector: react.ForwardRefExoticComponent<JerseyDetectorProps & react.RefAttributes<JerseyDetectorHandle>>;
|
|
152
155
|
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var Me=Object.create;var V=Object.defineProperty;var Ce=Object.getOwnPropertyDescriptor;var We=Object.getOwnPropertyNames,ge=Object.getOwnPropertySymbols,Se=Object.getPrototypeOf,he=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable;var pe=(e,r,t)=>r in e?V(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,ye=(e,r)=>{for(var t in r||(r={}))he.call(r,t)&&pe(e,t,r[t]);if(ge)for(var t of ge(r))xe.call(r,t)&&pe(e,t,r[t]);return e};var Oe=(e,r)=>{for(var t in r)V(e,t,{get:r[t],enumerable:!0})},Te=(e,r,t,E)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of We(r))!he.call(e,i)&&i!==t&&V(e,i,{get:()=>r[i],enumerable:!(E=Ce(r,i))||E.enumerable});return e};var Be=(e,r,t)=>(t=e!=null?Me(Se(e)):{},Te(r||!e||!e.__esModule?V(t,"default",{value:e,enumerable:!0}):t,e)),Ne=e=>Te(V({},"__esModule",{value:!0}),e);var x=(e,r,t)=>new Promise((E,i)=>{var O=f=>{try{w(t.next(f))}catch(R){i(R)}},b=f=>{try{w(t.throw(f))}catch(R){i(R)}},w=f=>f.done?E(f.value):Promise.resolve(f.value).then(O,b);w((t=t.apply(e,r)).next())});var Je={};Oe(Je,{DEFAULT_CONFIG:()=>d,JerseyDetector:()=>ie,useJerseyWorker:()=>ee});module.exports=Ne(Je);var s=require("react");var h=require("react");var p=null,W=!1,j=null,oe=0,se=null,k=new Map,Ae=0,Z=new Map;function ee(e,r){let t=(0,h.useRef)(!1),[E,i]=(0,h.useState)(!1),[O,b]=(0,h.useState)(null),w=(0,h.useRef)(!0),f=(0,h.useRef)(!1),R=(0,h.useRef)(`instance_${Math.random().toString(36).substr(2,9)}`),B=(0,h.useRef)(0);(0,h.useEffect)(()=>{var M;if(!e)return;w.current=!0,B.current++;let _=B.current,S=R.current,N=(M=Z.get(S))!=null?M:0;return _>N&&(oe++,Z.set(S,_)),x(null,null,function*(){var y;if(!p||!He(se,e)){p&&(p.terminate(),p=null,W=!1,console.log("[v0 useJerseyWorker] Worker terminated because of change in config"));try{f.current=(y=e.verbose)!=null?y:f.current;let m=r||"/jersey-detector-worker.js";p=new Worker(m),se=e,W=!1,j=null,i(!1),b(null),p.onmessage=g=>{let c=g.data;switch(c.type){case"ready":W=!0,i(!0),f.current&&console.log("[v0 useJerseyWorker] Worker Ready",{device:c.device,dtype:c.dtype,config:c.config});break;case"loading_progress":f.current&&console.log(`[v0 useJerseyWorker] Loaded ${c.progress}% of ${c.file}`);break;case"debug":f.current&&console.log(c.debug_message);break;case"error":let P=c.error_message||"Unknown worker error";console.error("[v0 useJerseyWorker] Worker sent error message:",P),W=!1,j=P,i(!1),b(P);break;case"detect_response":if(c.requestId&&k.has(c.requestId)){let l=k.get(c.requestId);l&&(l.resolve(c),k.delete(c.requestId))}else if(k.size>0){let l=k.entries().next();if(!l.done){let[re,A]=l.value;A.resolve(c),k.delete(re)}}break}},p.onerror=g=>{let c=g.message||"Worker initialization error";console.error("[useJerseyWorker] Worker error:",c),W=!1,j=c,i(!1),b(c)},p.postMessage({type:"init",config:e})}catch(m){let g=(m==null?void 0:m.message)||String(m);console.error("[useJerseyWorker] Failed to create worker:",g),i(!1),b(g)}}else i(W),b(j)}),()=>{w.current=!1;let y=R.current,m=Z.get(y),g=B.current;m===g&&(oe--,Z.delete(y),oe<=0&&p&&(p.terminate(),p=null,W=!1,j=null,se=null,k.clear()))}},[]);let Y=(0,h.useCallback)((_,S,N=.5)=>x(null,null,function*(){if(!p||!W)throw new Error("Worker not ready");if(t.current)return null;let v=`req_${++Ae}_${Date.now()}`;return new Promise((M,y)=>{k.set(v,{resolve:M,reject:y});try{t.current=!0,p.postMessage({type:"detect",requestId:v,dimensions:S,bitmap:_,threshold:N},[_])}catch(m){k.delete(v);let g=`Failed to send detect: ${m==null?void 0:m.message}`;y(new Error(g))}finally{t.current=!1}setTimeout(()=>{k.has(v)&&(k.delete(v),y(new Error("Detection timeout")))},1e4)})}),[E]);return{isReady:E,workerReady:E,lastError:O,detect:Y}}function He(e,r){return e?JSON.stringify(e)===JSON.stringify(r):!1}var d={TASK:"image-segmentation",MODEL:"BodyPix",BODYPIX_ARCHITECTURE:"MobileNetV1",BODYPIX_MULTIPLIER:.75,BODYPIX_QUANT_BYTES:2,BODYPIX_STRIDE:16,MULTI_SEGMENTATION:!0,SEGMENT_BODY_PARTS:!0,BACKGROUND_SHADE:0,SHIRT_SHADE:170,DETECTION_THRESHOLD:.5,TARGET_PART_ID:12,IMAGES_TO_RETURN:"mask",VERBOSE:!1,MIN_DETECTION_AREA:1e4};var Ee=Be(require("p-limit"));var De=require("react/jsx-runtime"),ie=(0,s.forwardRef)(({videoRef:e,onWorkerReady:r,onWorkerError:t,onStatsUpdate:E,onSegmentedImage:i,task:O=d.TASK,model:b=d.MODEL,verbose:w=d.VERBOSE,bodyPixArchitecture:f=d.BODYPIX_ARCHITECTURE,bodyPixMultiplier:R=d.BODYPIX_MULTIPLIER,bodyPixQuantBytes:B=d.BODYPIX_QUANT_BYTES,bodyPixStride:Y=d.BODYPIX_STRIDE,multiSegmentation:_=d.MULTI_SEGMENTATION,segmentBodyParts:S=d.SEGMENT_BODY_PARTS,backgroundShade:N=d.BACKGROUND_SHADE,shirtShade:v=d.SHIRT_SHADE,threshold:M=d.DETECTION_THRESHOLD,targetPartId:y=d.TARGET_PART_ID,imagesToReturn:m=d.IMAGES_TO_RETURN,minDetectionArea:g=d.MIN_DETECTION_AREA,workerUrl:c,className:P,style:l},re)=>{let A=(0,s.useRef)(null),L=(0,s.useRef)(null),te=(0,s.useRef)(!1),q=(0,s.useRef)([]),Ie=(0,s.useRef)(null),U=(0,s.useRef)(!1),X=(0,s.useRef)(void 0);X.current=t;let ne=(0,s.useRef)({jerseyCount:0,confidence:0,fps:0,processingTime:0}),ae=(0,s.useRef)(0),ke=500,ce=5,ue=(0,s.useMemo)(()=>(0,Ee.default)(ce),[]),$=(0,s.useMemo)(()=>({task:O,model:b,verbose:w,bodyPixArchitecture:f,bodyPixMultiplier:R,bodyPixQuantBytes:B,bodyPixStride:Y,multiSegmentation:_,segmentBodyParts:S,backgroundShade:N,shirtShade:v,threshold:M,targetPartId:y,imagesToReturn:m,minDetectionArea:g,mirror:(l==null?void 0:l.transform)==="scaleX(-1)"||typeof(l==null?void 0:l.transform)=="string"&&l.transform.includes("scaleX(-1)")}),[O,b,w,f,R,B,Y,_,S,N,v,M,y,m,g,l==null?void 0:l.transform]),be=()=>{var n,a;return{width:((n=e.current)==null?void 0:n.videoWidth)||0,height:((a=e.current)==null?void 0:a.videoHeight)||0}},{isReady:H,workerReady:C,lastError:G,detect:we}=ee($,c);(0,s.useEffect)(()=>{C&&console.log("[JerseyDetector] Worker Ready with config:",$),r==null||r(C)},[C,r,$]),(0,s.useEffect)(()=>{var n;G&&(U.current=!0,(n=X.current)==null||n.call(X,G))},[G]);let Re=(0,s.useCallback)((n,a)=>{if(ue.activeCount>=ce){n.forEach(o=>{var u;return(u=o==null?void 0:o.close)==null?void 0:u.call(o)}),console.warn("[JerseyDetector] Dropped new segmented images \u2014 max 5 classifications running");return}ue(()=>x(null,null,function*(){try{i==null||i(n,a)}catch(o){console.error("[JerseyDetector] Classification error:",o)}finally{n.forEach(o=>{var u;return(u=o==null?void 0:o.close)==null?void 0:u.call(o)})}}))},[i]),ve=()=>x(null,null,function*(){var D,z,le;let n=e.current,a=A.current;if(U.current||!H||!C||!n||!a||te.current||n.readyState<2||n.paused||n.ended||n.videoWidth===0||n.videoHeight===0)return;let o=a.getContext("2d");if(!o||a.width<=0||a.height<=0)return;let u=null,T=null;try{te.current=!0;let F=n.videoWidth,K=n.videoHeight;Ie.current={width:F,height:K},u=yield createImageBitmap(n);let _e=be(),I=yield we(u,_e,M);if((I==null?void 0:I.type)==="detect_response"){if(m!=="none"&&((a.width!==F||a.height!==K)&&(a.width=F,a.height=K),o.clearRect(0,0,F,K),I.bitmap)){let J=I.bitmap;o.drawImage(J,0,0),console.log(`[JerseyDetector] Bitmap created with dims ${J.width}x${J.height}`),J.close()}q.current.push(Date.now()),q.current=q.current.filter(J=>Date.now()-J<1e3);let Q={jerseyCount:((D=I.stats)==null?void 0:D.jerseyCount)||0,confidence:((z=I.stats)==null?void 0:z.confidence)||0,fps:q.current.length,processingTime:((le=I.stats)==null?void 0:le.processingTime)||0},de=ne.current;ne.current=Q;let fe=Date.now(),me=fe-ae.current>ke||Q.jerseyCount!==de.jerseyCount||Q.confidence!==de.confidence;me&&E&&(E(Q),ae.current=fe),me&&I.segmentedImages&&i&&Re(I.segmentedImages,I.bboxes)}}catch(F){U.current=!0}finally{u==null||u.close(),te.current=!1}});return(0,s.useImperativeHandle)(re,()=>({get isReady(){return H},get lastError(){return G},get stats(){return ne.current},capture:(n="image/jpeg",a=.92)=>{let o=e.current,u=A.current;if(!o||o.videoWidth<=0||o.videoHeight<=0)throw new Error("Video not ready for capture");let T=document.createElement("canvas");T.width=o.videoWidth,T.height=o.videoHeight;let D=T.getContext("2d");if(!D)throw new Error("Failed to get context for capture canvas");let z=$.mirror;return D.drawImage(o,0,0,T.width,T.height),u&&u.width>0&&u.height>0?z?(D.save(),D.translate(T.width,0),D.scale(-1,1),D.drawImage(u,0,0,T.width,T.height),D.restore()):D.drawImage(u,0,0,T.width,T.height):console.warn("[capture] Mask canvas not available \u2014 returning raw video frame"),T.toDataURL(n,a)}}),[H,G,C]),(0,s.useEffect)(()=>{if(!C||!H||U.current)return;let n=e.current,a=A.current;if(!n||!a||n.videoWidth===0||n.videoHeight===0){let u=setTimeout(()=>{L.current=requestAnimationFrame(()=>{})},100);return()=>clearTimeout(u)}(a.width!==n.videoWidth||a.height!==n.videoHeight)&&(a.width=n.videoWidth,a.height=n.videoHeight);let o=()=>x(null,null,function*(){!C||!H||U.current||(yield ve(),L.current=requestAnimationFrame(o))});return L.current=requestAnimationFrame(o),()=>{L.current&&cancelAnimationFrame(L.current)}},[C,H]),(0,De.jsx)("canvas",{ref:A,className:`absolute inset-0 pointer-events-none ${P||""}`,style:ye({zIndex:10,width:"100%",height:"100%"},l)})});ie.displayName="JerseyDetector";0&&(module.exports={DEFAULT_CONFIG,JerseyDetector,useJerseyWorker});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var ve=Object.defineProperty;var me=Object.getOwnPropertySymbols;var _e=Object.prototype.hasOwnProperty,Me=Object.prototype.propertyIsEnumerable;var ge=(t,n,o)=>n in t?ve(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,pe=(t,n)=>{for(var o in n||(n={}))_e.call(n,o)&&ge(t,o,n[o]);if(me)for(var o of me(n))Me.call(n,o)&&ge(t,o,n[o]);return t};var S=(t,n,o)=>new Promise((R,f)=>{var x=u=>{try{I(o.next(u))}catch(k){f(k)}},D=u=>{try{I(o.throw(u))}catch(k){f(k)}},I=u=>u.done?R(u.value):Promise.resolve(u.value).then(x,D);I((o=o.apply(t,n)).next())});import{forwardRef as Oe,useImperativeHandle as Be,useRef as w,useEffect as se,useMemo as ye,useCallback as Ne}from"react";import{useEffect as Ce,useState as he,useCallback as We,useRef as F}from"react";var g=null,C=!1,V=null,te=0,ne=null,E=new Map,Se=0,Q=new Map;function oe(t,n){let o=F(!1),[R,f]=he(!1),[x,D]=he(null),I=F(!0),u=F(!1),k=F(`instance_${Math.random().toString(36).substr(2,9)}`),O=F(0);Ce(()=>{var _;if(!t)return;I.current=!0,O.current++;let v=O.current,W=k.current,B=(_=Q.get(W))!=null?_:0;return v>B&&(te++,Q.set(W,v)),S(null,null,function*(){var p;if(!g||!xe(ne,t)){g&&(g.terminate(),g=null,C=!1,console.log("[v0 useJerseyWorker] Worker terminated because of change in config"));try{u.current=(p=t.verbose)!=null?p:u.current;let l=n||"/jersey-detector-worker.js";g=new Worker(l),ne=t,C=!1,V=null,f(!1),D(null),g.onmessage=m=>{let i=m.data;switch(i.type){case"ready":C=!0,f(!0),u.current&&console.log("[v0 useJerseyWorker] Worker Ready",{device:i.device,dtype:i.dtype,config:i.config});break;case"loading_progress":u.current&&console.log(`[v0 useJerseyWorker] Loaded ${i.progress}% of ${i.file}`);break;case"debug":u.current&&console.log(i.debug_message);break;case"error":let J=i.error_message||"Unknown worker error";console.error("[v0 useJerseyWorker] Worker sent error message:",J),C=!1,V=J,f(!1),D(J);break;case"detect_response":if(i.requestId&&E.has(i.requestId)){let c=E.get(i.requestId);c&&(c.resolve(i),E.delete(i.requestId))}else if(E.size>0){let c=E.entries().next();if(!c.done){let[Z,N]=c.value;N.resolve(i),E.delete(Z)}}break}},g.onerror=m=>{let i=m.message||"Worker initialization error";console.error("[useJerseyWorker] Worker error:",i),C=!1,V=i,f(!1),D(i)},g.postMessage({type:"init",config:t})}catch(l){let m=(l==null?void 0:l.message)||String(l);console.error("[useJerseyWorker] Failed to create worker:",m),f(!1),D(m)}}else f(C),D(V)}),()=>{I.current=!1;let p=k.current,l=Q.get(p),m=O.current;l===m&&(te--,Q.delete(p),te<=0&&g&&(g.terminate(),g=null,C=!1,V=null,ne=null,E.clear()))}},[]);let j=We((v,W,B=.5)=>S(null,null,function*(){if(!g||!C)throw new Error("Worker not ready");if(o.current)return null;let b=`req_${++Se}_${Date.now()}`;return new Promise((_,p)=>{E.set(b,{resolve:_,reject:p});try{o.current=!0,g.postMessage({type:"detect",requestId:b,dimensions:W,bitmap:v,threshold:B},[v])}catch(l){E.delete(b);let m=`Failed to send detect: ${l==null?void 0:l.message}`;p(new Error(m))}finally{o.current=!1}setTimeout(()=>{E.has(b)&&(E.delete(b),p(new Error("Detection timeout")))},1e4)})}),[R]);return{isReady:R,workerReady:R,lastError:x,detect:j}}function xe(t,n){return t?JSON.stringify(t)===JSON.stringify(n):!1}var d={TASK:"image-segmentation",MODEL:"BodyPix",BODYPIX_ARCHITECTURE:"MobileNetV1",BODYPIX_MULTIPLIER:.75,BODYPIX_QUANT_BYTES:2,BODYPIX_STRIDE:16,MULTI_SEGMENTATION:!0,SEGMENT_BODY_PARTS:!0,BACKGROUND_SHADE:0,SHIRT_SHADE:170,DETECTION_THRESHOLD:.5,TARGET_PART_ID:12,IMAGES_TO_RETURN:"mask",VERBOSE:!1,MIN_DETECTION_AREA:1e4};import Ae from"p-limit";import{jsx as He}from"react/jsx-runtime";var Te=Oe(({videoRef:t,onWorkerReady:n,onWorkerError:o,onStatsUpdate:R,onSegmentedImage:f,task:x=d.TASK,model:D=d.MODEL,verbose:I=d.VERBOSE,bodyPixArchitecture:u=d.BODYPIX_ARCHITECTURE,bodyPixMultiplier:k=d.BODYPIX_MULTIPLIER,bodyPixQuantBytes:O=d.BODYPIX_QUANT_BYTES,bodyPixStride:j=d.BODYPIX_STRIDE,multiSegmentation:v=d.MULTI_SEGMENTATION,segmentBodyParts:W=d.SEGMENT_BODY_PARTS,backgroundShade:B=d.BACKGROUND_SHADE,shirtShade:b=d.SHIRT_SHADE,threshold:_=d.DETECTION_THRESHOLD,targetPartId:p=d.TARGET_PART_ID,imagesToReturn:l=d.IMAGES_TO_RETURN,minDetectionArea:m=d.MIN_DETECTION_AREA,workerUrl:i,className:J,style:c},Z)=>{let N=w(null),P=w(null),ee=w(!1),Y=w([]),Ee=w(null),L=w(!1),q=w(void 0);q.current=o;let re=w({jerseyCount:0,confidence:0,fps:0,processingTime:0}),ie=w(0),De=500,ae=5,ce=ye(()=>Ae(ae),[]),X=ye(()=>({task:x,model:D,verbose:I,bodyPixArchitecture:u,bodyPixMultiplier:k,bodyPixQuantBytes:O,bodyPixStride:j,multiSegmentation:v,segmentBodyParts:W,backgroundShade:B,shirtShade:b,threshold:_,targetPartId:p,imagesToReturn:l,minDetectionArea:m,mirror:(c==null?void 0:c.transform)==="scaleX(-1)"||typeof(c==null?void 0:c.transform)=="string"&&c.transform.includes("scaleX(-1)")}),[x,D,I,u,k,O,j,v,W,B,b,_,p,l,m,c==null?void 0:c.transform]),Ie=()=>{var e,s;return{width:((e=t.current)==null?void 0:e.videoWidth)||0,height:((s=t.current)==null?void 0:s.videoHeight)||0}},{isReady:A,workerReady:M,lastError:U,detect:ke}=oe(X,i);se(()=>{M&&console.log("[JerseyDetector] Worker Ready with config:",X),n==null||n(M)},[M,n,X]),se(()=>{var e;U&&(L.current=!0,(e=q.current)==null||e.call(q,U))},[U]);let be=Ne((e,s)=>{if(ce.activeCount>=ae){e.forEach(r=>{var a;return(a=r==null?void 0:r.close)==null?void 0:a.call(r)}),console.warn("[JerseyDetector] Dropped new segmented images \u2014 max 5 classifications running");return}ce(()=>S(null,null,function*(){try{f==null||f(e,s)}catch(r){console.error("[JerseyDetector] Classification error:",r)}finally{e.forEach(r=>{var a;return(a=r==null?void 0:r.close)==null?void 0:a.call(r)})}}))},[f]),we=()=>S(null,null,function*(){var y,$,ue;let e=t.current,s=N.current;if(L.current||!A||!M||!e||!s||ee.current||e.readyState<2||e.paused||e.ended||e.videoWidth===0||e.videoHeight===0)return;let r=s.getContext("2d");if(!r||s.width<=0||s.height<=0)return;let a=null,h=null;try{ee.current=!0;let G=e.videoWidth,z=e.videoHeight;Ee.current={width:G,height:z},a=yield createImageBitmap(e);let Re=Ie(),T=yield ke(a,Re,_);if((T==null?void 0:T.type)==="detect_response"){if(l!=="none"&&((s.width!==G||s.height!==z)&&(s.width=G,s.height=z),r.clearRect(0,0,G,z),T.bitmap)){let H=T.bitmap;r.drawImage(H,0,0),console.log(`[JerseyDetector] Bitmap created with dims ${H.width}x${H.height}`),H.close()}Y.current.push(Date.now()),Y.current=Y.current.filter(H=>Date.now()-H<1e3);let K={jerseyCount:((y=T.stats)==null?void 0:y.jerseyCount)||0,confidence:(($=T.stats)==null?void 0:$.confidence)||0,fps:Y.current.length,processingTime:((ue=T.stats)==null?void 0:ue.processingTime)||0},le=re.current;re.current=K;let de=Date.now(),fe=de-ie.current>De||K.jerseyCount!==le.jerseyCount||K.confidence!==le.confidence;fe&&R&&(R(K),ie.current=de),fe&&T.segmentedImages&&f&&be(T.segmentedImages,T.bboxes)}}catch(G){L.current=!0}finally{a==null||a.close(),ee.current=!1}});return Be(Z,()=>({get isReady(){return A},get lastError(){return U},get stats(){return re.current},capture:(e="image/jpeg",s=.92)=>{let r=t.current,a=N.current;if(!r||r.videoWidth<=0||r.videoHeight<=0)throw new Error("Video not ready for capture");let h=document.createElement("canvas");h.width=r.videoWidth,h.height=r.videoHeight;let y=h.getContext("2d");if(!y)throw new Error("Failed to get context for capture canvas");let $=X.mirror;return y.drawImage(r,0,0,h.width,h.height),a&&a.width>0&&a.height>0?$?(y.save(),y.translate(h.width,0),y.scale(-1,1),y.drawImage(a,0,0,h.width,h.height),y.restore()):y.drawImage(a,0,0,h.width,h.height):console.warn("[capture] Mask canvas not available \u2014 returning raw video frame"),h.toDataURL(e,s)}}),[A,U,M]),se(()=>{if(!M||!A||L.current)return;let e=t.current,s=N.current;if(!e||!s||e.videoWidth===0||e.videoHeight===0){let a=setTimeout(()=>{P.current=requestAnimationFrame(()=>{})},100);return()=>clearTimeout(a)}(s.width!==e.videoWidth||s.height!==e.videoHeight)&&(s.width=e.videoWidth,s.height=e.videoHeight);let r=()=>S(null,null,function*(){!M||!A||L.current||(yield we(),P.current=requestAnimationFrame(r))});return P.current=requestAnimationFrame(r),()=>{P.current&&cancelAnimationFrame(P.current)}},[M,A]),He("canvas",{ref:N,className:`absolute inset-0 pointer-events-none ${J||""}`,style:pe({zIndex:10,width:"100%",height:"100%"},c)})});Te.displayName="JerseyDetector";export{d as DEFAULT_CONFIG,Te as JerseyDetector,oe as useJerseyWorker};
|