使用纯c ++模糊图像

时间:2017-08-07 07:40:10

标签: 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
};

你能帮忙吗?

1 个答案:

答案 0 :(得分:0)

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

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

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

即,

  

我可以通过将数据容器放入更大的数据来实现我的目标   容器

您可以通过创建新图像更大的图像并将边框值复制到边界外的图像来实现。您模糊它的内部部分(在源标记[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

现在,您可以在指数[1,3]上使用3x3框计算5x图像的模糊,并将其写为带有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;
}