Copy image into new object

I’m trying to create a new object that copies an image from the main app then displays that image on top, with decreasing opacity and increasing scale, so that it appears like the new image on top is “zooming” at the camera. It works, but the image in the new object appears corrupted like it’s not being copied over properly. I bet I am supposed to copy the image over in a more graceful way. Any ideas?

imgwarp.h

#ifndef _IMGWARP 
#define _IMGWARP 
#include "ofMain.h" 

class ImageWarp {

    public: 

    void setup(ofImage image);  
    void update(); 
    void draw(); 

    // variables
    ofImage img;
    float alpha = 255;
    float alphaDrain = 10;
    float scale = 1;
    float scaleSpeed = .01;

    ImageWarp(); 
}; 
#endif

imgwarp.cpp

#include "imgwarp.h"

ImageWarp::ImageWarp()
{
    img.allocate(1024, 1024, OF_IMAGE_COLOR);
}

void ImageWarp::setup(ofImage image)
{
    img = image;
}

void ImageWarp::update()
{
    alpha -= alphaDrain;
    scale += scaleSpeed;
}

void ImageWarp::draw()
{
    ofEnableAlphaBlending();
    ofSetColor(255, 255, 255, alpha);
    img.setAnchorPercent(0.5, 0.5);
    img.draw(512, 512, img.getWidth() * scale, img.getHeight() * scale); // replace constants
    ofDisableAlphaBlending();
}

creating new object instance

    if (key == 'w')
    {
        // image warp
        ImageWarp iw = ImageWarp();
        warps.push_back(iw);
        ofImage copy = currentImg;
        iw.setup(copy);
    }

interesting. I was looking at the ofImage::operator= functions and one uses clone and the other set from pixels. I think in your case it is using set from pixels. so I would try

void ImageWarp::setup(const ofImage & image)
{
    img.clone(image);
}

notice also that I changed the function parameter to be a reference so there is not a copy there.

Hey @prismspecs, I wonder if passing a reference to ImageWarp::setup() is enough to fix the issue. This is an interesting one because ofPixels, as far as I can tell, doesn’t have a constructor that takes an ofImage as an argument. The version of ofImage::operator= that @roymacdonald referred to takes an ofPixels reference as an argument, which presumably arises from passing an ofImage by copy to ImageWarp::setup(). Maybe Roy knows how this ofPixels object (reference ?) might be created when the ofImage is copied when ImageWarp::setup() is called. Maybe this is just a case of the compiler looking for the template that best suits the code? C++ can be so much fun to figure out sometimes!

@TimChi but @prismspecs’s ImageWarp class stores an ofImage, not an ofPixels. The ofImage::operator= only takes in different flavors of ofImage, not ofPixels, so there should be no problems

Thank you @roymacdonald and @TimChi. Roy’s suggestion worked, though I ended up altering it to apply the image as a texture to a mesh in the end. Assuming getTexture() passes a reference, I used to use getTextureReference() which I think was replaced by the former.

I have a very simple question, I searched around a bit and got overly-technical answers so maybe someone can put it simpler for me: Passing a reference, as I understand it, basically means to pass a reference to the place in memory where the data (here the texture) is stored, rather than copy the actual texture as a complete object and pass it to the next function. So, the benefit is simply speed both because it would have to create a copy before sending it, and the actual space in memory is saved because the texture doesn’t have to exist twice. Is that correct?

warp.cpp

#include "warp.h"

ImageWarp::ImageWarp(ofTexture & _tex, ofVec3f _pos)
{

    pos = _pos;
    tex = _tex;

    // create a quad mesh
    // first triangle
    mesh.addVertex(ofVec3f(-1, -1, 0));
    mesh.addVertex(ofVec3f(1, -1, 0));
    mesh.addVertex(ofVec3f(1, 1, 0));

    // second triangle
    mesh.addVertex(ofVec3f(1, 1, 0));
    mesh.addVertex(ofVec3f(-1, 1, 0));
    mesh.addVertex(ofVec3f(-1, -1, 0));

    // first triangle
    mesh.addTexCoord(ofVec2f(0, 0));
    mesh.addTexCoord(ofVec2f(1, 0));
    mesh.addTexCoord(ofVec2f(1, 1));

    // second triangle
    mesh.addTexCoord(ofVec2f(1, 1));
    mesh.addTexCoord(ofVec2f(0, 1));
    mesh.addTexCoord(ofVec2f(0, 0));
}

void ImageWarp::update()
{
    if (fly)
    {
        alpha -= alphaDrain;
        pos.z += speed;
    }
}

void ImageWarp::draw()
{
    ofPushMatrix();
    ofTranslate(pos);
    ofScale(scale, scale, 1);
    ofSetColor(255, 255, 255, alpha);
    tex.bind();
    mesh.draw();
    tex.unbind();
    ofPopMatrix();
}

warp.h

#ifndef _IMGWARP
#define _IMGWARP
#include "ofMain.h"

class ImageWarp
{

public:
    ImageWarp(ofTexture & _tex, ofVec3f _pos);
    void update();
    void draw();

    // variables
    ofImage img;

    ofVec3f pos;
    bool fly = false;
    ofTexture tex;
    ofMesh mesh;
    float speed = 15;

    float alpha = 255;
    float alphaDrain = 4;
    float scale = 512;
};
#endif

create new warp instance

origin = ofVec3f(540, 540, -100);
ImageWarp iw = ImageWarp(img.getTexture(), origin);
warps.push_back(iw);

Yes making copies of large objects can slow things down and use lots of resources, particularly if its done often. So using a reference as a function parameter avoids this. I like the idea of it as “a place in memory”, maybe like a pointer that you don’t have to dereference to use.

There is another benefit to a reference as a function parameter. References can be const or non-const. Using a non-const reference allows a function to modify that specific instance of the object. So I’ll specify a reference as a parameter when I want the function to “take this thing and modify it”. For example:

ofImage image;
ofImage anotherImage;

// send them to ofApp::setupImage() where it will be allocated and acquire a color
setupImage(image, ofColor(255, 0, 127));
setupImage(anotherImage, ofColor::blue);

// an ofImage can modified directly because the function parameter specifies a non-const reference
void ofApp::setupImage(ofImage& img, ofColor color)
{
     image.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_COLOR);
     image.setColor(color);
}

A const reference can be used when you want to protect the object, when you don’t want the function to modify it in any way (intentionally or otherwise). And you still get the benefits of avoiding a copy.

Essentially yes, it is correct. Actually a pointer passes the memory address of the object while the reference passes something else which I dont know what it is but I guess we can understand as a reference to the passed object. Besides the syntax difference when using a pointer and a reference (you use the -> with the pointer, instead of the dot operator) storing references vs storing pointers behave in a different way. But that’s for a different discussion.

Just as a good practice, everytime you pass a “heavy” object to a function do so by a const reference. Only in the case you need to modify somehow the passed referencee within the function, pass it as a non const reference.