ofxThreadedImageLoader inside a class

I’m developing a slideshow of sorts that bring images from a database of thousands of images. I wrote some methods but I need the image load to be threaded and smooth using my video card GPU. This WImage class allows me to load some images in a few layers from a list of images (mempic) that are loaded in the main loop, but every time it loads a new batch of files the whole thing lags a bit. Any ideas in how to achieve a smoother load in the these WImage layers? Thanks so much for any hint!

WImage.cpp

//
//  wImage.cpp
//  ofImages
//
//

#include "Wimage.h"


Wimage::Wimage() {

}

void Wimage::setup() {

	int wWidth = ofGetWidth();   // get window size
	int wHeight = ofGetHeight();
	extern float segmentol;
	extern float seghoriz;
	extern bool bSame;
	size = ofRandom(0.3, 1);

	if (!bSame) {
		newImage();
	}
	else { sameImage(); }
	
	resize(size);

	x = wWidth / 2 - w / 2;
	y = wHeight / 2 - h / 2;

	w = pic.getWidth();
	h = pic.getHeight();
	ratio = w / h;

	fadespeed = ofRandom(1, 4);
	showtime = 120;

	alpha = ofRandom(120, 235);       // alpha
	
	// fadespeed=3;

	t = 100; //ofRandom(100,500);
	
	segmento = int(ofRandom(0, 4));
	segmentol++; if (segmentol > 3) segmentol = 0;
	segmentolineal = segmentol;
	segmentohoriz = int(ofRandom(-8, 8));
	
	
	w6 = wWidth / 6;
	y6 = 0;
	seghoriz++; if (seghoriz > 5) seghoriz = 0;
	x6 = seghoriz * w6;
	seghorizlineal = seghoriz;
	// hsegmento = h/4*(ofRandom(1,2));
	hsegmento = h / 4;
	// hsegmento = ofGetHeight()/4;
	 //if (segmento == 3) hsegmento = h/4;

	// recorte y zoom 
	sx = ofRandom(0, w / 2);
	sy = ofRandom(0, h / 2);
	sw = ofRandom(w6 / 4, w6 * 2);
	sh = sw * 1.7777;
	resize(size);
	alphai = 0;

}

void Wimage::update() {

	

}

void Wimage::fade() {
	//extern float fadespeed;
	if (fadeout == 0) {
		alphai = alphai + fadespeed;
		if (alphai > alpha) {
			alphai = alpha; fadeout = 1;
		}
	}

	if (fadeout == 1) {
		showtime--;
		if (showtime <= 0) { fadeout = 2;  }

	}

	if (fadeout == 2) {
		alphai = alphai - fadespeed;
		if (alphai < 0) {
			alphai = 0; fadeout = 0; setup();
		}
	}
}

void Wimage::draw() {

	// drawfade();

}

void Wimage::resize(float percent) {

	size = percent;
	w = w * size;
	h = w / ratio;
	x = ofGetWidth() / 2 - w / 2;
	y = ofGetHeight() / 2 - h / 2;

}

void Wimage::drawfade() {

	fade();
	ofSetColor(255, 255, 255, alphai);
	pic.draw(x, y, w, h);
}


void Wimage::drawnofade() {

	ofSetColor(255, 255, 255, alpha);
	pic.draw(x, y, w, h);

}



void Wimage::newImage() {

	extern size_t ix;
	extern vector<ofImage> mempic;

	pic.loadData(mempic[ix]);
	ix++;

	if (ix >= mempic.size()) ix = 0;
}

Hi, you can use the ofxThreadedImageLoader addon, which is one of the openFrameworks’ core addons, thus you already have it. There is an example on how to use it in examples/threads/threadedImageLoaderExample
You can add more than one instance of ofxThreadedImageLoader to your class so you can load all faster and make use of your computers multiple CPUs but don’t make more than the amount of logical cores you’ve got. One good thing about the threaded image loaders is that it automatically queues the load requests, meaning that you dont have to code something where you wait for the load to finish in order to request a new load.
hope this helps.

Thanks @roymacdonald
I’m trying with ofxThreadedImageLoader but even when the load works without a break I can’t see the images with this method. The loading class is this one (it loads from a vector of URLs (mempicfiles) that I preloaded at the beginning) and it adds to the pic a new url value until it reaches the max value of mempicfiles. I read somewhere that you have to have this in the main thread but I don’t know if this means that I can’t use it inside another class.

Is there any other class with ofxThreadedImageLoader that I could check?

void Wimage::newImage() {

	extern size_t ix;
	extern vector<string> mempicfiles;

	ofxThreadedImageLoader loader;
	loader.loadFromDisk(pic, mempicfiles[ix]);
	ix++;
	if (ix >= mempicfiles.size()) ix = 0;

}

I show the image with a method like this one:

void Wimage::drawnofade() {

	ofSetColor(255, 255, 255, alpha);
	pic.draw(x, y, w, h);

}

the problem is that you are declaring the loader as a local variable of your function, which will get destroyed as soon as the whole function gets executed, thus not allowing it to finish loading. you need to declare it as a class variable instead so it remains there until the whole loading gets done.

Thanks a lot @roymacdonald --that was the issue. Is now running!
I’m having problems with images appearing suddenly (because the alpha fade-in is on its way already when the image loads), also the sizes are wrong (i think because of the same reason, the layer containing the dimensions of a former image). Is possible to check the load of the image in this case? I tried the solution here: https://gist.github.com/stephanschulz/3e3e23c30f377256abf936cdd8bdd1f8 but that bool bDoneLoading refers to the whole loader I think? --and in this case, as is a vector of a few WImage objects, I should check the individual image of every instance.

Thanks a lot for your great help.

Hi, I understand.
you can modify the ofxThreadedImageLoader class and add an ofEvent to which you register from your WImage class and trigger notify this event from

void ofxThreadedImageLoader::update(ofEventArgs & a){
    // Load 1 image per update so we don't block the gl thread for too long
	ofImageLoaderEntry entry;
	if (images_to_update.tryReceive(entry)) {
		entry.image->setUseTexture(true);
		entry.image->update();
               //call your custom event notification here, as the image is ready and loaded now.
	}
}

Another option would be to check against the ofImage’s isAllocated() function, which should become true only once it is fully loaded, thus allowing you to start the fade in and setting the size properly.

Thanks again @roymacdonald
I’m using

void Wimage::setup() {	

	newImage(); // function that gets a new threaded image in pic
	
	if (pic.isAllocated()) {
		size = ofRandom(0.3, 1);
		w = pic.getWidth();
		h = pic.getHeight();
		ratio = w / h;

        w = ofGetWidth() * size; // resizes image 
		h = w / ratio;  // calculates new height with aspect ratio, proportionally to display

		x = ofGetWidth() / 2 - w / 2;  // new position, centered
		y = ofGetHeight() / 2 - h / 2;

		fadespeed = 3;
		showtime = 120;

		alpha = ofRandom(120, 235);       // max alpha
		alphai = 0;                       // alpha value for fades
	}
}

newImage() function:

void Wimage::newImage() {

	extern size_t ix;  // current index of urls
	extern vector<string> mempicfiles;   // vector of urls

	loader.loadFromDisk(pic, mempicfiles[ix]);
	ix++;
	if (ix >= mempicfiles.size()) ix = 0;
}

fade() function:

void Wimage::fade() {

	if (pic.isAllocated()) {
		if ((fadeout == 0)) {  // fade in
			alphai = alphai + fadespeed;
			if (alphai > alpha) {
				alphai = alpha; fadeout = 1;
			}
		}

		if (fadeout == 1) { // if reaches max alpha it stays at full alpha for a while
			showtime--;
			if (showtime <= 0) { fadeout = 2; }

		}

		if (fadeout == 2) {  // fade out
			alphai = alphai - fadespeed;
			if (alphai < 0) {
				alphai = 0; fadeout = 0; setup();
			}
		}
	}
}

But the glitch is still there in the fade in (fade out is ok) and the sizes of the images that start to get weird aspect ratios.

Any idea? This is driving me nuts.

Thanks a lot for any hint --and excuse the bother

no prob.
in

void Wimage::setup() {	

	newImage(); // function that gets a new threaded image in pic
	
	if (pic.isAllocated()) {

you are calling pic.isAllocated immediately after calling newImage(). as the latter will use the threaded loader, it will return before the loading is done (this is the whole point about threading, so it does not block the rest of the code), thus pic.isAllocated() will probably be false. an easy work around is to call pic.isAllocated() when you are drawing the image, and execute there all the code you have in the setup.

1 Like