学習AIから画像を保護する「NoiseEncoder」

【更新履歴】

 ・2026/3/24 バージョン1.0公開。
          (中略)
 ・2026/3/24 バージョン1.5公開。


【概要】

・自分で描いた画像を公開したいけど、
 AIに学習されるのはイヤだ!
 という場合があると思います。

・このツールでは、
 加工したアニメpngなどを生成して、
 クローリングや、スクレーピングから
 あなたの画像を保護します。

・フレームごとの画像は、学習しにくいように
 特殊な加工が施されています。 


画像

・ダウンロードされる方はこちら。↓

・ソースコードはこちら。↓

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Noise Encoder 1.5</title>

<style>
body { font-family: sans-serif; }
canvas { border:1px solid #ccc; margin:5px; }

#previewArea {
    display:flex;
}

button { margin:3px; }
</style>

</head>
<body>

<h2>Noise Encoder 1.5</h2>

<input type="file" id="fileInput"><br><br>

フレーム数: <input type="number" id="frameCount" value="8"><br>
低周波: <input type="number" id="lowFreq" value="12"><br>
ノイズ: <input type="number" id="noise" value="4"><br>
位相: <input type="number" id="phase" step="0.01" value="0.15"><br>
FPS: <input type="number" id="fps" value="60"><br><br>

<button id="generateBtn">生成</button>
<button id="cancelBtn">キャンセル</button>
<button id="playBtn">再生</button>
<button id="stopBtn">停止</button>
<button id="exportPNG">PNG出力</button>
<button id="exportWEBM">WebM出力</button>

<hr>

<div id="previewArea">
    <canvas id="original"></canvas>
    <canvas id="preview"></canvas>
</div>

<hr>

<button id="prevBtn">前</button>
<button id="nextBtn">次</button>
<span id="frameIndex"></span><br>
<canvas id="frameView"></canvas>

<script>

// ===== 状態 =====
var frames = [];
var timer = null;
var idx = 0;
var w=0,h=0;

// ===== 乱数 =====
function Random(seed){this.s=seed;}
Random.prototype.next=function(){
    this.s=(this.s*1664525+1013904223)>>>0;
    return this.s/4294967296;
};

// ===== DCT =====
function C(u){return u==0?1/Math.sqrt(2):1;}

function dct(b){
    var o=new Array(64);
    for(var v=0;v<8;v++)
    for(var u=0;u<8;u++){
        var s=0;
        for(var y=0;y<8;y++)
        for(var x=0;x<8;x++){
            s+=b[y*8+x]*Math.cos((2*x+1)*u*Math.PI/16)*Math.cos((2*y+1)*v*Math.PI/16);
        }
        o[v*8+u]=0.25*C(u)*C(v)*s;
    }
    return o;
}

function idct(b){
    var o=new Array(64);
    for(var y=0;y<8;y++)
    for(var x=0;x<8;x++){
        var s=0;
        for(var v=0;v<8;v++)
        for(var u=0;u<8;u++){
            s+=C(u)*C(v)*b[v*8+u]*Math.cos((2*x+1)*u*Math.PI/16)*Math.cos((2*y+1)*v*Math.PI/16);
        }
        o[y*8+x]=0.25*s;
    }
    return o;
}

// ===== フレーム生成 =====
function generate(data,params){
    var out=[];

    for(var f=0;f<params.frameCount;f++){
        var rand=new Random(f*999);
        var frame=new Uint8ClampedArray(data.length);

        for(var by=0;by<h;by+=8)
        for(var bx=0;bx<w;bx+=8){

            var r=[],g=[],b=[];

            for(var y=0;y<8;y++)
            for(var x=0;x<8;x++){
                var px=bx+x,py=by+y;
                if(px>=w||py>=h){r.push(0);g.push(0);b.push(0);continue;}
                var i=(py*w+px)*4;
                r.push(data[i]);g.push(data[i+1]);b.push(data[i+2]);
            }

            var dR=dct(r),dG=dct(g),dB=dct(b);

            for(var i=params.lowFreq;i<64;i++){
                var j=params.lowFreq+Math.floor(rand.next()*(64-params.lowFreq));
                var t=dR[i];dR[i]=dR[j];dR[j]=t;
                t=dG[i];dG[i]=dG[j];dG[j]=t;
                t=dB[i];dB[i]=dB[j];dB[j]=t;

                dR[i]+= (rand.next()-0.5)*params.noise;
                dG[i]+= (rand.next()-0.5)*params.noise;
                dB[i]+= (rand.next()-0.5)*params.noise;
            }

            var oR=idct(dR),oG=idct(dG),oB=idct(dB);

            for(var y=0;y<8;y++)
            for(var x=0;x<8;x++){
                var px=bx+x,py=by+y;
                if(px>=w||py>=h)continue;
                var i=(py*w+px)*4;
                var k=y*8+x;
                frame[i]=oR[k];
                frame[i+1]=oG[k];
                frame[i+2]=oB[k];
                frame[i+3]=255;
            }
        }

        out.push(frame);
    }

    return out;
}

// ===== 表示 =====
function showFrame(i){
    var c=document.getElementById("frameView");
    var ctx=c.getContext("2d");
    c.width=w;c.height=h;

    var img=ctx.createImageData(w,h);
    img.data.set(frames[i]);
    ctx.putImageData(img,0,0);

    frameIndex.innerText=(i+1)+"/"+frames.length;
}

// ===== 再生 =====
function play(fps){
    var c=document.getElementById("preview");
    var ctx=c.getContext("2d");
    c.width=w;c.height=h;

    clearInterval(timer);
    idx=0;

    timer=setInterval(function(){
        var img=ctx.createImageData(w,h);
        img.data.set(frames[idx]);
        ctx.putImageData(img,0,0);
        idx=(idx+1)%frames.length;
    },1000/fps);
}

// ===== PNG出力 =====
function exportPNG(){
    frames.forEach((f,i)=>{
        var c=document.createElement("canvas");
        c.width=w;c.height=h;
        var ctx=c.getContext("2d");

        var img=ctx.createImageData(w,h);
        img.data.set(f);
        ctx.putImageData(img,0,0);

        var a=document.createElement("a");
        a.href=c.toDataURL();
        a.download="frame_"+i+".png";
        a.click();
    });
}

// ===== WebM出力 =====
function exportWEBM(){
    var c=document.getElementById("preview");
    var stream=c.captureStream();
    var rec=new MediaRecorder(stream);
    var chunks=[];

    rec.ondataavailable=e=>chunks.push(e.data);
    rec.onstop=e=>{
        var blob=new Blob(chunks,{type:"video/webm"});
        var a=document.createElement("a");
        a.href=URL.createObjectURL(blob);
        a.download="output.webm";
        a.click();
    };

    rec.start();

    var i=0;
    var ctx=c.getContext("2d");

    var interval=setInterval(()=>{
        var img=ctx.createImageData(w,h);
        img.data.set(frames[i]);
        ctx.putImageData(img,0,0);

        i++;
        if(i>=frames.length){
            clearInterval(interval);
            rec.stop();
        }
    },1000/30);
}

// ===== UI =====
generateBtn.onclick=function(){
    var file=fileInput.files[0];
    var img=new Image();

    img.onload=function(){
        w=img.width;h=img.height;

        var c=original;
        var ctx=c.getContext("2d");
        c.width=w;c.height=h;
        ctx.drawImage(img,0,0);

        var data=ctx.getImageData(0,0,w,h);

        frames=generate(data.data,{
            frameCount:+frameCount.value,
            lowFreq:+lowFreq.value,
            noise:+noise.value,
            phase:+phase.value
        });

        showFrame(0);
        play(+fps.value);
    };

    img.src=URL.createObjectURL(file);
};

prevBtn.onclick=function(){
    idx=(idx-1+frames.length)%frames.length;
    showFrame(idx);
};

nextBtn.onclick=function(){
    idx=(idx+1)%frames.length;
    showFrame(idx);
};

playBtn.onclick=function(){ play(+fps.value); };
stopBtn.onclick=function(){ clearInterval(timer); };

exportPNG.onclick=exportPNG;
exportWEBM.onclick=exportWEBM;

</script>

</body>
</html>



いいなと思ったら応援しよう!

コメント

コメントするには、 ログイン または 会員登録 をお願いします。
学習AIから画像を保護する「NoiseEncoder」|古井和雄
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1