Covariance Matrix from Image Patches
Compute the covariance matrix of image patches for PCA-based texture analysis.
Given an image and patch size, extract all overlapping patches, flatten them to vectors, and compute the covariance matrix. This is a fundamental step in texture analysis and eigenface computation.
Algorithm:
- Extract all overlapping patches of size pΓp from the image
- Flatten each patch into a vector of length p2
- Stack vectors as rows of data matrix X (shape: n_patches Γ pΒ²)
- Center the data: Xcβ=XβXΛ (subtract mean vector)
- Compute covariance: Ξ£=nβ11βXcTβXcβ
The covariance matrix Ξ£ captures correlations between pixel positions within patches.
Applications:
- PCA for dimensionality reduction
- Eigenface/Fisherface recognition
- Texture synthesis and analysis
Example:
image = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
patch_size = 2[[2.5, 2.5, 2.5, 2.5], [2.5, 2.5, 2.5, 2.5], [2.5, 2.5, 2.5, 2.5], [2.5, 2.5, 2.5, 2.5]]
Step 1: Extract 2Γ2 patches From 3Γ3 image, we get 4 overlapping patches:
- Patch 1 (top-left): [[1,2],[4,5]] β flattened: [1,2,4,5]
- Patch 2 (top-right): [[2,3],[5,6]] β flattened: [2,3,5,6]
- Patch 3 (bottom-left): [[4,5],[7,8]] β flattened: [4,5,7,8]
- Patch 4 (bottom-right): [[5,6],[8,9]] β flattened: [5,6,8,9]
Step 2: Create data matrix X (4Γ4) X=β1245β2356β4578β5689ββ
Step 3: Compute mean and center Mean vector: [3, 4, 6, 7] Xcβ=Xβmean
Step 4: Compute covariance Ξ£=31βXcTβXcβ
All entries are 2.5 due to the regular structure of this simple example.
Constraints:
- image: 2D numpy array (grayscale)
- patch_size: integer p (patches are pΓp)
- Return: covariance matrix of shape (pΒ², pΒ²)
- Round to 4 decimal places
Background Knowledge
Covariance matrices are fundamental statistical tools that capture the linear relationships between variables in a dataset. In the context of image patches, each pixel position within a patch is treated as a variable, and the covariance matrix reveals which pixel positions tend to vary together. When you flatten a patch into a vector, you're converting spatial information into a feature space where the covariance matrix becomes a symmetric, positive semi-definite matrix of shape p2Γp2.
Principal Component Analysis (PCA) relies on diagonalizing the covariance matrix to identify the directions of maximum variance in your data. For image patches, this means finding the most important patterns or textures that explain variation across your dataset. The eigenvectors of the covariance matrix form an orthonormal basis, and the eigenvalues tell you how much variance is explained along each direction. This is why computing the covariance matrix accurately is criticalβit directly determines which features PCA will extract.
Centering the data is essential because the covariance matrix measures deviations from the mean. Without centering, you're computing a second moment rather than a true covariance, which would incorrectly include information about the mean intensity of patches rather than their internal structure. The factor of nβ11β (Bessel's correction) provides an unbiased estimate when working with sample data rather than an entire population.
Algorithm/Approach
The solution follows a data preprocessing pipeline common in machine learning:
- Spatial extraction: Slide a pΓp window across the image with stride 1 to capture all overlapping patches
- Vectorization: Convert 2D patches to 1D vectors to create a data matrix where each row is a flattened patch
- Normalization: Center the data by subtracting the mean vector computed across all patches
- Covariance computation: Apply the mathematical formula Ξ£=\frac{1}{n-1}XcTβXcβ to obtain the final matrix
This approach is widely used in texture analysis and face recognition systems, where local patch statistics reveal meaningful patterns.
Step-by-Step Strategy
Step 1: Extract Overlapping Patches
- Iterate through the image with a sliding window of size pΓp
- For an image of size HΓW, you'll have (Hβp+1)Γ(Wβp+1) patches
- Store each patch as a separate entity (you can use a list or pre-allocate an array)
Step 2: Flatten and Stack into Data Matrix
- Convert each pΓp patch into a 1D vector of length p2
- Stack all vectors as rows in a matrix X of shape n\text{ patches}Γp2
- Ensure you're working with floating-point data types to avoid precision loss
Step 3: Compute the Mean Vector
- Calculate XΛ as the mean of each column (across all patches)
- This represents the "average pixel value" at each position within patches
Step 4: Center the Data
- Subtract the mean vector from every row: Xcβ=XβXΛ
- This ensures the covariance captures variance, not absolute intensity
Step 5: Compute Covariance Matrix
- Use matrix multiplication: Ξ£=\frac{1}{n-1}XcTβXcβ
- The result is a p2Γp2 symmetric matrix
- Verify symmetry as a sanity check (numerical errors may cause small asymmetries)
Common Pitfalls
- Forgetting to center: Computing XTX without centering gives incorrect results that conflate mean and variance
- Off-by-one errors in patch extraction: Ensure your loop bounds correctly capture all overlapping patches without duplicates or gaps
- Data type issues: Using integer types for pixel values can cause overflow or precision loss; convert to float early
- Memory efficiency: For large images and small patch sizes, the number of patches can be enormous. Consider whether you need to store all patches or can compute statistics incrementally
- Normalization factor confusion: Remember it's nβ11β for sample covariance (unbiased), not n1β (which is biased)
- Matrix dimension mismatch: Verify that Xcβ has shape nΓp2 before computing XcTβXcβ, which should yield p2Γp2
Time & Space Complexity
Time Complexity:
- Patch extraction: O((Hβp+1)(Wβp+1)β p2) to extract and flatten all patches
- Centering: O(nβ p2) where n=(Hβp+1)(Wβp+1)
- Covariance computation: O(nβ p4) for the matrix multiplication XcTβXcβ
- Overall: O(nβ p4) where the dominant cost is the matrix multiplication
Space Complexity:
- Data matrix X: O(nβ p2)
- Covariance matrix Ξ£: O(p4)
- Overall: O(nβ p2+p4)
For typical values (e.g., p=8, image 256Γ256), this is manageable, but for larger patches or images, memory becomes a constraint. Some implementations use incremental covariance computation to reduce memory usage.