| Server IP : 217.154.3.148 / Your IP : 216.73.216.90 Web Server : Apache System : Linux blissful-wright.217-154-3-148.plesk.page 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 User : gracious-boyd_hfhh1h8vo9n ( 10000) PHP Version : 8.3.31 Disable Function : opcache_get_status MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/lib/analyzers/ |
Upload File : |
/**
* Oriented Projections mit Occluder-Maske:
* - bevorzuge vertikale Kanten für Spalten-Projektion (projX)
* - bevorzuge horizontale Kanten für Zeilen-Projektion (projY)
* - dämpfe "Occluder" (stark texturiert / Ecken: |gx| und |gy| beide groß)
*/
function clamp(v:number, lo:number, hi:number){ return Math.max(lo, Math.min(hi, v)); }
function percentile(arr:number[], p:number): number {
if (!arr.length) return 0;
const a = arr.slice().sort((x,y)=>x-y);
const idx = clamp((p/100)*(a.length-1), 0, a.length-1);
const lo = Math.floor(idx), hi = Math.ceil(idx);
if (lo===hi) return a[lo];
const t = idx-lo; return a[lo]*(1-t)+a[hi]*t;
}
export function orientedProjectionsWithOccluder(
gray: Float32Array, w: number, h: number,
opts?: { orientGate?: number } // orientGate ~ wie streng die Orientierungs-Selektion ist
){
const projX = new Float32Array(w);
const projY = new Float32Array(h);
const gxAbsArr:number[] = [];
const gyAbsArr:number[] = [];
// 1) Gradienten
const abs = Math.abs;
// sammeln für Schwellen
for (let y=1; y<h-1; y++){
const o = y*w;
for (let x=1; x<w-1; x++){
const i = o+x;
const gx = gray[i+1]-gray[i-1];
const gy = gray[i+w]-gray[i-w];
gxAbsArr.push(abs(gx));
gyAbsArr.push(abs(gy));
}
}
const qx = Math.max(1e-6, percentile(gxAbsArr, 85));
const qy = Math.max(1e-6, percentile(gyAbsArr, 85));
const gate = opts?.orientGate ?? 0.5; // 0.5 = recht streng: |gy|/|gx| < 0.5 gilt als vertikal
const eps = 1e-6;
// 2) Gewichtetes Aufsummieren
for (let y=1; y<h-1; y++){
const o = y*w;
for (let x=1; x<w-1; x++){
const i = o+x;
const gx = gray[i+1]-gray[i-1];
const gy = gray[i+w]-gray[i-w];
let ax = abs(gx), ay = abs(gy);
// Occluder-Kennzeichnung: "Ecke" -> beide groß; winsorize gegen Ausreißer
const axw = Math.min(ax, qx);
const ayw = Math.min(ay, qy);
const isCorner = (axw>0.6*qx && ayw>0.6*qy); // grob: beides relativ groß
// Orientierungsgates:
const vertOk = (ay/(ax+eps) < gate); // vertikale Linien -> starker gx, schwacher gy
const horiOk = (ax/(ay+eps) < gate); // horizontale Linien -> starker gy, schwacher gx
// Gewichte: Corner dämpfen
const damp = isCorner ? 0.25 : 1.0;
if (vertOk){
projX[x] += axw * damp;
}
if (horiOk){
projY[y] += ayw * damp;
}
}
}
// leichte Glättung (3-Tap)
const smooth1D = (arr: Float32Array) => {
const out = new Float32Array(arr.length);
if (arr.length<3) return arr.slice();
out[0] = (arr[0]*2 + arr[1]) / 3;
for (let i=1;i<arr.length-1;i++){
out[i] = (arr[i-1]+arr[i]*2+arr[i+1]) / 4;
}
out[arr.length-1] = (arr[arr.length-2] + arr[arr.length-1]*2)/3;
return out;
};
const projX_s = smooth1D(projX);
const projY_s = smooth1D(projY);
return { projX: projX_s, projY: projY_s };
}