summaryrefslogtreecommitdiff
path: root/cnn_v3
diff options
context:
space:
mode:
Diffstat (limited to 'cnn_v3')
-rw-r--r--cnn_v3/training/adjust.html239
1 files changed, 239 insertions, 0 deletions
diff --git a/cnn_v3/training/adjust.html b/cnn_v3/training/adjust.html
new file mode 100644
index 0000000..219145c
--- /dev/null
+++ b/cnn_v3/training/adjust.html
@@ -0,0 +1,239 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Align & Optimize</title>
+<style>
+body{font-family:sans-serif;text-align:center;background:#f5f5f5}
+canvas{border:1px solid #ccc;margin-top:10px;cursor:grab}
+</style>
+</head>
+<body>
+
+<h3>Align & Optimize (Arrows=move, Shift+Arrows=scale)</h3>
+
+<input type="file" id="f1" accept="image/*">
+<input type="file" id="f2" accept="image/*"><br><br>
+
+Alpha <input type="range" id="alpha" min="0.2" max="1" step="0.01" value="0.5">
+<br><br>
+
+<button id="crop">Crop</button>
+<button id="opt">Optimize</button>
+<button id="dl" disabled>Download</button>
+
+<div>MSE: <span id="score">-</span></div>
+
+<canvas id="c"></canvas>
+
+<script>
+const c=document.getElementById('c'),x=c.getContext('2d');
+let i1=new Image(),i2=new Image(),l1=0,l2=0;
+
+let ox=0,oy=0,sx=1,sy=1;
+let drag=0,lx,ly,mx=0,my=0,a=document.getElementById('alpha');
+
+let out1,out2;
+
+// finer than before
+const PAN_STEP=0.3;
+const SCALE_STEP=0.002; // 🔬 very fine zoom
+const DRAG_SPEED=0.4;
+
+// MSE buffers (reused)
+let buf1=document.createElement('canvas');
+let buf2=document.createElement('canvas');
+let b1=buf1.getContext('2d');
+let b2=buf2.getContext('2d');
+const SAMPLE=128;
+
+// load images
+f1.onchange=e=>{
+ i1=new Image();
+ i1.onload=()=>{
+ l1=1;c.width=i1.width;c.height=i1.height;
+ ox=oy=0;sx=sy=1;draw();
+ };
+ i1.src=URL.createObjectURL(e.target.files[0]);
+};
+
+f2.onchange=e=>{
+ i2=new Image();
+ i2.onload=()=>{
+ l2=1;
+ ox=(c.width-i2.width)/2;
+ oy=(c.height-i2.height)/2;
+ sx=sy=1;draw();
+ };
+ i2.src=URL.createObjectURL(e.target.files[0]);
+};
+
+function draw(){
+ if(!l1)return;
+ x.clearRect(0,0,c.width,c.height);
+ x.drawImage(i1,0,0);
+ if(l2){
+ x.save();
+ x.globalAlpha=a.value;
+ x.translate(ox,oy);
+ x.scale(sx,sy);
+ x.drawImage(i2,0,0);
+ x.restore();
+ }
+ updateScore();
+}
+
+// --- FAST MSE ---
+function computeMSE(){
+ let x2=ox,y2=oy,w2=i2.width*sx,h2=i2.height*sy;
+ let x0=Math.max(0,x2),y0=Math.max(0,y2);
+ let x1=Math.min(c.width,x2+w2),y1=Math.min(c.height,y2+h2);
+ let w=Math.floor(x1-x0),h=Math.floor(y1-y0);
+ if(w<=0||h<=0)return Infinity;
+
+ let scale=Math.min(1,SAMPLE/Math.max(w,h));
+ let sw=Math.max(1,Math.floor(w*scale));
+ let sh=Math.max(1,Math.floor(h*scale));
+
+ buf1.width=buf2.width=sw;
+ buf1.height=buf2.height=sh;
+
+ b1.drawImage(i1,x0,y0,w,h,0,0,sw,sh);
+ b2.drawImage(i2,(x0-ox)/sx,(y0-oy)/sy,w/sx,h/sy,0,0,sw,sh);
+
+ let d1=b1.getImageData(0,0,sw,sh).data;
+ let d2=b2.getImageData(0,0,sw,sh).data;
+
+ let mse=0,n=sw*sh;
+
+ for(let i=0;i<d1.length;i+=4){
+ let g1=0.299*d1[i]+0.587*d1[i+1]+0.114*d1[i+2];
+ let g2=0.299*d2[i]+0.587*d2[i+1]+0.114*d2[i+2];
+ let d=g1-g2;
+ mse+=d*d;
+ }
+
+ return mse/n;
+}
+
+function updateScore(){
+ if(l1&&l2){
+ let s=computeMSE();
+ score.textContent=isFinite(s)?s.toFixed(2):"-";
+ }
+}
+
+// mouse
+c.onmousemove=e=>{
+ mx=e.offsetX;my=e.offsetY;
+ if(!drag)return;
+ ox+=(e.offsetX-lx)*DRAG_SPEED;
+ oy+=(e.offsetY-ly)*DRAG_SPEED;
+ lx=e.offsetX;ly=e.offsetY;
+ draw();
+};
+
+c.onmousedown=e=>{drag=1;lx=e.offsetX;ly=e.offsetY;c.style.cursor="grabbing";}
+c.onmouseup=c.onmouseleave=()=>{drag=0;c.style.cursor="grab";};
+
+a.oninput=draw;
+
+// keyboard
+document.onkeydown=e=>{
+ if(!l2)return;
+ if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].includes(e.key)) e.preventDefault();
+
+ if(e.shiftKey){
+ // scale around mouse
+ let ix=(mx-ox)/sx,iy=(my-oy)/sy;
+
+ if(e.key==="ArrowRight") sx+=SCALE_STEP;
+ if(e.key==="ArrowLeft") sx-=SCALE_STEP;
+ if(e.key==="ArrowUp") sy+=SCALE_STEP;
+ if(e.key==="ArrowDown") sy-=SCALE_STEP;
+
+ ox=mx-ix*sx;
+ oy=my-iy*sy;
+
+ } else {
+ // move
+ if(e.key==="ArrowRight") ox+=PAN_STEP;
+ if(e.key==="ArrowLeft") ox-=PAN_STEP;
+ if(e.key==="ArrowUp") oy-=PAN_STEP;
+ if(e.key==="ArrowDown") oy+=PAN_STEP;
+ }
+
+ draw();
+};
+
+// --- OPTIMIZER (safe + fast) ---
+opt.onclick=async ()=>{
+ if(!l1||!l2)return;
+
+ let best={ox,oy,sx,sy,score:computeMSE()};
+
+ for(let iter=0;iter<10;iter++){
+
+ let stepO=0.5/(iter+1);
+ let stepS=0.005/(iter+1);
+
+ let valuesO=[-stepO,-stepO/2,0,stepO/2,stepO];
+ let valuesS=[-stepS,-stepS/2,0,stepS/2,stepS];
+
+ for(let dx of valuesO)
+ for(let dy of valuesO)
+ for(let dsx of valuesS)
+ for(let dsy of valuesS){
+
+ let tox=best.ox+dx;
+ let toy=best.oy+dy;
+ let tsx=best.sx+dsx;
+ let tsy=best.sy+dsy;
+
+ ox=tox;oy=toy;sx=tsx;sy=tsy;
+
+ let s=computeMSE();
+ if(s<best.score){
+ best={ox:tox,oy:toy,sx:tsx,sy:tsy,score:s};
+ }
+ }
+
+ ox=best.ox;oy=best.oy;sx=best.sx;sy=best.sy;
+ draw();
+
+ await new Promise(r=>setTimeout(r,0)); // keep UI responsive
+ }
+};
+
+// crop + download
+crop.onclick=()=>{
+ let x2=ox,y2=oy,w2=i2.width*sx,h2=i2.height*sy;
+ let x0=Math.max(0,x2),y0=Math.max(0,y2);
+ let x1=Math.min(c.width,x2+w2),y1=Math.min(c.height,y2+h2);
+ let w=x1-x0,h=y1-y0;
+ if(w<=0||h<=0)return alert("no overlap");
+
+ out1=document.createElement('canvas');
+ out2=document.createElement('canvas');
+ out1.width=out2.width=w;
+ out1.height=out2.height=h;
+
+ out1.getContext('2d').drawImage(i1,x0,y0,w,h,0,0,w,h);
+ out2.getContext('2d').drawImage(i2,(x0-ox)/sx,(y0-oy)/sy,w/sx,h/sy,0,0,w,h);
+
+ dl.disabled=0;
+};
+
+dl.onclick=()=>{
+ let d=(cv,n)=>{
+ let a=document.createElement('a');
+ a.download=n+'.clipped.png';
+ a.href=cv.toDataURL();
+ a.click();
+ };
+ d(out1,'image1');d(out2,'image2');
+};
+</script>
+
+</body>
+</html> \ No newline at end of file