Made filters mutually exclusive

This commit is contained in:
Alex Matulich
2025-05-30 16:38:01 -07:00
parent 271bda2aca
commit 4afc72cb22

View File

@@ -10,8 +10,9 @@ Version 8: 26 April 2025 - added file size estimate to output section
Version 9: 20 May 2025 - improved appearance UI, added Sobel edge detection Version 9: 20 May 2025 - improved appearance UI, added Sobel edge detection
Version 10: 21 May 2025 - Added array_name_size value at top of output file Version 10: 21 May 2025 - Added array_name_size value at top of output file
Version 11: 22 May 2025 - Fixed filter artifacts at image edges, added sharpening filter Version 11: 22 May 2025 - Fixed filter artifacts at image edges, added sharpening filter
Version 12: 30 May 2025 - Made filters mutually exclusive
--> -->
<title>Image to OpenSCAD array, v11</title><!-- REMEMBER TO CHANGE VERSION --> <title>Image to OpenSCAD array, v12</title><!-- REMEMBER TO CHANGE VERSION -->
<meta charset="UTF-8"> <meta charset="UTF-8">
<style> <style>
body { font-family: sans-serif; padding-left:1em; padding-right:1em;} body { font-family: sans-serif; padding-left:1em; padding-right:1em;}
@@ -225,11 +226,14 @@ Alpha channel is ignored. After processing the image as desired, you may save it
<label><input type="checkbox" id="invertBrightness"> Invert brightness</label> <label><input type="checkbox" id="invertBrightness"> Invert brightness</label>
</div> </div>
<fieldset style="margin:8px 0;"> <fieldset style="margin:8px 0;">
<legend style="font-size:medium;">Filter cascade</legend> <legend style="font-size:medium;">Filter</legend>
<input type="radio" name="filterSelect" value="blur" checked>
<label for="blurRadius">Gaussian blur radius (pixels):</label> <label for="blurRadius">Gaussian blur radius (pixels):</label>
<input type="number" id="blurRadius" size="5" min="0" max="20" value="0"><br> <input type="number" id="blurRadius" size="5" min="0" max="20" value="0"><br>
<input type="radio" name="filterSelect" value="sharp">
<label for="sharpenRadius">Sharpen radius (pixels): <label for="sharpenRadius">Sharpen radius (pixels):
<input type="number" id="sharpenRadius" size="5" min="0" max="20" value="0"><br> <input type="number" id="sharpenRadius" size="5" min="0" max="20" value="0"><br>
<input type="radio" name="filterSelect" value="edge">
<label for="sobelRadius">Edge detect radius (pixels): <label for="sobelRadius">Edge detect radius (pixels):
<input type="number" id="sobelRadius" size="5" min="0" max="20" value="0"> <input type="number" id="sobelRadius" size="5" min="0" max="20" value="0">
</fieldset> </fieldset>
@@ -294,6 +298,7 @@ Alpha channel is ignored. After processing the image as desired, you may save it
const cropLeft = document.getElementById('cropLeft'); const cropLeft = document.getElementById('cropLeft');
const cropRight = document.getElementById('cropRight'); const cropRight = document.getElementById('cropRight');
const cropBottom = document.getElementById('cropBottom'); const cropBottom = document.getElementById('cropBottom');
const filterSelect = document.getElementById('filterSelect');
const blurRadiusInput = document.getElementById('blurRadius'); const blurRadiusInput = document.getElementById('blurRadius');
const sobelRadiusInput = document.getElementById('sobelRadius'); const sobelRadiusInput = document.getElementById('sobelRadius');
const sharpenRadiusInput = document.getElementById('sharpenRadius'); const sharpenRadiusInput = document.getElementById('sharpenRadius');
@@ -426,11 +431,11 @@ Alpha channel is ignored. After processing the image as desired, you may save it
return convolve1DHorizontal(g1, gKernel); return convolve1DHorizontal(g1, gKernel);
} }
function applySharpen(original, blurMatrix, radius, blurRadius, k) { function applySharpen(original, radius, k=1.0) {
if (radius <= 0) return blurMatrix; if (radius <= 0) return original;
const height = original.length; const height = original.length;
const width = original[0].length; const width = original[0].length;
blurred = blurRadius === 0 ? applyGaussianBlur(original, radius) : blurMatrix; blurred = applyGaussianBlur(original, radius);
const result = []; const result = [];
for (let y = 0; y < height; y++) { for (let y = 0; y < height; y++) {
result[y] = []; result[y] = [];
@@ -441,11 +446,11 @@ Alpha channel is ignored. After processing the image as desired, you may save it
return result; return result;
} }
function applySobel(matrix, sobelRadius, sharpenRadius, blurRadius) { function applySobel(matrix, radius) {
if (sobelRadius <= 0) return matrix; // No edge detection if (radius <= 0) return matrix; // No edge detection
const sobelSize = 2 * sobelRadius + 1; const sobelSize = 2 * radius + 1;
const dKernel = sobelDerivativeKernel(sobelSize); const dKernel = sobelDerivativeKernel(sobelSize);
let gblur = blurRadius === 0 && sharpenRadius === 0 ? applyGaussianBlur(matrix, sobelRadius) : matrix; let gblur = applyGaussianBlur(matrix, radius);
gx = convolve1DHorizontal(gblur, dKernel); gx = convolve1DHorizontal(gblur, dKernel);
gy = convolve1DVertical(gblur, dKernel); gy = convolve1DVertical(gblur, dKernel);
return computeEdgeMagnitude(gx, gy); return computeEdgeMagnitude(gx, gy);
@@ -512,13 +517,29 @@ Alpha channel is ignored. After processing the image as desired, you may save it
brightnessMatrix.push(row); brightnessMatrix.push(row);
} }
// apply filter cascade // apply filter
const blurRadius = parseInt(blurRadiusInput.value) || 0; const blurRadius = parseInt(blurRadiusInput.value) || 0;
const sharpenRadius = parseInt(sharpenRadiusInput.value) || 0; const sharpenRadius = parseInt(sharpenRadiusInput.value) || 0;
const sobelRadius = parseInt(sobelRadiusInput.value) || 0; const sobelRadius = parseInt(sobelRadiusInput.value) || 0;
const blurMatrix = applyGaussianBlur(brightnessMatrix, blurRadius); let filteredMatrix = [];
let filteredMatrix = applySharpen(brightnessMatrix, blurMatrix, sharpenRadius, blurRadius, 1.0); switch(document.querySelector('input[name="filterSelect"]:checked').value) {
filteredMatrix = applySobel(filteredMatrix, sobelRadius, sharpenRadius, blurRadius); // any of the filters return the original if the radius=0
case "blur":
console.log("blur");
filteredMatrix = applyGaussianBlur(brightnessMatrix, blurRadius);
break;
case "sharp":
console.log("sharp");
filteredMatrix = applySharpen(brightnessMatrix, sharpenRadius);
break;
case "edge":
console.log("edge");
filteredMatrix = applySobel(brightnessMatrix, sobelRadius);
break;
default:
console.log("none");
filteredMatrix = brightnessMatrix;
}
// crop the matrix, gather min and max values in crop area // crop the matrix, gather min and max values in crop area
const cropMatrix = []; const cropMatrix = [];
@@ -647,7 +668,10 @@ Alpha channel is ignored. After processing the image as desired, you may save it
// set up event listeners for all the input gadgets // set up event listeners for all the input gadgets
[blurRadiusInput, sobelRadiusInput, sharpenRadiusInput, contrastInput, thresholdInput, [blurRadiusInput, sobelRadiusInput, sharpenRadiusInput, contrastInput, thresholdInput,
...document.querySelectorAll('input[name="grayModel"]')].forEach(el => el.addEventListener('input', processImage)); ...document.querySelectorAll('input[name="grayModel"]'),
...document.querySelectorAll('input[name="filterSelect"]')
].forEach(el => el.addEventListener('input', processImage)
);
resizeWidthInput.addEventListener('input', function () { resizeWidthInput.addEventListener('input', function () {
let min = parseInt(this.min); let min = parseInt(this.min);