ofDocsexamples threads threadChannelExample src ImgAnalysisThread.cpp
/*
 * ImgAnalysisThread.cpp
 *
 *  Created on: Oct 8, 2014
 *      Author: arturo
 */

#include "ImgAnalysisThread.h"
#include "ofConstants.h"

ImgAnalysisThread::ImgAnalysisThread()
:newFrame(true){
	// start the thread as soon as the
	// class is created, it won't use any CPU
	// until we send a new frame to be analyzed
	startThread();
}

ImgAnalysisThread::~ImgAnalysisThread(){
	// when the class is destroyed
	// close both channels and wait for
	// the thread to finish
	toAnalyze.close();
	analyzed.close();
	waitForThread(true);
}

void ImgAnalysisThread::analyze(ofPixels & pixels){
	// send the frame to the thread for analyzing
	// this makes a copy but we can't avoid it anyway if
	// we want to update the grabber while analyzing
    // previous frames
	toAnalyze.send(pixels);
}

void ImgAnalysisThread::update(){
	// check if there's a new analyzed frame and upload
	// it to the texture. we use a while loop to drop any
	// extra frame in case the main thread is slower than
	// the analysis
	// tryReceive doesn't reallocate or make any copies
	newFrame = false;
	while(analyzed.tryReceive(pixels)){
		newFrame = true;
	}
	if(newFrame){
        if(!texture.isAllocated()){
            texture.allocate(pixels);
        }
		texture.loadData(pixels);
	}
}

bool ImgAnalysisThread::isFrameNew(){
	return newFrame;
}

ofPixels & ImgAnalysisThread::getPixels(){
	return pixels;
}

ofTexture & ImgAnalysisThread::getTexture(){
	return texture;
}

void ImgAnalysisThread::draw(float x, float y){
    if(texture.isAllocated()){
        texture.draw(x,y);
    }else{
        ofDrawBitmapString("No frames analyzed yet", x+20, y+20);
    }
}

void ImgAnalysisThread::draw(float x, float y, float w, float h){
    if(texture.isAllocated()){
        texture.draw(x,y,w,h);
    }else{
        ofDrawBitmapString("No frames analyzed yet", x+20, y+20);
    }
}

void ImgAnalysisThread::threadedFunction(){
    // wait until there's a new frame
    // this blocks the thread, so it doesn't use
    // the CPU at all, until a frame arrives.
    // also receive doesn't allocate or make any copies
    ofPixels pixels;
    while(toAnalyze.receive(pixels)){
        // we have a new frame, process it, the analysis
        // here is just a thresholding for the sake of
        // simplicity
        pixels.setImageType(OF_IMAGE_GRAYSCALE);
        for(auto & p: pixels){
            if(p > 80) p = 255;
            else p = 0;
        }

        // once processed send the result back to the
        // main thread. in c++11 we can move it to
        // avoid a copy
#if __cplusplus>=201103
        analyzed.send(std::move(pixels));
#else
        analyzed.send(pixels);
#endif
	}
}