#ifndef OFX_RGBVHISTOGRAM_HPP #define OFX_RGBVHISTOGRAM_HPP #include #include #include "ofxFastFboReader.h" #include "ofxHistogram.h" template std::vector operator+(const std::vector& a, const std::vector& b) { assert(a.size() == b.size()); std::vector result; result.reserve(a.size()); std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(result), std::plus()); return result; } class ofxRGBVHistogram { public: void setup(int w, int h, size_t bins = 256) { bins_ = bins; rgb_.allocate(w, h); hsv_.allocate(w, h); v.allocate(w, h); r.allocate(w, h); g.allocate(w, h); b.allocate(w, h); fbo_.allocate(w, h, GL_RGB); } void update() { update(fbo_); } void update(ofFbo& fbo) { ofPixels pixels; reader_.readToPixels(fbo, pixels); rgb_.setFromPixels(pixels); cvCvtColor(rgb_.getCvImage(), hsv_.getCvImage(), CV_BGR2HSV); r.setFromPixels(rgb_.getPixels().getChannel(0)); g.setFromPixels(rgb_.getPixels().getChannel(1)); b.setFromPixels(rgb_.getPixels().getChannel(2)); histogramR = histogram_.getHistogram(r, bins_); histogramG = histogram_.getHistogram(g, bins_); histogramB = histogram_.getHistogram(b, bins_); // the hsv conversion is not cheap; this is a faster way to get a sense of the V histogramV = histogramR + histogramG + histogramB; } void draw(int x, int y, int w, int h) { ofPushMatrix(); ofPushStyle(); { ofTranslate(x, y); ofEnableBlendMode(OF_BLENDMODE_ALPHA); ofFill(); ofSetColor(0, 0, 0, 128); ofDrawRectangle(0, 0, w, h); fbo_.draw(w, h, w, h); if (!histogramV.empty()) { draw_histogram(histogramR, w, h, ofColor(255, 50, 50, 128), ofColor(200, 0, 0, 64)); draw_histogram(histogramG, w, h, ofColor(0, 175, 0, 128), ofColor(0, 255, 0, 64)); draw_histogram(histogramB, w, h, ofColor(64, 64, 255, 128), ofColor(0, 0, 255, 64)); draw_histogram(histogramV, w, h, ofColor(128, 128, 128, 128)); ofEnableBlendMode(OF_BLENDMODE_DISABLED); // black peak if ((histogramV[0] + histogramV[1] + histogramV[2] + histogramV[3]) > .01) { ofFill(); ofSetColor(ofColor::black); ofDrawRectangle(5, h - 10 - 5, 10, 10); ofNoFill(); ofSetColor(ofColor::red); ofDrawRectangle(5, h - 10 - 5, 10, 10); } // white peak if (histogramV[histogramV.size() - 1] > 0.02) { ofFill(); ofSetColor(ofColor::white); ofDrawRectangle(w - 5 - 10, h - 10 - 5, 10, 10); ofNoFill(); ofSetColor(ofColor::red); ofDrawRectangle(w - 5 - 10, h - 10 - 5, 10, 10); } } } ofPopStyle(); ofPopMatrix(); } void draw_histogram(vector& h, int width, int height, ofColor line_color, ofColor fill_color = NULL) { if (fill_color != NULL) { ofSetColor(fill_color); ofEnableBlendMode(OF_BLENDMODE_ADD); ofBeginShape(); ofFill(); ofSetLineWidth(3); for (size_t i = 0; i < h.size(); i++) { float x = ofMap(i, 0, h.size() - 1, 0, width); float y = ofMap(pow(h[i], .5), 0, 0.3, height, 0, true); ofVertex(x, y); } ofVertex(width, height); ofVertex(0, height); ofEndShape(); } ofSetColor(line_color); ofEnableBlendMode(OF_BLENDMODE_DISABLED); ofBeginShape(); ofNoFill(); ofSetLineWidth(3); for (size_t i = 0; i < h.size(); i++) { float x = ofMap(i, 0, h.size() - 1, 0, width); float y = ofMap(sqrt(h[i]), 0, 0.3, height, 0, true); ofVertex(x, y); } ofEndShape(); } std::size_t bins_; ofxFastFboReader reader_; ofFbo fbo_; ofxHistogram histogram_; ofxCvColorImage rgb_, hsv_; ofxCvGrayscaleImage r, g, b, v; vector histogramV, histogramR, histogramG, histogramB; }; #endif // OFX_RGBVHISTOGRAM_HPP