File size: 5,218 Bytes
b96b3a8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
import React, { useEffect, useState } from 'react';
import PanelContainer from '../ui/PanelContainer';
import GlowingBox from '../ui/GlowingBox';
import FeatureMap from '../ui/FeatureMap';
import { ScanSearch, MoveRight } from 'lucide-react';
const ConvolutionPanel: React.FC = () => {
const [kernelPosition, setKernelPosition] = useState({ x: 0, y: 0 });
const [isAnimating, setIsAnimating] = useState(true);
// Simple edge detection kernel
const kernel = [
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]
];
// Animation for sliding kernel
useEffect(() => {
if (!isAnimating) return;
const maxPos = 5; // 8x8 input - 3x3 kernel + 1
const interval = setInterval(() => {
setKernelPosition(prev => {
const newX = prev.x + 1 > maxPos ? 0 : prev.x + 1;
const newY = newX === 0 ? (prev.y + 1 > maxPos ? 0 : prev.y + 1) : prev.y;
return { x: newX, y: newY };
});
}, 800);
return () => clearInterval(interval);
}, [isAnimating]);
return (
<PanelContainer
title="Convolution Operation"
description="The convolution operation slides a filter (kernel) across the input image to detect features like edges, textures, or patterns."
panelNumber={2}
>
<div className="flex flex-col lg:flex-row gap-8 items-center">
<div className="flex-1 flex flex-col items-center">
<h3 className="text-xl font-semibold text-gray-100 mb-4">Kernel Sliding</h3>
<div className="relative">
{/* Input image with overlay */}
<div className="grid grid-cols-8 grid-rows-8 w-full max-w-[280px] gap-[1px]">
{Array(64).fill(0).map((_, index) => {
const x = index % 8;
const y = Math.floor(index / 8);
// Determine if cell is within the current kernel position
const isInKernel = x >= kernelPosition.x && x < kernelPosition.x + 3 &&
y >= kernelPosition.y && y < kernelPosition.y + 3;
return (
<div
key={index}
className={`
aspect-square flex items-center justify-center
${isInKernel
? 'bg-purple-600/30 border border-purple-400'
: 'bg-gray-800 border border-gray-700'}
`}
></div>
);
})}
</div>
{/* Animated kernel */}
<div
className="absolute w-[calc(37.5%)] h-[calc(37.5%)] border-2 border-cyan-400 rounded-md shadow-lg shadow-cyan-500/50 transition-all duration-300 pointer-events-none"
style={{
top: `${kernelPosition.y * 12.5}%`,
left: `${kernelPosition.x * 12.5}%`
}}
>
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-cyan-400">
<ScanSearch size={24} />
</div>
</div>
</div>
<button
className="mt-4 px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-md text-sm"
onClick={() => setIsAnimating(!isAnimating)}
>
{isAnimating ? 'Pause Animation' : 'Resume Animation'}
</button>
</div>
<div className="hidden lg:flex items-center justify-center">
<MoveRight size={40} className="text-gray-500" />
</div>
<div className="flex-1 flex flex-col items-center">
<div className="flex gap-8 items-start">
<div>
<h3 className="text-xl font-semibold text-gray-100 mb-4">Kernel/Filter</h3>
<GlowingBox color="from-purple-500 to-blue-500" className="max-w-[150px]">
<div className="grid grid-cols-3 gap-1">
{kernel.flat().map((value, i) => (
<div
key={i}
className="aspect-square flex items-center justify-center bg-gray-900 text-sm font-mono"
>
{value}
</div>
))}
</div>
</GlowingBox>
<p className="mt-2 text-sm text-gray-400 max-w-[150px]">Edge detection filter</p>
</div>
<div>
<h3 className="text-xl font-semibold text-gray-100 mb-4">Feature Map</h3>
<GlowingBox color="from-blue-500 to-teal-500" className="max-w-[200px]">
<FeatureMap
size={6}
highlightPosition={kernelPosition.x < 6 && kernelPosition.y < 6 ?
{ x: kernelPosition.x, y: kernelPosition.y } : null}
/>
</GlowingBox>
<p className="mt-2 text-sm text-gray-400 max-w-[200px]">
Resulting feature map from convolution operation
</p>
</div>
</div>
</div>
</div>
</PanelContainer>
);
};
export default ConvolutionPanel; |