Here is the vectorized version of computing the local maxima (based on your algorithm):
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = ...
in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 1:(n_cols - 2)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(2:(n_rows - 1), 1:(n_cols - 2)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 1:(n_cols - 2)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 3:(n_cols )) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(2:(n_rows - 1), 3:(n_cols )) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 3:(n_cols ));
It may be made more cache friendly:
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = ...
in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 1:(n_cols - 2)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(2:(n_rows - 1), 1:(n_cols - 2)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 1:(n_cols - 2));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 2:(n_cols - 1));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 3:(n_cols )) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(2:(n_rows - 1), 3:(n_cols )) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 3:(n_cols ));
You can also try this third version:
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = ...
in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 1:(n_cols - 2));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(2:(n_rows - 1), 1:(n_cols - 2));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 1:(n_cols - 2));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 2:(n_cols - 1));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 2:(n_cols - 1));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(1:(n_rows - 2), 3:(n_cols ));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(2:(n_rows - 1), 3:(n_cols ));
is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) = is_local_max(2:(n_rows - 1), 2:(n_cols - 1)) ...
& in_arr(2:(n_rows - 1), 2:(n_cols - 1)) >= in_arr(3:(n_rows ), 3:(n_cols ));
I cannot verify, but MATLAB should be able to generate code without memory allocation.
stack(i,j,:)is yourlocal_buffat(i,j). Then you can usemaxon the third dimensionmax(in_arr((i - 1):(i + 1), (j - 1):(j + 1)), [], 'all')allows for better optimization. Otherwise try to explicitly compare each of the 8 neighbors to the central pixel. Also, instead of writing the result of the comparison tois_local_maxdirectly, maybe it’s faster to only write when it’s true (since you said it’s zero-initialized). If all else fails, write the C code by hand…