Работа с изображениями в SFML с использованием пиксельных массивов - PullRequest
1 голос
/ 15 июня 2011

Привет, поэтому я пытаюсь создать функцию, которая использует ссылку на изображение и sf :: IntRect

(, в которой есть 4 типа, представляющих верхнюю, нижнюю, левую и правую стороныпрямоугольник. Этот прямоугольник представляет часть отображаемого изображения, но фактически не обрезает пиксели за пределами прямоугольника)

, а затем создает новое сжатое изображение, обрезая пиксели за пределами IntRect,Я подумал, что единственный способ сделать это - создать массив 2d пикселей с теми же размерами, что и IntRect, а затем заполнить его, перебирая изображение, но, поскольку я не знаю размеры IntRect, я не могу сделать константумассив ......

Эта проблема постоянно возникает, я предполагаю, что выполнение множества векторных работ и преобразований в массивы c_style будет стоить много производительности ..

Есть ли какое-то простое решение для интенсивной манипуляции / изменения размеров и цветов изображений?

1 Ответ

1 голос
/ 15 июня 2011

Обычным способом хранения и доступа к 2-мерным изображениям (или любой 2-мерной матрице с переменным размером) является выделение 1-мерного массива подходящего размера (width * height или (width + padding) * height) и вычислениеиндекс в массив «вручную» (y * stride + x, где stride - width + padding).

(я обычно использую std::vector для этого одномерного массива, но это другая история)

Обычный способ ссылки на данные двумерного изображения (ссылка как при передаче по ссылке) заключается в передаче кортежа из:

  • void* imageData - адреса верхнего-пиксель
  • size_t stride - количество байтов, добавляемых к imageData для перехода к следующей строке
  • size_t width
  • size_t height
  • SomeEnum pixelFormat - пиксельный формат изображения (может быть пропущен, если есть только один)

Конечно, если есть только один Pixel-формат, вы можете использоватьвведите указатель и укажите 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 на верхний левый пиксель подчиненного прямоугольника и установите width и height на ширину и высоту подчиненного прямоугольника.stride остается прежним.

Это означает, что вам не нужно «материализировать» обрезанное изображение, вы можете просто передать ссылку на подчиненный объект любой функции, и он будет работать на этом подчиненном элементе.-корректируйте так же, как это было бы для «полного» изображения.

И если вы действительно хотите «материализовать» обрезанное изображение, у вас теперь должно быть достаточно информации, чтобы сделать это тоже.По крайней мере, я на это надеюсь:)

РЕДАКТИРОВАТЬ: Так как вы были очень откровенны в отношении части sf :: IntRect, но потом написали «image» вместо sf :: Image, я предположилВы говорили о чем-то, чем управляете сами, а не о сфинитере. 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);
...