Eigen3矩阵缩放实现:类似OpenCV cv::resize的插值缩放方法
Great question! Unlike OpenCV which has a ready-to-use cv::resize function for image scaling, Eigen3 doesn't include an out-of-the-box equivalent for its core Matrix type. However, you can easily implement interpolation-based scaling yourself, or use Eigen's Tensor module if you're working with image-like data. Here are two reliable approaches:
1. Manual Bilinear Interpolation (For Core Eigen Matrix Types)
Bilinear interpolation is a common choice for smooth scaling, and works well for any scaling factor (not just integer multiples like 2x). Here's a complete implementation:
#include <Eigen/Dense> #include <cmath> #include <algorithm> Eigen::MatrixXd scaleMatrix(const Eigen::MatrixXd& input, double scale) { const int inputRows = input.rows(); const int inputCols = input.cols(); const int outputRows = static_cast<int>(inputRows * scale); const int outputCols = static_cast<int>(inputCols * scale); Eigen::MatrixXd output(outputRows, outputCols); for (int y = 0; y < outputRows; ++y) { for (int x = 0; x < outputCols; ++x) { // Map target pixel to original matrix coordinates const double srcY = y / scale; const double srcX = x / scale; // Get surrounding integer coordinates (clamped to avoid out-of-bounds) const int y0 = static_cast<int>(std::floor(srcY)); const int y1 = std::min(y0 + 1, inputRows - 1); const int x0 = static_cast<int>(std::floor(srcX)); const int x1 = std::min(x0 + 1, inputCols - 1); // Calculate fractional offsets const double dy = srcY - y0; const double dx = srcX - x0; // Bilinear interpolation formula const double interpolatedValue = (1.0 - dx) * (1.0 - dy) * input(y0, x0) + dx * (1.0 - dy) * input(y0, x1) + (1.0 - dx) * dy * input(y1, x0) + dx * dy * input(y1, x1); output(y, x) = interpolatedValue; } } return output; } // Usage Example int main() { // Create a 1000x1000 random matrix Eigen::MatrixXd originalMatrix = Eigen::MatrixXd::Random(1000, 1000); // Scale to 2000x2000 (scale factor = 2.0) Eigen::MatrixXd scaledMatrix = scaleMatrix(originalMatrix, 2.0); return 0; }
Key Notes:
- Boundary Handling: We use
std::minto clamp coordinates to the original matrix's bounds, preventing out-of-bounds access. - Flexibility: This works for any positive scale factor (e.g., 0.5x for downscaling, 3.2x for arbitrary upscaling).
- Performance: For large matrices, you might want to optimize this with vectorization (Eigen's auto-vectorization can help if you compile with optimizations enabled).
2. Using Eigen's Tensor Module (For Image/Tensor Data)
If you're working with data that's naturally tensor-like (like images), Eigen's Tensor module provides built-in interpolation utilities. This is cleaner if you can enable the Tensor module in your Eigen build:
#include <Eigen/Tensor> using namespace Eigen; // Scale a 2D tensor with bilinear interpolation Tensor<double, 2> scaleTensor(const Tensor<double, 2>& input, double scale) { const int inputRows = input.dimension(0); const int inputCols = input.dimension(1); const int outputRows = static_cast<int>(inputRows * scale); const int outputCols = static_cast<int>(inputCols * scale); // Define resizing operation with linear (bilinear) interpolation TensorResizingOp<InterpolateOp<LinearInterpolator<double>>, Tensor<double, 2>> resizer( input, InterpolateOp<LinearInterpolator<double>>( {outputRows, outputCols}, // Target dimensions {inputRows, inputCols} // Original dimensions ) ); // Evaluate and return the scaled tensor return resizer.eval(); } // Usage Example int main() { // Create a 1000x1000 random tensor Tensor<double, 2> originalTensor(1000, 1000); originalTensor.setRandom(); // Scale to 2000x2000 Tensor<double, 2> scaledTensor = scaleTensor(originalTensor, 2.0); return 0; }
Key Notes:
- Interpolation Options: Replace
LinearInterpolatorwithNearestInterpolatorif you want nearest-neighbor scaling (faster but less smooth). - Build Requirements: Ensure your Eigen library is compiled with the Tensor module enabled (most pre-built packages include this by default, but double-check your build configuration).
内容的提问来源于stack exchange,提问作者Vicente Bosch

