@niivue/nv-ext-image-processing 1.0.0-rc.3 → 1.0.0-rc.4
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/package.json +6 -3
- package/dist/index.d.ts +0 -8
- package/dist/nv-ext-image-processing.js +0 -154
- package/dist/processing/conform.d.ts +0 -40
- package/dist/processing/connectedLabel.d.ts +0 -20
- package/dist/processing/otsu.d.ts +0 -22
- package/dist/transforms.d.ts +0 -6
- package/dist/worker.d.ts +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@niivue/nv-ext-image-processing",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Image processing extensions for NiiVue (Otsu thresholding, haze removal, etc.)",
|
|
6
6
|
"main": "./dist/nv-ext-image-processing.js",
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"@niivue/niivue": "
|
|
19
|
+
"@niivue/niivue": "1.0.0-rc.4"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@niivue/niivue": "
|
|
22
|
+
"@niivue/niivue": "1.0.0-rc.4",
|
|
23
23
|
"typescript": "~5.8.3",
|
|
24
24
|
"vite": "^6.3.2",
|
|
25
25
|
"vite-plugin-dts": "^4.5.4"
|
|
@@ -31,5 +31,8 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"gl-matrix": "^3.4.4",
|
|
33
33
|
"nifti-reader-js": "^0.8.0"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
34
37
|
}
|
|
35
38
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @niivue/nv-ext-image-processing
|
|
3
|
-
*
|
|
4
|
-
* Image processing extensions for NiiVue.
|
|
5
|
-
* Each export is a VolumeTransform that can be registered with
|
|
6
|
-
* `ctx.registerVolumeTransform()` via the NiiVue extension context.
|
|
7
|
-
*/
|
|
8
|
-
export { conform, connectedLabel, otsu, removeHaze } from './transforms';
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { NVWorker as u } from "@niivue/niivue";
|
|
2
|
-
const f = '(function(){"use strict";var T=typeof Float32Array<"u"?Float32Array:Array;function B(){var n=new T(16);return T!=Float32Array&&(n[1]=0,n[2]=0,n[3]=0,n[4]=0,n[6]=0,n[7]=0,n[8]=0,n[9]=0,n[11]=0,n[12]=0,n[13]=0,n[14]=0),n[0]=1,n[5]=1,n[10]=1,n[15]=1,n}function q(n,e,t,a,i,r,y,l,s,c,v,u,w,b,h,A){var x=new T(16);return x[0]=n,x[1]=e,x[2]=t,x[3]=a,x[4]=i,x[5]=r,x[6]=y,x[7]=l,x[8]=s,x[9]=c,x[10]=v,x[11]=u,x[12]=w,x[13]=b,x[14]=h,x[15]=A,x}function J(n,e){if(n===e){var t=e[1],a=e[2],i=e[3],r=e[6],y=e[7],l=e[11];n[1]=e[4],n[2]=e[8],n[3]=e[12],n[4]=t,n[6]=e[9],n[7]=e[13],n[8]=a,n[9]=r,n[11]=e[14],n[12]=i,n[13]=y,n[14]=l}else n[0]=e[0],n[1]=e[4],n[2]=e[8],n[3]=e[12],n[4]=e[1],n[5]=e[5],n[6]=e[9],n[7]=e[13],n[8]=e[2],n[9]=e[6],n[10]=e[10],n[11]=e[14],n[12]=e[3],n[13]=e[7],n[14]=e[11],n[15]=e[15];return n}function sn(n,e){var t=e[0],a=e[1],i=e[2],r=e[3],y=e[4],l=e[5],s=e[6],c=e[7],v=e[8],u=e[9],w=e[10],b=e[11],h=e[12],A=e[13],x=e[14],p=e[15],I=t*l-a*y,o=t*s-i*y,f=t*c-r*y,M=a*s-i*l,d=a*c-r*l,P=i*c-r*s,S=v*A-u*h,U=v*x-w*h,F=v*p-b*h,Y=u*x-w*A,g=u*p-b*A,L=w*p-b*x,z=I*L-o*g+f*Y+M*F-d*U+P*S;return z?(z=1/z,n[0]=(l*L-s*g+c*Y)*z,n[1]=(i*g-a*L-r*Y)*z,n[2]=(A*P-x*d+p*M)*z,n[3]=(w*d-u*P-b*M)*z,n[4]=(s*F-y*L-c*U)*z,n[5]=(t*L-i*F+r*U)*z,n[6]=(x*f-h*P-p*o)*z,n[7]=(v*P-w*f+b*o)*z,n[8]=(y*g-l*F+c*S)*z,n[9]=(a*F-t*g-r*S)*z,n[10]=(h*d-A*f+p*I)*z,n[11]=(u*f-v*d-b*I)*z,n[12]=(l*U-y*Y-s*S)*z,n[13]=(t*Y-a*U+i*S)*z,n[14]=(A*o-h*M-x*I)*z,n[15]=(v*M-u*o+w*I)*z,n):null}function wn(n,e,t){var a=e[0],i=e[1],r=e[2],y=e[3],l=e[4],s=e[5],c=e[6],v=e[7],u=e[8],w=e[9],b=e[10],h=e[11],A=e[12],x=e[13],p=e[14],I=e[15],o=t[0],f=t[1],M=t[2],d=t[3];return n[0]=o*a+f*l+M*u+d*A,n[1]=o*i+f*s+M*w+d*x,n[2]=o*r+f*c+M*b+d*p,n[3]=o*y+f*v+M*h+d*I,o=t[4],f=t[5],M=t[6],d=t[7],n[4]=o*a+f*l+M*u+d*A,n[5]=o*i+f*s+M*w+d*x,n[6]=o*r+f*c+M*b+d*p,n[7]=o*y+f*v+M*h+d*I,o=t[8],f=t[9],M=t[10],d=t[11],n[8]=o*a+f*l+M*u+d*A,n[9]=o*i+f*s+M*w+d*x,n[10]=o*r+f*c+M*b+d*p,n[11]=o*y+f*v+M*h+d*I,o=t[12],f=t[13],M=t[14],d=t[15],n[12]=o*a+f*l+M*u+d*A,n[13]=o*i+f*s+M*w+d*x,n[14]=o*r+f*c+M*b+d*p,n[15]=o*y+f*v+M*h+d*I,n}function Mn(n,e,t){var a=t[0],i=t[1],r=t[2];return n[0]=e[0]*a,n[1]=e[1]*a,n[2]=e[2]*a,n[3]=e[3]*a,n[4]=e[4]*i,n[5]=e[5]*i,n[6]=e[6]*i,n[7]=e[7]*i,n[8]=e[8]*r,n[9]=e[9]*r,n[10]=e[10]*r,n[11]=e[11]*r,n[12]=e[12],n[13]=e[13],n[14]=e[14],n[15]=e[15],n}var hn=wn;function on(){var n=new T(3);return T!=Float32Array&&(n[0]=0,n[1]=0,n[2]=0),n}function K(n,e,t){var a=new T(3);return a[0]=n,a[1]=e,a[2]=t,a}function In(n,e,t){return n[0]=e[0]-t[0],n[1]=e[1]-t[1],n[2]=e[2]-t[2],n}(function(){var n=on();return function(e,t,a,i,r,y){var l,s;for(t||(t=3),a||(a=0),i?s=Math.min(i*t+a,e.length):s=e.length,l=a;l<s;l+=t)n[0]=e[l],n[1]=e[l+1],n[2]=e[l+2],r(n,n,y),e[l]=n[0],e[l+1]=n[1],e[l+2]=n[2];return e}})();function cn(){var n=new T(4);return T!=Float32Array&&(n[0]=0,n[1]=0,n[2]=0,n[3]=0),n}function Q(n,e,t,a){var i=new T(4);return i[0]=n,i[1]=e,i[2]=t,i[3]=a,i}function pn(n,e,t){return n[0]=e[0]*t,n[1]=e[1]*t,n[2]=e[2]*t,n[3]=e[3]*t,n}function fn(n,e,t){var a=e[0],i=e[1],r=e[2],y=e[3];return n[0]=t[0]*a+t[4]*i+t[8]*r+t[12]*y,n[1]=t[1]*a+t[5]*i+t[9]*r+t[13]*y,n[2]=t[2]*a+t[6]*i+t[10]*r+t[14]*y,n[3]=t[3]*a+t[7]*i+t[11]*r+t[15]*y,n}(function(){var n=cn();return function(e,t,a,i,r,y){var l,s;for(t||(t=4),a||(a=0),i?s=Math.min(i*t+a,e.length):s=e.length,l=a;l<s;l+=t)n[0]=e[l],n[1]=e[l+1],n[2]=e[l+2],n[3]=e[l+3],r(n,n,y),e[l]=n[0],e[l+1]=n[1],e[l+2]=n[2],e[l+3]=n[3];return e}})();function dn(n,e,t=256,a=1,i=!1){const r=e,y=q(r[0],r[1],r[2],r[3],r[4],r[5],r[6],r[7],r[8],r[9],r[10],r[11],r[12],r[13],r[14],r[15]),l=Q(n[1]/2,n[2]/2,n[3]/2,1),s=cn(),c=B();J(c,y),fn(s,l,c);const v=K(s[0],s[1],s[2]),u=K(a,a,a);let w=q(-1,0,0,0,0,0,1,0,0,-1,0,0,0,0,0,1);i&&(w=q(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)),J(w,w);const b=Q(t,t,t,1),h=B();Mn(h,w,u);const A=Q(b[0],b[1],b[2],1);fn(A,A,h),pn(A,A,.5);const x=on();In(x,v,K(A[0],A[1],A[2]));const p=B();J(p,h),p[3]=x[0],p[7]=x[1],p[11]=x[2];const I=B();sn(I,p);const o=B();hn(o,y,I);const f=B();return sn(f,o),[p,o,f]}function bn(n,e){if(!(n instanceof ArrayBuffer))return n;switch(e){case 2:return new Uint8Array(n);case 4:return new Int16Array(n);case 8:return new Int32Array(n);case 16:return new Float32Array(n);case 64:return new Float64Array(n);case 256:return new Int8Array(n);case 512:return new Uint16Array(n);case 768:return new Uint32Array(n);default:return new Float32Array(n)}}function Fn(n,e,t,a,i){const r=n.length,y=new Uint8Array(r);for(let l=0;l<r;l++){let s=e+i*(n[l]-a);s=Math.max(s,e),s=Math.min(s,t),y[l]=s}return y}function Un(n,e,t,a,i){const r=n.length,y=new Float32Array(r);for(let l=0;l<r;l++){let s=e+i*(n[l]-a);s=Math.max(s,e),s=Math.min(s,t),y[l]=s}return y}function yn(n,e,t,a,i,r,y,l,s,c,v,u=.999){let w=y,b=l;if(n===2)return[w,1];const h=e.length,A=new Float32Array(h);for(let U=0;U<h;U++)A[U]=e[U]*t+a;if(v===0&&u===1)return[w,1];let x=0;for(let U=0;U<h;U++)Math.abs(A[U])>=1e-15&&x++;const p=1e3,I=(b-w)/p,o=new Array(p).fill(0);for(let U=0;U<h;U++){let F=Math.floor((A[U]-w)/I);F=Math.min(F,p-1),o[F]++}const f=new Array(p).fill(0);f[0]=o[0];for(let U=1;U<p;U++)f[U]=f[U-1]+o[U];let M=Math.floor(v*h),d=0;for(;d<p&&!(f[d]>=M);)d++;const P=w;for(w=d*I+P,M=h-Math.floor((1-u)*x),d=0;d<p-1&&!(f[d+1]>=M);)d++;b=d*I+P;let S=1;return w!==b&&(S=(c-s)/(b-w)),[w,S]}function _n(n){const{datatypeCode:e,dims:t,affine:a,sclSlope:i,sclInter:r,toRAS:y=!1,isLinear:l=!0,asFloat32:s=!1,isRobustMinMax:c=!1}=n,v=bn(n.img,e),u=256,w=1,[b,,h]=dn(t,a,u,w,y),A=u*u*u,x=new Float32Array(A),p=t[1]*t[2]*t[3],I=new Float32Array(p);for(let _=0;_<p;_++)I[_]=v[_]*i+r;let o=1/0,f=-1/0;for(let _=0;_<p;_++){const C=I[_];C<o&&(o=C),C>f&&(f=C)}const M=t[1],d=t[2],P=t[3],S=M*d;function U(_,C,j){return _+C*M+j*S}const F=h;let Y=-1;if(l)for(let _=0;_<u;_++)for(let C=0;C<u;C++){const j=C*F[1]+_*F[2]+F[3],en=C*F[5]+_*F[6]+F[7],tn=C*F[9]+_*F[10]+F[11];for(let N=0;N<u;N++){const E=N*F[0]+j,Z=N*F[4]+en,k=N*F[8]+tn,rn=Math.floor(E),ln=Math.floor(Z),an=Math.floor(k);if(Y++,rn<0||ln<0||an<0)continue;const gn=Math.ceil(E),$n=Math.ceil(Z),En=Math.ceil(k);if(gn>=M||$n>=d||En>=P)continue;const O=E-rn,X=Z-ln,m=k-an,D=1-O,G=1-X,H=1-m,$=U(rn,ln,an);let R=0;R+=I[$]*D*G*H,R+=I[$+S]*D*G*m,R+=I[$+M]*D*X*H,R+=I[$+M+S]*D*X*m,R+=I[$+1]*O*G*H,R+=I[$+1+S]*O*G*m,R+=I[$+1+M]*O*X*H,R+=I[$+1+M+S]*O*X*m,x[Y]=R}}else for(let _=0;_<u;_++)for(let C=0;C<u;C++){const j=C*F[1]+_*F[2]+F[3],en=C*F[5]+_*F[6]+F[7],tn=C*F[9]+_*F[10]+F[11];for(let N=0;N<u;N++){const E=Math.round(N*F[0]+j),Z=Math.round(N*F[4]+en),k=Math.round(N*F[8]+tn);Y++,!(E<0||Z<0||k<0)&&(E>=M||Z>=d||k>=P||(x[Y]=I[U(E,Z,k)]))}}const g=c?NaN:0;let L,z,nn;if(s){const[_,C]=yn(e,v,i,r,0,0,o,f,0,1,g);L=Un(x,0,1,_,C),z=16,nn=32}else{const[_,C]=yn(e,v,i,r,0,0,o,f,0,255,g);L=Fn(x,0,255,_,C),z=2,nn=8}const Rn=Array.from(b);return{img:L,dims:[3,u,u,u,1,1,1,1],pixDims:[1,w,w,w,1,0,0,0],affine:Rn,datatypeCode:z,bitsPerVoxel:nn,sclSlope:1,sclInter:0,calMin:0,calMax:0}}function zn(n,e){if(!(n instanceof ArrayBuffer))return n;switch(e){case 2:return new Uint8Array(n);case 4:return new Int16Array(n);case 8:return new Int32Array(n);case 16:return new Float32Array(n);case 64:return new Float64Array(n);case 256:return new Int8Array(n);case 512:return new Uint16Array(n);case 768:return new Uint32Array(n);default:return new Float32Array(n)}}function V(n,e,t,a){return t*a[0]*a[1]+e*a[0]+n}function un(n,e,t){let a=0;const i=new Uint32Array(t+5).fill(0);let y=2147483647;for(let l=0;l<t;l++){let s=e[l];for(a=0;n[s-1]!==s&&(s=n[s-1],a++,!(a>100)););i[l]=s,y=Math.min(y,s)}for(let l=0;l<t;l++)n[i[l]-1]=y}function Cn(n,e,t,a,i,r,y,l){const s=new Uint32Array(27);let c=0;if(!i)return 0;const v=n[V(t,a,i,r)];if(y>=6){const u=V(t,a,i-1,r);v===n[u]&&(s[c++]=e[u])}if(y>=18){if(t){const u=V(t-1,a,i-1,r);v===n[u]&&(s[c++]=e[u])}if(a){const u=V(t,a-1,i-1,r);v===n[u]&&(s[c++]=e[u])}if(t<r[0]-1){const u=V(t+1,a,i-1,r);v===n[u]&&(s[c++]=e[u])}if(a<r[1]-1){const u=V(t,a+1,i-1,r);v===n[u]&&(s[c++]=e[u])}}if(y===26){if(t&&a){const u=V(t-1,a-1,i-1,r);v===n[u]&&(s[c++]=e[u])}if(t<r[0]-1&&a){const u=V(t+1,a-1,i-1,r);v===n[u]&&(s[c++]=e[u])}if(t&&a<r[1]-1){const u=V(t-1,a+1,i-1,r);v===n[u]&&(s[c++]=e[u])}if(t<r[0]-1&&a<r[1]-1){const u=V(t+1,a+1,i-1,r);v===n[u]&&(s[c++]=e[u])}}return c?(un(l,s,c),s[0]):0}function Vn(n,e,t){let a=1;const i=8192;let r=i,y=new Uint32Array(r).fill(0);const l=new Uint32Array(e[0]*e[1]*e[2]).fill(0),s=new Uint32Array(27);for(let c=0;c<e[2];c++)for(let v=0;v<e[1];v++)for(let u=0;u<e[0];u++){let w=0;const b=n[V(u,v,c,e)];if(b!==0){if(s[0]=Cn(n,l,u,v,c,e,t,y),s[0]&&(w+=1),t>=6){if(u){const h=V(u-1,v,c,e);b===n[h]&&(s[w++]=l[h])}if(v){const h=V(u,v-1,c,e);b===n[h]&&(s[w++]=l[h])}}if(t>=18){if(v&&u){const h=V(u-1,v-1,c,e);b===n[h]&&(s[w++]=l[h])}if(v&&u<e[0]-1){const h=V(u+1,v-1,c,e);b===n[h]&&(s[w++]=l[h])}}if(w)l[V(u,v,c,e)]=s[0],un(y,s,w);else{if(l[V(u,v,c,e)]=a,a>=r){r+=i;const h=new Uint32Array(r);h.set(y),y=h}y[a-1]=a,a++}}}for(let c=0;c<a-1;c++){let v=c;for(;y[v]!==v+1;)v=y[v]-1;y[c]=v+1}return[a-1,y,l]}function Sn(n,e,t,a){const i=e[0]*e[1]*e[2];let r=0;const y=new Uint32Array(i).fill(0);for(let c=0;c<a;c++)r=Math.max(r,t[c]);const l=new Uint32Array(r).fill(0);let s=0;for(let c=0;c<i;c++)n[c]&&(l[t[n[c]-1]-1]||(s+=1,l[t[n[c]-1]-1]=s),y[c]=l[t[n[c]-1]-1]);return[s,y]}function Pn(n,e,t){const a=n.length,i=new Uint32Array(e+1).fill(0),r=new Uint32Array(e+1).fill(0);for(let s=0;s<a;s++)i[t[s]]=n[s],r[t[s]]++;let y=0;for(let s=0;s<e+1;s++){const c=i[s];y=Math.max(y,c);for(let v=0;v<e+1;v++)v!==s&&c===i[v]&&(r[s]<r[v]||r[s]===r[v]&&s<v)&&(i[s]=0)}const l=new Uint32Array(a).fill(0);for(let s=0;s<a;s++)l[s]=i[t[s]];return[y,l]}function Nn(n){const{datatypeCode:e,dims:t,conn:a=26,binarize:i=!1,onlyLargestClusterPerClass:r=!1}=n,y=zn(n.img,e),l=Uint32Array.from([t[1],t[2],t[3]]),s=l[0]*l[1]*l[2],c=new Uint32Array(s).fill(0);if(i)for(let f=0;f<s;f++)y[f]!==0&&(c[f]=1);else for(let f=0;f<s;f++)c[f]=y[f];const[v,u,w]=Vn(c,l,a),[b,h]=Sn(w,l,u??new Uint32Array,v);let A,x;r?[A,x]=Pn(c,b,h):(A=b,x=h);let p,I,o;return A>65535?(p=Float32Array.from(x),I=16,o=32):A>255?(p=Uint16Array.from(x),I=512,o=16):(p=Uint8Array.from(x),I=2,o=8),{img:p,datatypeCode:I,bitsPerVoxel:o,calMax:A}}function vn(n,e,t,a,i,r=2){const y=n.length;if(y<1)return[];const l=256,s=l-1,c=new Array(l).fill(0),v=e,u=t;if(u<=v)return[];const w=(u-v)/l;function b(o){return o*w+v}const h=(l-1)/Math.abs(u-v);for(let o=0;o<y;o++){let f=n[o]*i+a;f=Math.min(Math.max(f,v),u),f=Math.round((f-v)*h),c[f]++}const A=Array(l).fill(0).map(()=>Array(l).fill(0)),x=Array(l).fill(0).map(()=>Array(l).fill(0));for(let o=1;o<l;++o)A[o][o]=c[o],x[o][o]=o*c[o];for(let o=1;o<l-1;++o)A[1][o+1]=A[1][o]+c[o+1],x[1][o+1]=x[1][o]+(o+1)*c[o+1];for(let o=2;o<l;o++)for(let f=o+1;f<l;f++)A[o][f]=A[1][f]-A[1][o-1],x[o][f]=x[1][f]-x[1][o-1];for(let o=1;o<l;++o)for(let f=o+1;f<l;f++)A[o][f]!==0&&(A[o][f]=x[o][f]*x[o][f]/A[o][f]);let p=0;const I=[1/0,1/0,1/0];if(r>3)for(let o=0;o<l-3;o++)for(let f=o+1;f<l-2;f++)for(let M=f+1;M<l-1;M++){const d=A[0][o]+A[o+1][f]+A[f+1][M]+A[M+1][s];d>p&&(I[0]=o,I[1]=f,I[2]=M,p=d)}else if(r===3)for(let o=0;o<l-2;o++)for(let f=o+1;f<l-1;f++){const M=A[0][o]+A[o+1][f]+A[f+1][s];M>p&&(I[0]=o,I[1]=f,p=M)}else for(let o=0;o<l-1;o++){const f=A[0][o]+A[o+1][s];f>p&&(I[0]=o,p=f)}return[b(I[0]),b(I[1]),b(I[2])]}function Yn(n,e){const t=n.length,a=new Uint8Array(t);for(let i=0;i<t;i++){const r=n[i];r>e[0]&&(a[i]=1),r>e[1]&&(a[i]=2),r>e[2]&&(a[i]=3)}return a}function Tn(n,e,t,a,i){const r=n.length,y=new Float32Array(r);for(let l=0;l<r;l++){const s=n[l]*t+e;y[l]=s<i?a:n[l]}return y}const W=self.postMessage.bind(self);function xn(n,e){if(!(n instanceof ArrayBuffer))return n;switch(e){case 2:return new Uint8Array(n);case 4:return new Int16Array(n);case 8:return new Int32Array(n);case 16:return new Float32Array(n);case 64:return new Float64Array(n);case 256:return new Int8Array(n);case 512:return new Uint16Array(n);case 768:return new Uint32Array(n);default:return new Float32Array(n)}}function An(n,e,t){let a=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;for(let r=0;r<n.length;r++){const y=n[r]*e+t;Number.isFinite(y)&&(y<a&&(a=y),y>i&&(i=y))}return[a,i]}const Ln={otsu(n,e,t,a,i){const r=i.levels??3,y=xn(n,e),l=t||1,s=a||0,[c,v]=An(y,l,s),u=vn(y,c,v,s,l,r);return{img:Yn(y,u),datatypeCode:2,bitsPerVoxel:8,sclSlope:1,sclInter:0,calMin:0,calMax:r}},removeHaze(n,e,t,a,i){const r=i.level??5,y=r===5||r===1?4:r===4||r===2?3:2,l=xn(n,e),s=t||1,c=a||0,[v,u]=An(l,s,c),w=vn(l,v,u,c,s,y),b=r===1?w[2]:r===2?w[1]:w[0];return{img:Tn(l,c,s,v,b),datatypeCode:16,bitsPerVoxel:32,sclSlope:1,sclInter:0,calMin:v,calMax:u}},conform(n,e,t,a,i){const r=_n({img:n,datatypeCode:e,dims:i.dims,pixDims:i.pixDims,affine:i.affine,sclSlope:t||1,sclInter:a||0,toRAS:i.toRAS??!1,isLinear:i.isLinear??!0,asFloat32:i.asFloat32??!1,isRobustMinMax:i.isRobustMinMax??!1});return{img:r.img,datatypeCode:r.datatypeCode,bitsPerVoxel:r.bitsPerVoxel,sclSlope:r.sclSlope,sclInter:r.sclInter,calMin:r.calMin,calMax:r.calMax,dims:r.dims,pixDims:r.pixDims,affine:r.affine}},connectedLabel(n,e,t,a,i){const r=Nn({img:n,datatypeCode:e,dims:i.dims,conn:i.conn??26,binarize:i.binarize??!1,onlyLargestClusterPerClass:i.onlyLargestClusterPerClass??!1});return{img:r.img,datatypeCode:r.datatypeCode,bitsPerVoxel:r.bitsPerVoxel,sclSlope:1,sclInter:0,calMin:0,calMax:r.calMax}}};self.onmessage=n=>{const{_wbId:e,name:t,img:a,datatypeCode:i,sclSlope:r,sclInter:y,options:l}=n.data,s=Ln[t];if(!s){W({_wbId:e,_wbError:`Unknown transform: ${t}`});return}try{const c=s(a,i,r,y,l??{});W({_wbId:e,...c},[c.img.buffer])}catch(c){W({_wbId:e,_wbError:c instanceof Error?c.message:String(c)})}}})();\n', c = typeof self < "u" && self.Blob && new Blob([f], { type: "text/javascript;charset=utf-8" });
|
|
3
|
-
function y(n) {
|
|
4
|
-
let e;
|
|
5
|
-
try {
|
|
6
|
-
if (e = c && (self.URL || self.webkitURL).createObjectURL(c), !e) throw "";
|
|
7
|
-
const t = new Worker(e, {
|
|
8
|
-
name: n == null ? void 0 : n.name
|
|
9
|
-
});
|
|
10
|
-
return t.addEventListener("error", () => {
|
|
11
|
-
(self.URL || self.webkitURL).revokeObjectURL(e);
|
|
12
|
-
}), t;
|
|
13
|
-
} catch {
|
|
14
|
-
return new Worker(
|
|
15
|
-
"data:text/javascript;charset=utf-8," + encodeURIComponent(f),
|
|
16
|
-
{
|
|
17
|
-
name: n == null ? void 0 : n.name
|
|
18
|
-
}
|
|
19
|
-
);
|
|
20
|
-
} finally {
|
|
21
|
-
e && (self.URL || self.webkitURL).revokeObjectURL(e);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
let i = null;
|
|
25
|
-
function d() {
|
|
26
|
-
return i || (i = new u(() => new y())), i;
|
|
27
|
-
}
|
|
28
|
-
async function s(n, e, t, l) {
|
|
29
|
-
const r = await d().execute({
|
|
30
|
-
name: n,
|
|
31
|
-
img: t,
|
|
32
|
-
datatypeCode: e.datatypeCode,
|
|
33
|
-
sclSlope: e.scl_slope,
|
|
34
|
-
sclInter: e.scl_inter,
|
|
35
|
-
options: l
|
|
36
|
-
}), a = JSON.parse(JSON.stringify(e));
|
|
37
|
-
if (a.datatypeCode = r.datatypeCode, a.numBitsPerVoxel = r.bitsPerVoxel, a.scl_slope = r.sclSlope, a.scl_inter = r.sclInter, a.cal_min = r.calMin, a.cal_max = r.calMax, r.dims && (a.dims = r.dims), r.pixDims && (a.pixDims = r.pixDims), r.affine) {
|
|
38
|
-
const o = r.affine;
|
|
39
|
-
a.affine = [
|
|
40
|
-
[o[0], o[1], o[2], o[3]],
|
|
41
|
-
[o[4], o[5], o[6], o[7]],
|
|
42
|
-
[o[8], o[9], o[10], o[11]],
|
|
43
|
-
[0, 0, 0, 1]
|
|
44
|
-
], a.sform_code = 1, a.qform_code = 0;
|
|
45
|
-
}
|
|
46
|
-
return { hdr: a, img: r.img };
|
|
47
|
-
}
|
|
48
|
-
const w = {
|
|
49
|
-
name: "otsu",
|
|
50
|
-
description: "Otsu multi-level thresholding — produces a labeled segmentation volume",
|
|
51
|
-
options: [
|
|
52
|
-
{
|
|
53
|
-
name: "levels",
|
|
54
|
-
type: "select",
|
|
55
|
-
label: "Segmentation levels",
|
|
56
|
-
default: 3,
|
|
57
|
-
options: [2, 3, 4]
|
|
58
|
-
}
|
|
59
|
-
],
|
|
60
|
-
resultDefaults: {
|
|
61
|
-
colormap: "actc",
|
|
62
|
-
opacity: 0.5
|
|
63
|
-
},
|
|
64
|
-
apply: (n, e, t) => s("otsu", n, e, t)
|
|
65
|
-
}, A = {
|
|
66
|
-
name: "conform",
|
|
67
|
-
description: "Reslice to 256×256×256 isotropic 1 mm volume (FreeSurfer style)",
|
|
68
|
-
options: [
|
|
69
|
-
{
|
|
70
|
-
name: "toRAS",
|
|
71
|
-
type: "checkbox",
|
|
72
|
-
label: "Output RAS orientation",
|
|
73
|
-
default: !1
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: "isLinear",
|
|
77
|
-
type: "checkbox",
|
|
78
|
-
label: "Linear interpolation",
|
|
79
|
-
default: !0
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
name: "asFloat32",
|
|
83
|
-
type: "checkbox",
|
|
84
|
-
label: "Output as Float32",
|
|
85
|
-
default: !1
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: "isRobustMinMax",
|
|
89
|
-
type: "checkbox",
|
|
90
|
-
label: "Robust min/max (2%-98%)",
|
|
91
|
-
default: !1
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
apply: (n, e, t) => {
|
|
95
|
-
const l = {
|
|
96
|
-
...t,
|
|
97
|
-
dims: [...n.dims],
|
|
98
|
-
pixDims: [...n.pixDims],
|
|
99
|
-
affine: n.affine.flat()
|
|
100
|
-
};
|
|
101
|
-
return s("conform", n, e, l);
|
|
102
|
-
}
|
|
103
|
-
}, m = {
|
|
104
|
-
name: "connectedLabel",
|
|
105
|
-
description: "Label connected components in a volume (bwlabel)",
|
|
106
|
-
options: [
|
|
107
|
-
{
|
|
108
|
-
name: "conn",
|
|
109
|
-
type: "select",
|
|
110
|
-
label: "Connectivity",
|
|
111
|
-
default: 26,
|
|
112
|
-
options: [6, 18, 26]
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
name: "binarize",
|
|
116
|
-
type: "checkbox",
|
|
117
|
-
label: "Binarize input",
|
|
118
|
-
default: !1
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
name: "onlyLargestClusterPerClass",
|
|
122
|
-
type: "checkbox",
|
|
123
|
-
label: "Only largest cluster per class",
|
|
124
|
-
default: !1
|
|
125
|
-
}
|
|
126
|
-
],
|
|
127
|
-
resultDefaults: {
|
|
128
|
-
colormap: "random",
|
|
129
|
-
opacity: 0.8
|
|
130
|
-
},
|
|
131
|
-
apply: (n, e, t) => {
|
|
132
|
-
const l = { ...t, dims: [...n.dims] };
|
|
133
|
-
return s("connectedLabel", n, e, l);
|
|
134
|
-
}
|
|
135
|
-
}, v = {
|
|
136
|
-
name: "removeHaze",
|
|
137
|
-
description: "Remove dark background voxels using Otsu thresholding",
|
|
138
|
-
options: [
|
|
139
|
-
{
|
|
140
|
-
name: "level",
|
|
141
|
-
type: "select",
|
|
142
|
-
label: "Preservation level (1=aggressive, 5=conservative)",
|
|
143
|
-
default: 5,
|
|
144
|
-
options: [1, 2, 3, 4, 5]
|
|
145
|
-
}
|
|
146
|
-
],
|
|
147
|
-
apply: (n, e, t) => s("removeHaze", n, e, t)
|
|
148
|
-
};
|
|
149
|
-
export {
|
|
150
|
-
A as conform,
|
|
151
|
-
m as connectedLabel,
|
|
152
|
-
w as otsu,
|
|
153
|
-
v as removeHaze
|
|
154
|
-
};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FreeSurfer-style conform transform — pure computation.
|
|
3
|
-
*
|
|
4
|
-
* Reslices any image to a 256×256×256 isotropic volume with 1 mm voxels,
|
|
5
|
-
* centered on the original volume. Optionally rescales intensities.
|
|
6
|
-
*
|
|
7
|
-
* Based on FastSurfer conform.py (Apache License) and nibabel mghformat.py (MIT License).
|
|
8
|
-
*/
|
|
9
|
-
export interface ConformInput {
|
|
10
|
-
/** Flat voxel data */
|
|
11
|
-
img: ArrayLike<number>;
|
|
12
|
-
/** NIfTI datatype code */
|
|
13
|
-
datatypeCode: number;
|
|
14
|
-
/** Volume dimensions [ndim, x, y, z, ...] */
|
|
15
|
-
dims: number[];
|
|
16
|
-
/** Pixel dimensions [qfac, dx, dy, dz, ...] */
|
|
17
|
-
pixDims: number[];
|
|
18
|
-
/** 4×4 affine as flat 16-element array (row-major) */
|
|
19
|
-
affine: number[];
|
|
20
|
-
sclSlope: number;
|
|
21
|
-
sclInter: number;
|
|
22
|
-
/** Options */
|
|
23
|
-
toRAS?: boolean;
|
|
24
|
-
isLinear?: boolean;
|
|
25
|
-
asFloat32?: boolean;
|
|
26
|
-
isRobustMinMax?: boolean;
|
|
27
|
-
}
|
|
28
|
-
export interface ConformOutput {
|
|
29
|
-
img: ArrayBufferView;
|
|
30
|
-
dims: number[];
|
|
31
|
-
pixDims: number[];
|
|
32
|
-
affine: number[];
|
|
33
|
-
datatypeCode: number;
|
|
34
|
-
bitsPerVoxel: number;
|
|
35
|
-
sclSlope: number;
|
|
36
|
-
sclInter: number;
|
|
37
|
-
calMin: number;
|
|
38
|
-
calMax: number;
|
|
39
|
-
}
|
|
40
|
-
export declare function computeConform(input: ConformInput): ConformOutput;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Connected component labeling — pure computation.
|
|
3
|
-
*
|
|
4
|
-
* Port of https://github.com/rordenlab/niimath/blob/master/src/bwlabel.c
|
|
5
|
-
*/
|
|
6
|
-
export interface ConnectedLabelInput {
|
|
7
|
-
img: ArrayLike<number> | ArrayBuffer;
|
|
8
|
-
datatypeCode: number;
|
|
9
|
-
dims: number[];
|
|
10
|
-
conn?: number;
|
|
11
|
-
binarize?: boolean;
|
|
12
|
-
onlyLargestClusterPerClass?: boolean;
|
|
13
|
-
}
|
|
14
|
-
export interface ConnectedLabelOutput {
|
|
15
|
-
img: ArrayBufferView;
|
|
16
|
-
datatypeCode: number;
|
|
17
|
-
bitsPerVoxel: number;
|
|
18
|
-
calMax: number;
|
|
19
|
-
}
|
|
20
|
-
export declare function computeConnectedLabel(input: ConnectedLabelInput): ConnectedLabelOutput;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure Otsu thresholding functions.
|
|
3
|
-
* Ported from the old niivue ImageProcessing module.
|
|
4
|
-
*
|
|
5
|
-
* These functions are designed to run in a Web Worker (no DOM dependencies).
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Compute one or more Otsu threshold levels for a volume.
|
|
9
|
-
*
|
|
10
|
-
* Based on:
|
|
11
|
-
* - C: https://github.com/rordenlab/niimath
|
|
12
|
-
* - Java: https://github.com/stevenjwest/Multi_OTSU_Segmentation
|
|
13
|
-
*/
|
|
14
|
-
export declare function findOtsu(img: ArrayLike<number>, calMin: number, calMax: number, sclInter: number, sclSlope: number, mlevel?: number): number[];
|
|
15
|
-
/**
|
|
16
|
-
* Apply Otsu thresholds to produce a labeled segmentation.
|
|
17
|
-
*/
|
|
18
|
-
export declare function applyOtsu(img: ArrayLike<number>, thresholds: number[]): Uint8Array;
|
|
19
|
-
/**
|
|
20
|
-
* Apply haze removal: zero out voxels below the threshold.
|
|
21
|
-
*/
|
|
22
|
-
export declare function applyHazeRemoval(img: ArrayLike<number>, sclInter: number, sclSlope: number, globalMin: number, threshold: number): Float32Array;
|
package/dist/transforms.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { VolumeTransform } from '@niivue/niivue';
|
|
2
|
-
export declare function terminateWorker(): void;
|
|
3
|
-
export declare const otsu: VolumeTransform;
|
|
4
|
-
export declare const conform: VolumeTransform;
|
|
5
|
-
export declare const connectedLabel: VolumeTransform;
|
|
6
|
-
export declare const removeHaze: VolumeTransform;
|
package/dist/worker.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Web Worker for nv-ext-image-processing transforms.
|
|
3
|
-
*
|
|
4
|
-
* Speaks only primitives — no NIFTI header objects cross the boundary.
|
|
5
|
-
*
|
|
6
|
-
* Protocol (NVWorker bridge):
|
|
7
|
-
* Request: { _wbId, name, img, datatypeCode, sclSlope, sclInter, ...options }
|
|
8
|
-
* Response: { _wbId, img, datatypeCode, bitsPerVoxel, sclSlope, sclInter, calMin, calMax }
|
|
9
|
-
* Error: { _wbId, _wbError: string }
|
|
10
|
-
*/
|
|
11
|
-
export {};
|