diff --git a/index.html b/index.html index 3c2639c..d9e01dd 100644 --- a/index.html +++ b/index.html @@ -428,7 +428,7 @@ - + @@ -465,7 +465,7 @@ src="js/ui/tool/generic.js?v=3e678e0" type="text/javascript"> - + diff --git a/js/lib/util.js b/js/lib/util.js index 0607dcd..2955e2d 100644 --- a/js/lib/util.js +++ b/js/lib/util.js @@ -483,7 +483,7 @@ const makeElement = ( * @param {number}} blur * @returns {HTMLCanvasElement} */ -const subtractBackground = (canvas, bb, bgImg, blur = 0) => { +const subtractBackground = (canvas, bb, bgImg, blur = 0, threshold = 10) => { // set up temp canvases const bgCanvas = document.createElement("canvas"); const fgCanvas = document.createElement("canvas"); @@ -503,19 +503,22 @@ const subtractBackground = (canvas, bb, bgImg, blur = 0) => { // draw new image fgCtx.drawImage(canvas, 0, 0); const fgImgData = fgCtx.getImageData(0, 0, bb.w, bb.h); - // const blendImgData = blendCtx.getImageData(0, 0, bb.w, bb.h); for (var i = 0; i < bgImgData.data.length; i += 4) { + // one of these days i'm gonna learn how to use map reduce or whatever and stop iterating in for loops :( + // a la https://adamwathan.me/refactoring-to-collections/ + + // background rgb var bgr = bgImgData.data[i]; var bgg = bgImgData.data[i + 1]; var bgb = bgImgData.data[i + 2]; - + // foreground rgb var fgr = fgImgData.data[i]; var fgb = fgImgData.data[i + 1]; var fgd = fgImgData.data[i + 2]; - - const dr = Math.abs(bgr - fgr) > 10 ? fgr : 0; - const dg = Math.abs(bgg - fgb) > 10 ? fgb : 0; - const db = Math.abs(bgb - fgd) > 10 ? fgd : 0; + // delta rgb + const dr = Math.abs(bgr - fgr) > threshold ? fgr : 0; + const dg = Math.abs(bgg - fgb) > threshold ? fgb : 0; + const db = Math.abs(bgb - fgd) > threshold ? fgd : 0; const pxChanged = dr > 0 && dg > 0 && db > 0; diff --git a/js/ui/tool/dream.js b/js/ui/tool/dream.js index 3bf03d5..66d17c7 100644 --- a/js/ui/tool/dream.js +++ b/js/ui/tool/dream.js @@ -538,7 +538,13 @@ const _generate = async (endpoint, request, bb, options = {}) => { endpoint == "img2img" && toolbar._current_tool.state.removeBackground ) { - canvas = subtractBackground(canvas, bb, dreamData.bgImg, 0); + canvas = subtractBackground( + canvas, + bb, + dreamData.bgImg, + toolbar._current_tool.state.carve_blur, + toolbar._current_tool.state.carve_threshold + ); } commands.runCommand("drawImage", "Image Dream", { @@ -1760,7 +1766,16 @@ const dreamTool = () => state, "removeBackground", "Remove Identical/BG Pixels", - "icon-slice" + "icon-slice", + () => { + if (state.removeBackground) { + state.ctxmenu.carveBlurLabel.classList.remove("invisible"); + state.ctxmenu.carveThresholdLabel.classList.remove("invisible"); + } else { + state.ctxmenu.carveBlurLabel.classList.add("invisible"); + state.ctxmenu.carveThresholdLabel.classList.add("invisible"); + } + } ).checkbox; // Overmasking Slider @@ -1788,6 +1803,32 @@ const dreamTool = () => textStep: 1, } ).slider; + // bg carve blur + state.ctxmenu.carveBlurLabel = _toolbar_input.slider( + state, + "carve_blur", + "BG Remove Blur", + { + min: 0, + max: 30, + step: 2, + textStep: 1, + } + ).slider; + state.ctxmenu.carveBlurLabel.classList.add("invisible"); + // bg carve threshold + state.ctxmenu.carveThresholdLabel = _toolbar_input.slider( + state, + "carve_threshold", + "BG Remove Threshold", + { + min: 0, + max: 255, + step: 5, + textStep: 1, + } + ).slider; + state.ctxmenu.carveThresholdLabel.classList.add("invisible"); } menu.appendChild(state.ctxmenu.cursorSizeSlider); @@ -1805,6 +1846,8 @@ const dreamTool = () => // menu.appendChild(state.ctxmenu.keepUnmaskedBlurSliderLinebreak); // menu.appendChild(state.ctxmenu.preserveMasksLabel); // menu.appendChild(document.createElement("br")); + menu.appendChild(state.ctxmenu.carveBlurLabel); + menu.appendChild(state.ctxmenu.carveThresholdLabel); menu.appendChild(state.ctxmenu.outpaintTypeSelect); menu.appendChild(state.ctxmenu.overMaskPxLabel); menu.appendChild(state.ctxmenu.eagerGenerateCountLabel); @@ -2326,7 +2369,16 @@ const img2imgTool = () => state, "removeBackground", "Remove Identical/BG Pixels", - "icon-slice" + "icon-slice", + () => { + if (state.removeBackground) { + state.ctxmenu.carveBlurLabel.classList.remove("invisible"); + state.ctxmenu.carveThresholdLabel.classList.remove("invisible"); + } else { + state.ctxmenu.carveBlurLabel.classList.add("invisible"); + state.ctxmenu.carveThresholdLabel.classList.add("invisible"); + } + } ).checkbox; // Border Mask Size Slider @@ -2387,6 +2439,34 @@ const img2imgTool = () => state.ctxmenu.instructPix2PixImgCfgLabel.classList.add( "instruct-pix2pix-img-cfg" ); + + // bg carve blur + state.ctxmenu.carveBlurLabel = _toolbar_input.slider( + state, + "carve_blur", + "BG Remove Blur", + { + min: 0, + max: 30, + step: 2, + textStep: 1, + } + ).slider; + state.ctxmenu.carveBlurLabel.classList.add("invisible"); + + // bg carve threshold + state.ctxmenu.carveThresholdLabel = _toolbar_input.slider( + state, + "carve_threshold", + "BG Remove Threshold", + { + min: 0, + max: 255, + step: 5, + textStep: 1, + } + ).slider; + state.ctxmenu.carveThresholdLabel.classList.add("invisible"); } menu.appendChild(state.ctxmenu.cursorSizeSlider); @@ -2400,6 +2480,8 @@ const img2imgTool = () => menu.appendChild(array); menu.appendChild(state.ctxmenu.keepUnmaskedBlurSlider); // menu.appendChild(state.ctxmenu.keepUnmaskedBlurSliderLinebreak); + menu.appendChild(state.ctxmenu.carveBlurLabel); + menu.appendChild(state.ctxmenu.carveThresholdLabel); menu.appendChild(state.ctxmenu.inpaintTypeSelect); menu.appendChild(state.ctxmenu.denoisingStrengthSlider); menu.appendChild(state.ctxmenu.instructPix2PixImgCfgLabel);