我正忙着尝试实现一种图像过滤算法,其工作原理如下: 过滤器是一个大小为 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/