mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-08-10 00:36:39 +02:00
Made filters mutually exclusive
This commit is contained in:
@@ -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);
|
||||||
|
Reference in New Issue
Block a user