mirror of
https://github.com/mschuepbach/matrix-kernel-filter-calculator.git
synced 2026-01-15 21:12:14 +01:00
189 lines
5.0 KiB
Svelte
189 lines
5.0 KiB
Svelte
<script>
|
|
import ThemeWrapper from "./../node_modules/svelte-themer/components/ThemeWrapper.svelte";
|
|
import Matrix from "./Matrix.svelte";
|
|
import MatrixSizeInput from "./MatrixSizeInput.svelte";
|
|
import { themes } from "./themes";
|
|
import ThemeToggle from "./ThemeToggle.svelte";
|
|
|
|
let matrixWidth = 4;
|
|
let matrixHeight = 4;
|
|
let kernelWidth = 3;
|
|
let kernelHeight = 3;
|
|
let padding = 0;
|
|
let addPadding = true;
|
|
|
|
$: matrix = initMatrix(matrixWidth, matrixHeight, 1);
|
|
$: kernel = initMatrix(kernelWidth, kernelHeight, 1);
|
|
$: result = applyKernelFilter(matrix, kernel, addPadding, padding);
|
|
|
|
function initMatrix(width, height, value) {
|
|
return width > 0 && height > 0
|
|
? Array(Math.floor(height))
|
|
.fill(value)
|
|
.map(() => Array(Math.floor(width)).fill(value))
|
|
: [[]];
|
|
}
|
|
|
|
function applyKernelFilter(matrix, kernel, addPadding, padding = 0) {
|
|
let kernelHeight = kernel.length;
|
|
let kernelWidth = kernel[0].length;
|
|
let matrixHeight = matrix.length;
|
|
let matrixWidth = matrix[0].length;
|
|
let result = initMatrix(matrixWidth, matrixHeight, 0);
|
|
let kernelCenterX = Math.floor(kernelWidth / 2);
|
|
let kernelCenterY = Math.floor(kernelHeight / 2);
|
|
|
|
for (let i = 0; i < matrixHeight; i++) {
|
|
for (let j = 0; j < matrixWidth; j++) {
|
|
for (let m = 0; m < kernelHeight; m++) {
|
|
for (let n = 0; n < kernelWidth; n++) {
|
|
let ii = i + (m - kernelCenterY);
|
|
let jj = j + (n - kernelCenterX);
|
|
if (ii >= 0 && ii < matrixHeight && jj >= 0 && jj < matrixWidth) {
|
|
result[i][j] += matrix[ii][jj] * kernel[m][n];
|
|
} else {
|
|
result[i][j] += padding * kernel[m][n];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!addPadding && kernelCenterX > 0 && kernelCenterY > 0)
|
|
result =
|
|
kernelHeight >= matrixHeight || kernelWidth >= matrixWidth
|
|
? [[]]
|
|
: result
|
|
.slice(kernelCenterY, -kernelCenterY)
|
|
.map((r) => r.slice(kernelCenterX, -kernelCenterX));
|
|
|
|
return result;
|
|
}
|
|
</script>
|
|
|
|
<ThemeWrapper {themes} key="kernel-filter-calculator__theme">
|
|
<div class="container">
|
|
<header><h1>Matrix Kernel Filter Calculator</h1></header>
|
|
<main>
|
|
<h5 style="grid-area: matrix-title">Matrix</h5>
|
|
<h5 style="grid-area: kernel-title">Kernel</h5>
|
|
<h5 style="grid-area: result-title">Result</h5>
|
|
<div style="grid-area: matrix-size">
|
|
<MatrixSizeInput bind:matrixWidth bind:matrixHeight />
|
|
</div>
|
|
<div style="grid-area: kernel-size">
|
|
<MatrixSizeInput
|
|
bind:matrixWidth={kernelWidth}
|
|
bind:matrixHeight={kernelHeight}
|
|
/>
|
|
</div>
|
|
<div style="grid-area: result-size">
|
|
{result[0].length}x{result.length}
|
|
</div>
|
|
<div style="grid-area: matrix"><Matrix bind:matrix /></div>
|
|
<div style="grid-area: kernel"><Matrix bind:matrix={kernel} /></div>
|
|
<div style="grid-area: result">
|
|
<Matrix matrix={result} readonly="true" />
|
|
</div>
|
|
<div style="grid-area: padding">
|
|
<label>
|
|
<input type="checkbox" bind:checked={addPadding} />
|
|
Padding
|
|
</label>
|
|
<div>
|
|
<input
|
|
type="number"
|
|
bind:value={padding}
|
|
style="width: 3em;"
|
|
onclick="select()"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<footer>
|
|
<div class="left"><ThemeToggle /></div>
|
|
<div class="center">
|
|
<a
|
|
href="https://github.com/mschuepbach/matrix-kernel-filter-calculator"
|
|
target="_blank"
|
|
title="GitHub Repository"
|
|
>
|
|
<img src="./GitHub-Mark.svg" alt="GitHub Repository" width="32px" />
|
|
</a>
|
|
</div>
|
|
<div class="right" />
|
|
</footer>
|
|
</div>
|
|
</ThemeWrapper>
|
|
|
|
<style>
|
|
:global(html) {
|
|
background-color: var(--theme-colors-background, initial);
|
|
color: var(--theme-colors-text, initial);
|
|
}
|
|
|
|
:global(input) {
|
|
color: var(--theme-colors-text, initial);
|
|
border-color: var(--theme-colors-input-border, initial);
|
|
background-color: var(--theme-colors-input-background, initial);
|
|
}
|
|
|
|
:global(button) {
|
|
color: var(--theme-colors-text, initial);
|
|
}
|
|
|
|
h5 {
|
|
margin: 1em 0 0;
|
|
}
|
|
|
|
.container {
|
|
text-align: center;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
header {
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
main {
|
|
display: grid;
|
|
margin-bottom: auto;
|
|
grid-template-areas:
|
|
"matrix-title kernel-title result-title"
|
|
"matrix-size kernel-size result-size"
|
|
"matrix kernel result"
|
|
"padding padding padding";
|
|
grid-gap: 0.8em;
|
|
align-items: center;
|
|
}
|
|
|
|
@media (max-width: 960px) {
|
|
main {
|
|
grid-template-areas:
|
|
"matrix-title"
|
|
"matrix-size"
|
|
"matrix"
|
|
"kernel-title"
|
|
"kernel-size"
|
|
"kernel"
|
|
"result-title"
|
|
"result-size"
|
|
"result"
|
|
"padding";
|
|
}
|
|
}
|
|
|
|
footer {
|
|
display: flex;
|
|
margin-top: 1em;
|
|
text-align: left;
|
|
}
|
|
|
|
.left,
|
|
.right {
|
|
flex: 1;
|
|
}
|
|
</style>
|