| 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); |
| |
| |
| const kernel = [ |
| [-1, -1, -1], |
| [-1, 8, -1], |
| [-1, -1, -1] |
| ]; |
| |
| |
| useEffect(() => { |
| if (!isAnimating) return; |
| |
| const maxPos = 5; |
| 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; |