使用像素阵列在SFML中处理图像

时间:2011-06-14 23:44:51

标签: c++ image-manipulation pixel vector-graphics sfml

嘿所以我正在尝试创建一个带有图像参考的函数和sf :: IntRect

这有4个整数,表示矩形的顶部,底部,左侧和右侧。此矩形表示正在显示的图像部分,但实际上并未切除矩形外的像素)< / em>的

然后通过切断IntRect外部的像素来创建新的压缩图像。我认为我能做到这一点的唯一方法是制作一个与IntRect尺寸相同的二维像素阵列,然后通过迭代图像来填充它,但由于我不知道IntRect的尺寸我不能做一个常数阵列......

这个问题不断出现,我假设做一堆矢量工作并且对c_style数组的转换会花费很多性能。

是否有一些简单的溶剂来严重操纵/改变图像的尺寸和颜色?

1 个答案:

答案 0 :(得分:1)

存储和访问二维图像(或任何大小可变的二维矩阵)的常用方法是分配一个合适大小的一维数组(width * height(width + padding) * height ),并“手动”计算数组中的索引(y * stride + x,其中stridewidth + padding)。

(我通常将std::vector用于该1维数组,但这是一个不同的故事)

引用2D图像数据(参考传递参考)的常用方法是传递一个元组:

  • void* imageData - 左上角像素的地址
  • size_t stride - 要添加到imageData以转到下一行的字节数
  • size_t width
  • size_t height
  • SomeEnum pixelFormat - 图像的像素格式(如果只有一个,则可省略)

当然,如果只有一个Pixel-Format,您可以使用类型指针,并以该类型为单位指定stride(而不是字节)。

使用这样的引用,您可以非常轻松且高效地访问循环中的像素:

size_t const bytesPerPixel = GetBytesPerPixel(ref->pixelFormat);

for (size_t y = 0; y < ref->height; y++)
{
    unsigned char* currentLine =
        static_cast<unsigned char*>(ref->imageData) + ref->stride * y;

    for (size_t x = 0; x < ref->width; x++)
    {
        // any modern compiler will optimize the multiplication below to
        // an incremental addition
        unsigned char* currentPixel = currentLine + bytesPerPixel * y;

        // do something to the pixel data at
        // currentPixel[0] ... currentPixel[bytesPerPixel - 1]
    }
}

以这种方式传递图像引用的好处是,您可以始终“调整”这样的引用以指向原始图像的子矩形。您只需相应地调整值:将imageData指向子矩形的左上角像素,并将widthheight设置为子矩阵的宽度和高度。 stride保持不变。

这意味着您不必“实现”裁剪后的图像,您只需将对子矩阵的引用传递给任何函数,它就会像在“完整”上那样在该子矩阵上运行“图片。

如果你真的想要“实现”裁剪的图像,你现在应该有足够的信息来做到这一点。至少我希望如此:)

编辑:既然你对sf :: IntRect部分非常明确,但之后只写了“image”而不是sf :: Image,我以为你在谈论自己管理的事情,不是sf :: Image。嗯......

如果您只想将sf :: Image的子矩形复制到另一个sf :: Image,您可以这样做:

sf::Image sourceImage = ...;
sf::IntRect subRect = ...;

// construct an empty sf::Image with the appropriate dimensions
sf::Image newImage(subRect.GetWidth(), subRect.GetHeight());

// copy the pixel data into the new image
newImage.Copy(sourceImage, 0, 0, subRect);