Files
matrix-kernel-filter-calcul…/src/App.svelte
2022-02-04 15:28:23 +01:00

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>