C++图像过滤算法

标签 c++ arrays image algorithm filter

我正忙着尝试实现一种图像过滤算法,其工作原理如下: 过滤器是一个大小为 N 的二维数组(N 必须是奇数),因此具有 N*N 个元素。大小为 3 的示例过滤器为:

0.25 1 0.25
0.25 0 0.25
0.25 1 0.25

对于图像数据中的每个无符号字符(像素),将过滤器阵列的中心放在当前工作像素处。然后对于过滤器在图像中覆盖的每个像素,找到过滤器覆盖的所有像素的加权和(即每个过滤器值乘以它当前覆盖的像素)并将当前工作图像像素值设置为该加权和.对图像中的每个像素执行此操作。如果滤镜像素超出图像二维阵列的范围(即偏离左、右、上、下),则它必须环绕图像的适当边缘。

所以我有以下代码:

Image Image::operator%(const Filter & g) {
    Image filtered = *this;
    std::vector<std::vector<float>> filter = g.get_filter();
    Image::iterator beg = filtered.begin();
    Image::iterator end = filtered.end();
    unsigned char* pixel_data = filtered.data.get();
    int pixel_index = 0;

    while(beg != end) {
        // current working pixel value
        unsigned char* c_pixel = *beg;

        float weight = 0;

        // starting x and y position (top left) relative to the centre
        // of the filter at index 'pixel'
        int start_y = pixel_index - (g.get_size()-1) / 2;
        int start_x = pixel_index - (g.get_size()-1) / 2;

        for(int row = 0; row < g.get_size(); ++row) {
            std::vector<float> r = filter.at(row);
            int c_row = start_y + row;

            if(c_row >= height) {
                c_row %= height;
            } else if(c_row < 0) {
                c_row += height;
            }

            for(int col = 0; col < g.get_size(); ++col) {
                // current column of filter relative
                // to the image pixel
                int c_col = start_x + col;

                if(c_col >= width) {
                    c_col %= width;
                } else if(c_col < 0) {
                    c_col += width;
                }
                weight += pixel_data[this->index(c_col, c_row)]*r.at(col);
            }
        }
        *c_pixel = weight;
        ++beg;
        ++pixel_index;
    }
    return filtered;
}

如果您想知道,this->index(c_col, c_row)将一维数组视为二维数组:

int Image::index(int x, int y) {
    return width*y + x;
}

... 图像数据受 std::unique_ptr<unsigned char[]> 保护. 这段代码给了我一些奇怪的输出。生成的图像具有不同像素颜色的垂直条纹,有点类似于原始图像颜色。我不知道我做错了什么,因为这种方法在纸上检查而不是在代码中检查。如果需要,我很乐意添加任何额外信息。 :)

最佳答案

我首先关心的是图像像素格式。你说输出是std::unique_ptr<unsigned char[]> ,但权重是使用 float 计算和写入的。你的index方法返回一个索引,而不考虑像素数据大小 { 1_BYTE (monochrome), 3_BYTE (RGB8), 4_Byte(RGBA8) }。 pixel_data是 char(字节),所以我不确定您是否正确索引了像素数据,没有考虑像素大小,也没有忽略 alpha(如果需要)。

另一个问题是,如果您使用的是 RGB(a) 数据,则从 INT->Float 的转换将无法正确缩放。乘以 float 会将像素缩放为实数而不是单独的 channel 。这将导致 channel 相互溢出并且通常不正确。

您的下一步是创建一个过滤器,该过滤器以具有 RGB channel (忽略 alpha)的像素形式读取和写入数据,以确保您的过滤器是直通的。然后,您将编写一个过滤器,通过将其设置为 0 或 255 来移除 RGB channel 。(红色 channel 、蓝色 channel 、绿色 channel )

一旦确定可以分别正确地操作 RGB,就可以开始应用权重了。

第一次尝试会很慢。最终你会发现你可以使用 MASKs 来抓取与 G channel 分开的 R_B channel ,你不会担心溢出。这个魔法一般看起来像这样:

    UInt32 WeightPixel(UInt32 value, float weight)
    {
        const UInt32 MASK1 = (UInt32)0x00ff00ff; // _R_B
        const UInt32 MASK2 = (UInt32)0xff00ff00; // A_G_

        int f2 = (int)(256 * weight); // Scale weight into char range

        // >> 8 is just divide by 256
        return (UInt32)(((((value & MASK1) * f2)) >> 8) & MASK1)
               | (UInt32)(((((value & MASK2) * f2)) >> 8) & MASK2);
    }

关于C++图像过滤算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44099410/

相关文章:

c++ - C++中返回指针的函数

c++ - 当存在 2 个不同大小时打印函数多维数组 C++

arrays - bash 在循环中分配给数组索引时遇到问题

CSS3 - 覆盖整个网站的多个背景

java - Netbeans 导致我的 Logo 颜色反转?

c++ - C++ 拷贝构造函数中的 const

c++ - 与 std::atomic 相反,读取互斥量范围之外的 volatile 变量

c++ - 基本构造函数根据输入调用派生的构造函数-在运行时选择对象子类型

python - cursor.fetchall() 的打印结果没有尾随 'L'

excel - 如何控制图像透明度?