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;