You load the image just the same way as you did in GDScript, the syntax is just a bit different.
Ref<Image> image; // do this once and store it in a member variable
image.instance();
image->load("res://image.png");
image->lock(); // this where you need access to pixels
Color c = image->get_pixel(42, 42);
image->unlock();
You can also read the pixel data directly by using get_data()
https://docs.godotengine.org/en/stable/classes/class_image.html#class-image-method-get-data
Then use a Read
struct to access by pointer/ But you will have to deal with the internal layout of the pixel format, because that gives you a raw array of bytes.
tbh, I would actually implement only the CPU-intensive part in GDNative, not the whole thing. So for example, you'd load the image or handle the GUI in GDScript and only do rendering in C++, because GDNative can be rough on the edges, while GDScript allows you to make mistakes without crashing too much. But that's my opinion.
Also depending on how much draw calls you do, GDNative won't shave the overhead of Godot's draw functions.
Even better, for a rendering problem like you have, shaders sound like a much better candidate (although, it may require a much different approach than the ones shown in VoxelSpace I suppose).