Skip to content

How to Read Pixel Data from Images in Unreal Engine Using C++

In this blog post, I'll guide you through the process of reading pixel data from images in Unreal Engine using C++. This technique can be beneficial for various applications, including image processing, custom shaders, or making decisions based on image content.

Prerequisites

Before diving into the code, ensure you have:

  • A basic understanding of Unreal Engine and C++.

  • Unreal Engine installed and set up.

  • A project created in Unreal Engine.

Step 1: Include Necessary Headers

First, include the necessary headers in your .cpp file. These headers are essential for handling textures and image data.

```cpp

#include "GetTexture.h"
#include <ImageUtils.h>

Step 2: Write the Function to Read Pixel Data

Here's the function to read pixel data from a UTexture2D object. This function will populate a TArray with FColor values representing each pixel''s color data, and it will also output the texture's width and height.

void AGetTexture::GetPixels(UTexture2D* Texture, int32& OutWidth, int32& OutHeight)
{
    TArray<FColor> PixelArray;

    if (!Texture || !Texture->GetPlatformData())
    {
        UE_LOG(LogTemp, Error, TEXT("Texture is null or PlatformData is missing"));
        OutWidth = 0;
        OutHeight = 0;
        return; 
    }

    // Save old texture settings
    TextureCompressionSettings OldCompressionSettings = Texture->CompressionSettings;
    TextureMipGenSettings OldMipGenSettings = Texture->MipGenSettings;
    bool OldSRGB = Texture->SRGB;

    // Temporarily change texture settings for pixel reading
    Texture->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
    Texture->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
    Texture->SRGB = false;
    Texture->UpdateResource();

    FTexture2DMipMap* MipMap = &Texture->PlatformData->Mips[0];
    const FColor* FormattedImageData = static_cast<const FColor*>(MipMap->BulkData.LockReadOnly());

    OutWidth = MipMap->SizeX;
    OutHeight = MipMap->SizeY;
    PixelArray.SetNum(OutWidth * OutHeight);

    for (int32 Y = 0; Y < OutHeight; Y++)
    {
        for (int32 X = 0; X < OutWidth; X++)
        {
            FColor PixelColor = FormattedImageData[Y * OutWidth + X];
            PixelArray[Y * OutWidth + X] = PixelColor;
            SpawnCubes(PixelColor, Y, X);
        }
    }

    MipMap->BulkData.Unlock();

    // Restore original texture settings
    Texture->CompressionSettings = OldCompressionSettings;
    Texture->MipGenSettings = OldMipGenSettings;
    Texture->SRGB = OldSRGB;
    Texture->UpdateResource();
}

Explanation of the Function

Parameters:

  • UTexture2D* Texture: The texture from which you want to read pixel data.

  • int32& OutWidth: Output parameter for the texture's width.

  • int32& OutHeight: Output parameter for the texture's height.

Checking Texture Validity

if (!Texture || !Texture->GetPlatformData())
{
    UE_LOG(LogTemp, Error, TEXT("Texture is null or PlatformData is missing"));
    OutWidth = 0;
    OutHeight = 0;
    return; // Return empty array to indicate an error
}

This section checks if the texture is valid and if it has platform data. If either is missing, it logs an error and sets the output width and height to zero.

Temporarily Change Texture Settings

// Save old texture settings
TextureCompressionSettings OldCompressionSettings = Texture->CompressionSettings;
TextureMipGenSettings OldMipGenSettings = Texture->MipGenSettings;
bool OldSRGB = Texture->SRGB;

// Temporarily change texture settings for pixel reading
Texture->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
Texture->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
Texture->SRGB = false;
Texture->UpdateResource();

Changing the texture settings is crucial for ensuring the pixel data is read correctly. Here’s why each setting is important:

Compression Settings:

Using TC_VectorDisplacementmap ensures the texture is not compressed in a way that would alter pixel values. Mip Generation Settings: Setting MipGenSettings to TMGS_NoMipmaps ensures you are reading the highest resolution of the texture. SRGB: Disabling SRGB ensures the color values are read linearly without gamma correction, preserving the original pixel data.

Importance of Texture Compression

Texture compression in Unreal Engine can significantly affect image quality and pixel data accuracy. When textures are compressed, color information may be altered or reduced, leading to visual artifacts or inaccuracies in applications like image processing or shader effects.

Visual Comparison: Compressed vs. Uncompressed Image

Image Compressed

alt textalt text

Image Uncompressed

alt textalt text

The above images demonstrate the difference between an uncompressed and compressed texture. Notice how compression make pixel data completely unrecognizable.

Visualizing Pixel Data

To illustrate how texture settings impact pixel data, we can spawn cubes in Unreal Engine for each pixel color read from a texture.

Locking MipMap Data

FTexture2DMipMap* MipMap = &Texture->PlatformData->Mips[0];
const FColor* FormattedImageData = static_cast<const FColor*>(MipMap->BulkData.LockReadOnly());

This part locks the mipmap data for reading. The mipmap stores different levels of texture detail, with level 0 being the highest resolution.

Reading Pixel Data

OutWidth = MipMap->SizeX;
OutHeight = MipMap->SizeY;
PixelArray.SetNum(OutWidth * OutHeight);

for (int32 Y = 0; Y < OutHeight; Y++)
{
    for (int32 X = 0; X < OutWidth; X++)
    {
        FColor PixelColor = FormattedImageData[Y * OutWidth + X];
        PixelArray[Y * OutWidth + X] = PixelColor;
    }
}

This loop iterates over each pixel in the texture, reading the color data and storing it in the PixelArray.

Unlocking MipMap Data

MipMap->BulkData.Unlock();

Finally, the function unlocks the mipmap data to ensure it''s properly released after reading.

Restoring Original Texture Settings

Texture->CompressionSettings = OldCompressionSettings;
Texture->MipGenSettings = OldMipGenSettings;
Texture->SRGB = OldSRGB;
Texture->UpdateResource();

Restoring the original texture settings ensures the texture is returned to its initial state after the pixel data is read.


By following these steps, you can effectively read pixel data from images in Unreal Engine using C++. This functionality opens up various possibilities for image manipulation and analysis within your Unreal Engine projects.