Tutorial

Image Loading & Display

Load and display images in a GPU window. Pass a path, get a window. JPEG, PNG, BMP, TGA, HDR supported.

API levelLevel 0 — OaGpuiApp + OaUiImage + OaImagePlanes
Image formatsJPEG, PNG, BMP, TGA, HDR (stb_image)
Display pathVulkan compute → swapchain blit, letterboxed
InputOaInputSystem key actions
SourceTutorial/Vision/TutorialImageViewer.cpp
OA Image Viewer running on Linux

Controls

KeyAction
RView RGB (full colour)
1Red channel only
2Green channel only
3Blue channel only
Q / EscQuit

Bridge to ML

OaImagePlanes and OaMatrix are the same type family — an image loaded here can flow directly into a model without a copy:

Tutorialimageviewer.cpp

// After OaImagePlanes::LoadFile — same GPU buffer, no copy
auto mat = OaFnImage::Normalize(planes, /*mean=*/0.485f, /*std=*/0.229f);
// mat is OaMatrix [1, C, H, W] — ready for model.Forward()

Full Source

The complete 112-line tutorial is in Tutorial/Vision/TutorialImageViewer.cpp:

Tutorialimageviewer.cpp

// ═══════════════════════════════════════════════════════════════════════════
// OA Tutorial: Image Loading and Display — Vision Fundamentals
// Level 0 API — OaGpuiApp + OaUiImage + OaImagePlanes + OaInputSystem
// ═══════════════════════════════════════════════════════════════════════════
//
// Source: oa/Tutorial/Vision/TutorialImageViewer.cpp
// ═══════════════════════════════════════════════════════════════════════════
#include <Oa/Runtime/Engine.h>
#include <Oa/Ui/Gpui.h>
#include <Oa/Ui/Image.h>
enum class ViewMode : OaU8 { RGB = 0, R = 1, G = 2, B = 3 };
class OaImageViewerApp : public OaGpuiApp {
public:
OaStringView Path_ = "Asset/Image/Realm1024px.jpg";
void OnInit(OaGpui& InGpui) override {
auto& rt = *OaVkComputeEngine::GetGlobal();
if (auto r = OaUiImage::LoadFile(rt, Path_); r.IsOk()) { Image_ = *r; }
if (auto r = OaImagePlanes::LoadFile(rt, Path_); r.IsOk()) { Planes_ = *r; }
if (Image_.IsValid()) {
ResizeWindow(Image_.Width, Image_.Height);
}
auto& input = InGpui.Input();
input.RegisterAction({.Name = "quit", .Binding = {.Key = OuiKey::Escape}, .Callback = [this] { Quit(); }});
input.RegisterAction({.Name = "quitq", .Binding = {.Key = OuiKey::Q}, .Callback = [this] { Quit(); }});
input.RegisterAction({.Name = "rgb", .Binding = {.Key = OuiKey::R}, .Callback = [this] { Mode_ = ViewMode::RGB; }});
input.RegisterAction({.Name = "red", .Binding = {.Key = OuiKey::Num1}, .Callback = [this] { Mode_ = ViewMode::R; }});
input.RegisterAction({.Name = "green", .Binding = {.Key = OuiKey::Num2}, .Callback = [this] { Mode_ = ViewMode::G; }});
input.RegisterAction({.Name = "blue", .Binding = {.Key = OuiKey::Num3}, .Callback = [this] { Mode_ = ViewMode::B; }});
}
void OnRender(Oui& InOui) override {
if (!Image_.IsValid()) return;
// Letterbox: fit image to window preserving aspect ratio.
OaF32 W = (OaF32)Gpui().Width(), H = (OaF32)Gpui().Height();
OaF32 a = (OaF32)Image_.Width / (OaF32)Image_.Height;
OaI32 dW = (OaI32)W, dH = (OaI32)(W / a);
if (dH > (OaI32)H) { dH = (OaI32)H; dW = (OaI32)(H * a); }
OaI32 x = ((OaI32)W - dW) / 2, y = ((OaI32)H - dH) / 2;
InOui.BeginPanel("image", {.X = x, .Y = y, .W = dW, .H = dH});
if (Mode_ == ViewMode::RGB) {
InOui.Image(Image_.BindlessIndex(), Image_.Width, Image_.Height);
} else {
OaU32 ch = (OaU32)Mode_ - 1;
OaImagePlanes single;
single.Width = Planes_.Width; single.Height = Planes_.Height;
single.ChannelCount = 1;
single.Planes[0] = Planes_.Planes[ch];
single.Dtypes[0] = Planes_.Dtypes[ch];
InOui.ImagePlanar(single);
}
InOui.EndPanel();
}
void OnShutdown(OaGpui& /*InGpui*/) override {
auto& rt = *OaVkComputeEngine::GetGlobal();
Planes_.Destroy(rt);
Image_.Destroy(rt);
}
private:
OaUiImage Image_;
OaImagePlanes Planes_;
ViewMode Mode_ = ViewMode::RGB;
};
int main(int argc, char** argv) {
OaImageViewerApp app;
if (argc > 1) app.Path_ = argv[1];
return app.Run({.Title = "OA Image Viewer", .Width = 1280, .Height = 720}).IsOk() ? 0 : 1;
}