Я хочу выполнить свертку образа и ядра. Оба являются собственными матрицами динамического размера со значениями 2001x2001. Я знаю, что моя матрица ядра очень разрежена и содержит ~ 350 ненулевых значений.
Итак, я создал эту функцию с помощью sparseView () матрицы ядра и проверил ее правильность. Идея состоит в том, чтобы перебирать только ненулевые значения моего ядра при выполнении шагов умножения свертки.
Тем не менее, в сценарии, указанном выше, время выполнения этой функции составляет в среднем около 16 секунд на моей машине, даже несмотря на то, что нужно выполнить «только» 1 401 400 350 операций. Используя тот же вход, MATLAB может выполнить свертку с conv2 примерно за 2 секунды. Это просто экстремальная оптимизация в MATLABS или я что-то упустил? (Разделение ядра невозможно)
Matrix<double, Dynamic, Dynamic> halfSparseConvolution(const Matrix<double, Dynamic, Dynamic> &image, const SparseMatrix<double> &kernel) {
assert(kernel.rows() % 2 == 1 && kernel.cols() % 2 == 1);
Matrix<double, Dynamic, Dynamic> image_out = Matrix<double, Dynamic, Dynamic>(image.cols(), image.rows());
int kernelColsHalf = kernel.cols() / 2;
int kernelRowsHalf = kernel.rows() / 2;
for (int i = 0; i < image.rows(); ++i) {
for (int j = 0; j < image.cols(); ++j) {
double sum = 0;
for (int k = 0; k < kernel.outerSize(); ++k) {
if (j + kernelColsHalf - k < 0 || j + kernelColsHalf - k >= image.cols())//Checking if out of bounds -> zero-padded so ignore
continue;
for (Eigen::SparseMatrix<double>::InnerIterator it(kernel, k); it; ++it) {
//This iterator only iterates over non-zero values so only nonzero values are multitplied -> better performance with sparse matrices
if (i + kernelRowsHalf - it.row() < 0 || i + kernelRowsHalf - it.row() >= image.rows())//Checking if out of bounds -> zero-padded so ignore
continue;
sum += image(i + kernelRowsHalf - it.row(), j + kernelColsHalf - it.col()) * it.value();
}
}
image_out(i, j) = sum;
}
}
return image_out;
}