mihirmithani
Add Kernel Convolution Visualizer - Phase 1 complete
80bcac8
Raw History Blame
10.2 kB
import { Kernel, KernelCategory, PaddingMode } from '@/types'
export type { KernelCategory } from '@/types'
export const KERNEL_CATEGORIES: { value: KernelCategory; label: string; description: string }[] = [
{ value: 'blur', label: 'Blur', description: 'Smoothing and noise reduction filters' },
{ value: 'sharpen', label: 'Sharpen', description: 'Enhance edges and details' },
{ value: 'edge', label: 'Edge Detection', description: 'Find boundaries and contours' },
{ value: 'emboss', label: 'Emboss', description: '3D relief and depth effects' },
{ value: 'other', label: 'Special Effects', description: 'Creative and artistic filters' },
{ value: 'custom', label: 'Custom', description: 'User-defined kernels' },
]
export const PREDEFINED_KERNELS: Kernel[] = [
// Blur Kernels
{
id: 'box-blur-3x3',
name: 'Box Blur 3×3',
category: 'blur',
matrix: [
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
],
size: 3,
normalize: true,
description: 'Simple averaging blur. Each pixel becomes the average of its 3×3 neighborhood.',
formula: '1/9 × Σ neighborhood',
reference: 'https://en.wikipedia.org/wiki/Box_blur',
},
{
id: 'box-blur-5x5',
name: 'Box Blur 5×5',
category: 'blur',
matrix: [
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
],
size: 5,
normalize: true,
description: 'Larger box blur for stronger smoothing effect.',
formula: '1/25 × Σ neighborhood',
},
{
id: 'gaussian-blur-3x3',
name: 'Gaussian Blur 3×3',
category: 'blur',
matrix: [
[1, 2, 1],
[2, 4, 2],
[1, 2, 1],
],
size: 3,
normalize: true,
description: 'Gaussian-weighted blur. Preserves edges better than box blur while reducing noise.',
formula: '1/16 × G(x,y) where G is Gaussian function',
reference: 'https://en.wikipedia.org/wiki/Gaussian_blur',
},
{
id: 'gaussian-blur-5x5',
name: 'Gaussian Blur 5×5',
category: 'blur',
matrix: [
[1, 4, 6, 4, 1],
[4, 16, 24, 16, 4],
[6, 24, 36, 24, 6],
[4, 16, 24, 16, 4],
[1, 4, 6, 4, 1],
],
size: 5,
normalize: true,
description: 'Larger Gaussian kernel for stronger blur with better frequency response.',
formula: '1/256 × G(x,y) where G is Gaussian function',
},
// Sharpen Kernels
{
id: 'sharpen',
name: 'Sharpen',
category: 'sharpen',
matrix: [
[0, -1, 0],
[-1, 5, -1],
[0, -1, 0],
],
size: 3,
normalize: false,
description: 'Enhances edges by subtracting blurred version from original (unsharp masking).',
formula: '5×center - Σ(neighbors)',
reference: 'https://en.wikipedia.org/wiki/Unsharp_masking',
},
{
id: 'sharpen-strong',
name: 'Strong Sharpen',
category: 'sharpen',
matrix: [
[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1],
],
size: 3,
normalize: false,
description: 'More aggressive sharpening with stronger edge enhancement.',
formula: '9×center - Σ(all neighbors)',
},
{
id: 'unsharp-mask',
name: 'Unsharp Mask 5×5',
category: 'sharpen',
matrix: [
[-1, -4, -6, -4, -1],
[-4, -16, -24, -16, -4],
[-6, -24, 476, -24, -6],
[-4, -16, -24, -16, -4],
[-1, -4, -6, -4, -1],
],
size: 5,
normalize: false,
description: 'Classic unsharp mask: original - blurred. Large kernel for broad edge enhancement.',
formula: 'Original - GaussianBlur(original)',
},
// Edge Detection Kernels
{
id: 'sobel-x',
name: 'Sobel X (Horizontal Edges)',
category: 'edge',
matrix: [
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1],
],
size: 3,
normalize: false,
description: 'Detects vertical edges (horizontal gradients). Highlights left-right transitions.',
formula: 'Gx = ∂I/∂x',
reference: 'https://en.wikipedia.org/wiki/Sobel_operator',
},
{
id: 'sobel-y',
name: 'Sobel Y (Vertical Edges)',
category: 'edge',
matrix: [
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1],
],
size: 3,
normalize: false,
description: 'Detects horizontal edges (vertical gradients). Highlights top-bottom transitions.',
formula: 'Gy = ∂I/∂y',
},
{
id: 'sobel-combined',
name: 'Sobel Combined (Magnitude)',
category: 'edge',
matrix: [
[-1, -2, -1],
[0, 0, 0],
[1, 2, 1],
],
size: 3,
normalize: false,
description: 'Combined Sobel magnitude: √(Gx² + Gy²). Shows all edges regardless of direction.',
formula: '√(Gx² + Gy²)',
},
{
id: 'prewitt-x',
name: 'Prewitt X',
category: 'edge',
matrix: [
[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1],
],
size: 3,
normalize: false,
description: 'Similar to Sobel but with uniform weights. Faster but less noise-resistant.',
formula: 'Gx = ∂I/∂x (uniform weights)',
},
{
id: 'prewitt-y',
name: 'Prewitt Y',
category: 'edge',
matrix: [
[-1, -1, -1],
[0, 0, 0],
[1, 1, 1],
],
size: 3,
normalize: false,
description: 'Prewitt vertical edge detector.',
formula: 'Gy = ∂I/∂y (uniform weights)',
},
{
id: 'roberts-cross',
name: 'Roberts Cross',
category: 'edge',
matrix: [
[1, 0],
[0, -1],
],
size: 2,
normalize: false,
description: 'Simple 2×2 diagonal edge detector. Very fast but noisy.',
formula: 'Diagonal gradient approximation',
},
{
id: 'laplacian',
name: 'Laplacian',
category: 'edge',
matrix: [
[0, 1, 0],
[1, -4, 1],
[0, 1, 0],
],
size: 3,
normalize: false,
description: 'Second derivative operator. Detects edges at zero-crossings. Isotropic (rotation-invariant).',
formula: '∇²I = ∂²I/∂x² + ∂²I/∂y²',
reference: 'https://en.wikipedia.org/wiki/Discrete_Laplacian',
},
{
id: 'laplacian-diagonal',
name: 'Laplacian (with Diagonals)',
category: 'edge',
matrix: [
[1, 1, 1],
[1, -8, 1],
[1, 1, 1],
],
size: 3,
normalize: false,
description: 'Laplacian including diagonal neighbors. More isotropic response.',
formula: '∇²I including diagonals',
},
// Emboss Kernels
{
id: 'emboss',
name: 'Emboss',
category: 'emboss',
matrix: [
[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2],
],
size: 3,
normalize: false,
description: 'Creates 3D relief effect. Light appears to come from top-left.',
formula: 'Directional derivative at 45°',
reference: 'https://en.wikipedia.org/wiki/Embossing_(image_processing)',
},
{
id: 'emboss-strong',
name: 'Strong Emboss',
category: 'emboss',
matrix: [
[-3, -2, -1],
[-2, 0, 2],
[-1, 2, 3],
],
size: 3,
normalize: false,
description: 'More pronounced embossing effect.',
},
{
id: 'emboss-bottom-right',
name: 'Emboss (Bottom-Right Light)',
category: 'emboss',
matrix: [
[2, 1, 0],
[1, 1, -1],
[0, -1, -2],
],
size: 3,
normalize: false,
description: 'Emboss with light source from bottom-right.',
},
// Special Effects
{
id: 'motion-blur',
name: 'Motion Blur (Horizontal)',
category: 'other',
matrix: [
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1],
],
size: 5,
normalize: true,
description: 'Simulates horizontal camera motion. Diagonal line of 1s.',
formula: 'Average along motion direction',
},
{
id: 'motion-blur-vertical',
name: 'Motion Blur (Vertical)',
category: 'other',
matrix: [
[0, 0, 0, 0, 1],
[0, 0, 0, 1, 0],
[0, 0, 1, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
],
size: 5,
normalize: true,
description: 'Simulates vertical camera motion.',
},
{
id: 'outline',
name: 'Outline',
category: 'other',
matrix: [
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1],
],
size: 3,
normalize: false,
description: 'Extracts outlines/edges. Similar to Laplacian but stronger center weight.',
formula: '8×center - Σ(neighbors)',
},
{
id: 'ridge-detection',
name: 'Ridge Detection',
category: 'other',
matrix: [
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1],
],
size: 3,
normalize: false,
description: 'Highlights ridges (bright lines on dark background).',
},
{
id: 'identity',
name: 'Identity (No Change)',
category: 'other',
matrix: [
[0, 0, 0],
[0, 1, 0],
[0, 0, 0],
],
size: 3,
normalize: false,
description: 'Returns the original image unchanged. Useful as baseline.',
formula: 'I\' = I',
},
]
export function getKernelById(id: string): Kernel | undefined {
return PREDEFINED_KERNELS.find((k) => k.id === id)
}
export function getKernelsByCategory(category: KernelCategory): Kernel[] {
return PREDEFINED_KERNELS.filter((k) => k.category === category)
}
export function normalizeKernel(matrix: number[][]): number[][] {
const sum = matrix.flat().reduce((a, b) => a + b, 0)
if (sum === 0) return matrix
return matrix.map((row) => row.map((val) => val / sum))
}
export function createCustomKernel(
name: string,
matrix: number[][],
normalize: boolean,
category: KernelCategory = 'custom',
description = 'Custom user-defined kernel'
): Kernel {
return {
id: `custom-${Date.now()}`,
name,
category,
matrix,
size: matrix.length,
normalize,
description,
}
}
export const PADDING_MODES: { value: PaddingMode; label: string; description: string }[] = [
{ value: 'zero', label: 'Zero Padding', description: 'Fill outside with zeros (black)' },
{ value: 'reflect', label: 'Reflect Padding', description: 'Mirror the image at boundaries' },
{ value: 'replicate', label: 'Replicate Padding', description: 'Repeat edge pixels outward' },
{ value: 'wrap', label: 'Wrap Padding', description: 'Tile the image (torus topology)' },
]