Let's create a comprehensive system that combines mathematical theory with practical implementation. This system will allow us to design, test, and apply custom filters based on linear algebra principles.
class AdvancedFilterSystem:
def __init__(self):
self.filter_history = []
self.kernel_library = {}
def add_kernel_to_library(self, name, kernel, description=""):
"""Add custom kernel to library"""
self.kernel_library[name] = {
'kernel': kernel,
'description': description,
'properties': self._analyze_kernel(kernel)
}
def _analyze_kernel(self, kernel):
"""Analyze kernel properties"""
properties = {
'size': kernel.shape,
'sum': np.sum(kernel),
'mean': np.mean(kernel),
'std': np.std(kernel),
'range': (np.min(kernel), np.max(kernel)),
'center_value': kernel[kernel.shape[0]//2, kernel.shape[1]//2],
'is_separable': self._check_separability(kernel)
}
return properties
def _check_separability(self, kernel):
"""Check if kernel is separable (can be decomposed into 1D kernels)"""
try:
U, s, Vt = np.linalg.svd(kernel)
# If rank is 1, kernel is separable
rank = np.sum(s > 1e-10)
return rank == 1
except:
return False
def create_edge_detection_family(self):
"""Create family of edge detection kernels"""
edge_kernels = {
'Sobel_X': np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]]),
'Sobel_Y': np.array([[-1, -2, -1],
[ 0, 0, 0],
[ 1, 2, 1]]),
'Laplacian': np.array([[ 0, -1, 0],
[-1, 4, -1],
[ 0, -1, 0]]),
'Laplacian_8': np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]]),
'Prewitt_X': np.array([[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]]),
'Prewitt_Y': np.array([[-1, -1, -1],
[ 0, 0, 0],
[ 1, 1, 1]])
}
for name, kernel in edge_kernels.items():
self.add_kernel_to_library(name, kernel, "Edge detection kernel")
return edge_kernels
def apply_filter_combination(self, image, filter_sequence):
"""Apply sequence of filters"""
result = image.copy()
for filter_name, params in filter_sequence:
if filter_name in self.kernel_library:
kernel = self.kernel_library[filter_name]['kernel']
result = cv2.filter2D(result, -1, kernel)
elif filter_name == 'gaussian_blur':
ksize = params.get('ksize', 5)
sigma = params.get('sigma', 1)
result = cv2.GaussianBlur(result, (ksize, ksize), sigma)
elif filter_name == 'threshold':
thresh_val = params.get('thresh', 127)
_, result = cv2.threshold(result, thresh_val, 255, cv2.THRESH_BINARY)
# Record in history
self.filter_history.append({
'filter': filter_name,
'params': params,
'image_stats': {
'mean': np.mean(result),
'std': np.std(result),
'min': np.min(result),
'max': np.max(result)
}
})
return result
def design_custom_kernel_interactive(self, target_effect):
"""Design kernel based on desired effect"""
if target_effect == "sharpen":
# Create sharpening kernel
base = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]])
return base
elif target_effect == "blur":
# Create averaging kernel
size = 5
kernel = np.ones((size, size)) / (size * size)
return kernel
elif target_effect == "edge_enhance":
# Combine edge detection with original
edge = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]])
identity = np.array([[0, 0, 0],
[0, 1, 0],
[0, 0, 0]])
return 0.5 * identity + 0.5 * edge
def demonstrate_complete_system(self):
"""Comprehensive demonstration"""
# Create test image
img = np.zeros((200, 200), dtype=np.uint8)
cv2.rectangle(img, (50, 50), (150, 150), 255, -1)
cv2.circle(img, (75, 75), 20, 128, -1)
cv2.circle(img, (125, 125), 15, 64, -1)
# Add edge detection kernels
edge_kernels = self.create_edge_detection_family()
# Create custom kernels
custom_kernels = {
'Custom_Sharpen': self.design_custom_kernel_interactive("sharpen"),
'Custom_Blur': self.design_custom_kernel_interactive("blur"),
'Edge_Enhance': self.design_custom_kernel_interactive("edge_enhance")
}
for name, kernel in custom_kernels.items():
self.add_kernel_to_library(name, kernel, f"Custom {name}")
# Demonstrate filter combinations
filter_sequences = [
[('Custom_Blur', {}), ('Custom_Sharpen', {})],
[('Sobel_X', {}), ('threshold', {'thresh': 50})],
[('gaussian_blur', {'ksize': 5, 'sigma': 1}), ('Laplacian', {})]
]
plt.figure(figsize=(20, 15))
# Original
plt.subplot(4, 5, 1)
plt.imshow(img, cmap='gray')
plt.title('Original')
plt.axis('off')
# Individual kernels
all_kernels = {**edge_kernels, **custom_kernels}
for i, (name, kernel) in enumerate(list(all_kernels.items())[:8]):
result = cv2.filter2D(img, -1, kernel)
plt.subplot(4, 5, i + 2)
plt.imshow(result, cmap='gray')
plt.title(name)
plt.axis('off')
# Filter sequences
for i, sequence in enumerate(filter_sequences):
result = self.apply_filter_combination(img, sequence)
plt.subplot(4, 5, 11 + i)
plt.imshow(result, cmap='gray')
seq_name = ' → '.join([f[0] for f in sequence])
plt.title(f'Sequence {i+1}\n{seq_name}')
plt.axis('off')
# Kernel analysis
plt.subplot(4, 5, 15)
kernel_names = list(self.kernel_library.keys())[:5]
sums = [self.kernel_library[name]['properties']['sum'] for name in kernel_names]
plt.bar(range(len(kernel_names)), sums)
plt.xticks(range(len(kernel_names)), kernel_names, rotation=45)
plt.title('Kernel Sum Analysis')
plt.ylabel('Sum of Elements')
plt.tight_layout()
plt.show()
# Print library summary
print("\nKernel Library Summary:")
print("-" * 50)
for name, info in self.kernel_library.items():
props = info['properties']
print(f"{name}:")
print(f" Size: {props['size']}")
print(f" Sum: {props['sum']:.4f}")
print(f" Separable: {props['is_separable']}")
print(f" Description: {info['description']}")
print()
# Usage
filter_system = AdvancedFilterSystem()
filter_system.demonstrate_complete_system()