This commit is contained in:
William Henderson
2025-07-23 12:17:28 +01:00
commit f7f598c599
143 changed files with 1706 additions and 0 deletions
+237
View File
@@ -0,0 +1,237 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Knee Function Adjustment</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
}
.container {
display: flex;
flex-direction: row;
gap: 20px;
margin: 20px 0;
width: 100%;
justify-content: center;
}
canvas {
max-width: 100%;
height: auto;
}
.slider-container {
display: flex;
flex-direction: column;
gap: 15px;
margin: 20px;
}
.slider {
display: flex;
flex-direction: column;
align-items: center;
}
.slider input {
width: 200px;
}
.image-wrapper {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.image-wrapper canvas {
width: 100%;
height: auto;
}
.file-input {
margin: 20px;
}
</style>
</head>
<body>
<h1>Knee Function Adjustment</h1>
<div class="file-input">
<label for="fileInput">Choose an image:</label>
<input type="file" id="fileInput" accept="image/*">
</div>
<div class="container">
<div class="image-wrapper">
<h3>Original Image</h3>
<canvas id="originalCanvas"></canvas>
<p id="originalGrayLabel">Avg Gray: 0.00</p>
</div>
<div class="image-wrapper">
<h3>Processed Image</h3>
<canvas id="processedCanvas"></canvas>
<p id="processedGrayLabel">Avg Gray: 0.00</p>
</div>
</div>
<div class="slider-container">
<div class="slider">
<label for="sensorOutput1">Sensor Output Shadow</label>
<input type="range" id="sensorOutput1" min="0" max="255" value="25">
</div>
<div class="slider">
<label for="mappedOutput1">Mapped Output Shadow</label>
<input type="range" id="mappedOutput1" min="0" max="255" value="50">
</div>
<div class="slider">
<label for="sensorOutput2">Sensor Output Bright</label>
<input type="range" id="sensorOutput2" min="0" max="255" value="200">
</div>
<div class="slider">
<label for="mappedOutput2">Mapped Output Bright</label>
<input type="range" id="mappedOutput2" min="0" max="255" value="200">
</div>
</div>
<h3>Knee Function Graph</h3>
<canvas id="kneeGraph"></canvas>
<script>
const originalCanvas = document.getElementById('originalCanvas');
const processedCanvas = document.getElementById('processedCanvas');
const kneeGraph = document.getElementById('kneeGraph');
const originalGrayLabel = document.getElementById('originalGrayLabel');
const processedGrayLabel = document.getElementById('processedGrayLabel');
const sensorOutput1 = document.getElementById('sensorOutput1');
const mappedOutput1 = document.getElementById('mappedOutput1');
const sensorOutput2 = document.getElementById('sensorOutput2');
const mappedOutput2 = document.getElementById('mappedOutput2');
const fileInput = document.getElementById('fileInput');
let imageArray = null;
function drawImage(canvas, imageArray, imgWidth, imgHeight) {
const ctx = canvas.getContext('2d');
// Set the canvas size according to the image aspect ratio
const aspectRatio = imgWidth / imgHeight;
const canvasWidth = 500; // Set the desired width for the canvas
const canvasHeight = canvasWidth / aspectRatio;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
const imageData = ctx.createImageData(canvasWidth, canvasHeight);
for (let i = 0; i < imageArray.length; i++) {
imageData.data[i * 4] = imageData.data[i * 4 + 1] = imageData.data[i * 4 + 2] = imageArray[i];
imageData.data[i * 4 + 3] = 255; // Alpha channel
}
ctx.putImageData(imageData, 0, 0);
}
function applyKnee(imageArray, kneeLevel, kneeSlope) {
return imageArray.map(value =>
value > kneeLevel ? kneeLevel + (value - kneeLevel) * kneeSlope : value
);
}
function calculateAverageGray(imageArray) {
return (imageArray.reduce((sum, value) => sum + value, 0) / imageArray.length).toFixed(2);
}
function update() {
if (!imageArray) return;
const sensor1 = parseInt(sensorOutput1.value);
const map1 = parseInt(mappedOutput1.value);
const sensor2 = parseInt(sensorOutput2.value);
const map2 = parseInt(mappedOutput2.value);
const kneeLevel = map1;
const kneeSlope = sensor2 === sensor1 ? 0 : (map2 - map1) / (sensor2 - sensor1);
const processedArray = applyKnee(imageArray, kneeLevel, kneeSlope);
drawImage(originalCanvas, imageArray, 256, 256); // Adjust this to the actual image size
drawImage(processedCanvas, processedArray, 256, 256); // Adjust this to the actual image size
originalGrayLabel.textContent = `Avg Gray: ${calculateAverageGray(imageArray)}`;
processedGrayLabel.textContent = `Avg Gray: ${calculateAverageGray(processedArray)}`;
updateKneeGraph(kneeLevel, kneeSlope);
}
function updateKneeGraph(kneeLevel, kneeSlope) {
const x = Array.from({ length: 256 }, (_, i) => i);
const y = x.map(value =>
value > kneeLevel ? kneeLevel + (value - kneeLevel) * kneeSlope : value
);
const ctx = kneeGraph.getContext('2d');
kneeGraph.width = 512;
kneeGraph.height = 256;
ctx.clearRect(0, 0, kneeGraph.width, kneeGraph.height);
ctx.beginPath();
ctx.moveTo(0, 256);
x.forEach((value, i) => {
ctx.lineTo(value * 2, 256 - y[i]);
});
ctx.strokeStyle = 'blue';
ctx.lineWidth = 2;
ctx.stroke();
}
function loadImage(file) {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, img.width, img.height);
imageArray = new Uint8Array(img.width * img.height);
for (let i = 0; i < imageArray.length; i++) {
imageArray[i] = imageData.data[i * 4]; // Grayscale from red channel
}
// Draw original and processed images with aspect ratio
drawImage(originalCanvas, imageArray, img.width, img.height);
drawImage(processedCanvas, imageArray, img.width, img.height);
update();
};
img.src = URL.createObjectURL(file);
}
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
loadImage(file);
}
});
[sensorOutput1, mappedOutput1, sensorOutput2, mappedOutput2].forEach(slider => {
slider.addEventListener('input', update);
});
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB