Convolution product

template <typename Img>
concept bool Image_with_Neighborhood_and_Extension =
    Image<Img> &&
    Neighborhood<Img> &&
    Extension<Img>;

template <
    Image_with_Neighborhood_and_Extension Img,
    Zippable<Img::neighborhood_type, Convol_Values>
>
Image convolution_product(const Img& ima, const Convol_Values& convol_values) {
    auto ima_res = copy(ima);

    for(auto [&pix_res, pix] : zip(ima_res.pixels(), ima.pixels())) {
        pix_res.val() = accumulate(
            zip(pix.neighborsWithSE(), convol_values),
            Img::value_type{},
            [](auto init_val, auto&& zipped_pixel) {
                auto [neighbor, conv_scalar] = zipped_pixel;
                return init_val + neighbor.val() * conv_scalar;
            }
        );
    }

    return ima_res;
}