用纯c++模糊图像

Blur image with pure c++

我正在尝试模糊图像。在这一点上,我可以无边框模糊它。我读到我可以通过将我的数据容器放入更大的数据容器来实现我的目标。我试过了,但没能成功。也许有人知道一个更简单的解决方案来做到这一点?这是我的代码:

Image Blur::transform(const Image &inputImage)
{
    Image input = (inputImage.type != ImageType::Grayscale)
            ? Grayscale().transform(inputImage)
            : inputImage;

    std::cout << "Blurring" << std::endl;

    Image output = input;

    auto indexAt = [&input](int row, int col) { return row * input.size.m_width + col; };

    for (int row = m_BLUR_MASK_RADIUS; row < output.size.m_height - m_BLUR_MASK_RADIUS; row++)
    {
        for (int col = m_BLUR_MASK_RADIUS; col < output.size.m_width - m_BLUR_MASK_RADIUS; col++)
        {
            std::vector<uint8_t> pixel_values;
            for (int row_offset = -m_BLUR_MASK_RADIUS; row_offset <= m_BLUR_MASK_RADIUS; row_offset++)
            {
                for (int col_offset = -m_BLUR_MASK_RADIUS; col_offset <= m_BLUR_MASK_RADIUS; col_offset++)
                {
                    const int offset_pixel_index = indexAt(row + row_offset, col + col_offset);
                    pixel_values.push_back(input.data[offset_pixel_index]);
                }
            }

            const int center_pixel_index = indexAt(row, col);
            output.data[center_pixel_index] = getModifiedValue(pixel_values);
        }
    }

    return output;
}

其中Image如下:

struct Image
{
    std::vector<uint8_t> data;
    Size size;
    ImageType type;

    int pixelCount() const {
        return size.m_height * size.m_width;
    }

    Image() {}
    Image(Size _size, ImageType _type) : size(_size), type(_type) {}
    ~Image() {}
};

struct Size
{
    int m_width;
    int m_height;

    Size() {}
    Size(int width, int height) : m_width(width), m_height(height) {}
};

enum class ImageType
{
    Rgba,
    Grayscale
};

那你能帮忙吗?

我不太确定你的问题是什么,如果你想模糊它,有边框或无边框模糊,所以我会尝试用这两种方法回答。

首先,当您模糊边界时,您需要假设边界后面的值是什么。通常你会重复使用边框值。

x index -2 | -1  | 0  |  1 |  2  
        ---------------------------
  color ?  |  ?  | C1 | C2 | C3

所以将C1复制到-1,-2索引

x index -2 | -1  | 0  |  1 |  2  
        ---------------------------
  color C1 | C1  | C1 | C2 | C3

I can achieve my goal by putting my data container into bigger data container

您可以通过创建新图像更大的图像并将边界值复制到边界外的图像来实现。您模糊了它的内部部分(在源索引 [0,N] 上),然后丢弃边界外的值(因为它们与原始图像无关)。

3x3 图片示例:

C1 | C2 | C3
------------
C5 | C5 | C6
------------
C7 | C8 | C9

添加 1 个模糊半径

C1 | C1 | C2 | C3 | C3
----------------------
C1 | C1 | C2 | C3 | C3
----------------------
C5 | C5 | C5 | C6 | C6
----------------------
C7 | C7 | C8 | C9 | C9
----------------------
C7 | C7 | C8 | C9 | C9

现在你计算 5x 图像的模糊,在索引 [1,3] 上的索引上有 3x3 框,并将其写为 3x3 模糊图像。这就是您的函数几乎已经做的事情(调整大小除外)。

通过放入更大的容器模糊:

Image transformWithExtending(const Image &inputImage)
{
    Image input = (inputImage.type != ImageType::Grayscale)
        ? Grayscale().transform(inputImage)
        : inputImage;
    Image newInput = Image({ input.size.m_width + 2 * m_BLUR_MASK_RADIUS, input.size.m_height + 2 * m_BLUR_MASK_RADIUS }, input.type);

    auto indexAt = [&input](int row, int col) { return row * input.size.m_width + col; };
    auto clamp = [&input](int x, int minv, int maxv) {return std::min(std::max(x, minv), maxv); } // std::clamp is only in C++17
    // indexing in source image (with negatives)
    for (int row = -m_BLUR_MASK_RADIUS; row < input.size.m_height + m_BLUR_MASK_RADIUS; row++)
        for (int col = -m_BLUR_MASK_RADIUS; col < input.size.m_width + m_BLUR_MASK_RADIUS; col++)
            newInput.data.push_back(input.data[indexAt(clamp(row, 0,input.size.m_width - 1), clamp(row, 0, input.size.m_height - 1))]);


    // now transform it with previous function
    Transform(newInput)

    // and resize...
    // TODO
    //
    return output;
}

但是现在你可以问问自己:为什么要将所有这些数据复制到临时图像中,如果在填充过滤器框值时通过选择边框像素而不是其中一个边框像素可以获得相同的结果?只需将边界外的指数钳制到边界指数即可。这给出了:

在不放入更大容器的情况下进行模糊处理:(您的函数仅改变了几个通道)

Image Blur::transformWithBorders(const Image &inputImage)
{
    Image input = (inputImage.type != ImageType::Grayscale)
        ? Grayscale().transform(inputImage)
        : inputImage;

    std::cout << "Blurring" << std::endl;

    Image output = input;

    auto indexAt = [&input](int row, int col) { return row * input.size.m_width + col; };
    auto clamp = [&input](int x, int minv, int maxv) {return std::min(std::max(x, minv), maxv); } // std::clamp is only in C++17

    for (int row = 0; row < output.size.m_height; row++) // go over whole image
    {
        for (int col = 0; col < output.size.m_width; col++) // go over whole image
        {
            std::vector<uint8_t> pixel_values;
            for (int row_offset = -m_BLUR_MASK_RADIUS; row_offset <= m_BLUR_MASK_RADIUS; row_offset++)
            {
                for (int col_offset = -m_BLUR_MASK_RADIUS; col_offset <= m_BLUR_MASK_RADIUS; col_offset++)
                {
                    // and clamp indicies here
                    const int offset_pixel_index = indexAt(clamp(row + row_offset, 0, output.size.m_height - 1), clamp(col + col_offset,0, output.size.m_width - 1));
                    pixel_values.push_back(input.data[offset_pixel_index]);
                }
            }

            const int center_pixel_index = indexAt(row, col);
            output.data[center_pixel_index] = getModifiedValue(pixel_values);
        }
    }

    return output;
}