diff --git a/bin/data/shaders/grayscale/grayscale.frag b/bin/data/shaders/grayscale/grayscale.frag new file mode 100644 index 0000000..4ad8a23 --- /dev/null +++ b/bin/data/shaders/grayscale/grayscale.frag @@ -0,0 +1,14 @@ +OF_GLSL_SHADER_HEADER +precision mediump float; + +uniform sampler2DRect tex0; +in vec2 varyingtexcoord; +out vec4 fragColor; + + + +void main() { + vec4 texColor = texture(tex0, varyingtexcoord); + float gray = dot(texColor.rgb, vec3(0.299, 0.587, 0.114)); // Standard luminance formula + fragColor = vec4(vec3(gray), 1.0); +} \ No newline at end of file diff --git a/bin/data/shaders/grayscale/grayscale.vert b/bin/data/shaders/grayscale/grayscale.vert new file mode 100644 index 0000000..aca90a0 --- /dev/null +++ b/bin/data/shaders/grayscale/grayscale.vert @@ -0,0 +1,17 @@ +OF_GLSL_SHADER_HEADER + +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; +uniform mat4 textureMatrix; +uniform mat4 modelViewProjectionMatrix; + +in vec4 position; +in vec2 texcoord; + +out vec2 varyingtexcoord; + +void main() +{ + varyingtexcoord = texcoord; + gl_Position = modelViewProjectionMatrix * position; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0df6a15..af9a805 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ int main( ){ //Use ofGLFWWindowSettings for more options like multi-monitor fullscreen ofGLWindowSettings settings; + settings.setGLVersion(3, 2); settings.setSize(1920, 1080); settings.windowMode = OF_WINDOW; //can also be OF_FULLSCREEN diff --git a/src/ofApp.cpp b/src/ofApp.cpp index 13d4ae9..d101ecd 100644 --- a/src/ofApp.cpp +++ b/src/ofApp.cpp @@ -3,6 +3,9 @@ //-------------------------------------------------------------- void ofApp::setup(){ ofSetFrameRate(60); + //ofDisableArbTex(); + //ofEnableDepthTest(); + ofEnableAlphaBlending(); videoPlayer.load(videoPath); videoPlayer.setLoopState(OF_LOOP_NORMAL); @@ -22,6 +25,7 @@ void ofApp::update(){ videoFrame.setFromPixels(p); } onnx.update(videoFrame); + ofLog() << ofGetFrameRate(); } //-------------------------------------------------------------- diff --git a/src/ofYolo.cpp b/src/ofYolo.cpp index 8ce3e4d..bc0f9ad 100644 --- a/src/ofYolo.cpp +++ b/src/ofYolo.cpp @@ -25,7 +25,7 @@ void ofYolo::ParseOutput(float* &output_tensors, std::vector face.box.y1 = cy - h / 2; face.box.x2 = cx + w / 2; face.box.y2 = cy + h / 2; - face.box.score = cls_conf; + face.box.score = cls_conf * obj_conf; face.box.label_text = "face"; // Extract landmarks @@ -44,13 +44,59 @@ void ofYolo::ParseOutput(float* &output_tensors, std::vector } // Simple helper for drawing boxes given x1, y1, x2, y2 coordinates. -void ofYolo::DrawBox(std::vector &detected_faces){ +void ofYolo::DrawBox(std::vector &detected_faces, int limit){ + int count = 0; for (const auto &face : detected_faces) { + if (count >= limit) break; ofPushStyle(); ofNoFill(); - ofSetColor(ofColor::cyan); - ofDrawRectangle(face.box.x1, face.box.y1, ((face.box.x2) - (face.box.x1)), face.box.y2 - face.box.y1); + ofSetColor(ofColor::red); + float width = face.box.x2 - face.box.x1; + float height = face.box.y2 - face.box.y1; + float side = std::max(width, height); + + // Center of the box + float centerX = (face.box.x1 + face.box.x2) / 2.0f; + float centerY = (face.box.y1 + face.box.y2) / 2.0f; + + // Top-left corner of the square + float x = centerX - side / 2.0f; + float y = centerY - side / 2.0f; + + ofDrawRectangle(x, y, side, side); + ofPopStyle(); + count++; + } +} + +void ofYolo::DrawBoxLabels(const std::vector& detected_faces, int limit) { + int count = 0; + for (const auto& face : detected_faces) { + if (count >= limit) break; + float width = face.box.x2 - face.box.x1; + float height = face.box.y2 - face.box.y1; + float side = std::max(width, height); + + float centerX = (face.box.x1 + face.box.x2) / 2.0f; + float centerY = (face.box.y1 + face.box.y2) / 2.0f; + float x = centerX - side / 2.0f; + float y = centerY - side / 2.0f; + + float margin = 4.0f; + float textX = x + side - margin; + float textY = y + margin + 12; + + std::string label = "Score: " + ofToString(face.box.score, 2) + + "\n" + face.emotion.getDominantEmotion(); + + // Calculate bounding box width for right alignment + ofRectangle bbox = ofBitmapFont().getBoundingBox(label, 0, 0); + + ofPushStyle(); + ofSetColor(ofColor::yellow); + ofDrawBitmapStringHighlight(label, textX - bbox.getWidth(), textY); ofPopStyle(); + count++; } } @@ -170,6 +216,7 @@ void ofYolo::CropFaceToImage(ofImage &inputImage, BoxfWithLandmarks &face, ofIma void ofYolo::SortDetectedFaces(std::vector &detectedFaces){ std::sort(detectedFaces.begin(), detectedFaces.end(), [](const BoxfWithLandmarks &a, const BoxfWithLandmarks &b) { - return a.box.center.x > b.box.center.x; // Sort in descending order + //return a.box.center.x > b.box.center.x; // Sort in descending order + return a.box.score > b.box.score; }); } \ No newline at end of file diff --git a/src/ofYolo.h b/src/ofYolo.h index 6983b4f..d774e96 100644 --- a/src/ofYolo.h +++ b/src/ofYolo.h @@ -116,12 +116,13 @@ class ofYolo{ public: ofYolo(){}; void ParseOutput(float* &out_ptr, std::vector &sorted_faces, unsigned int num_anchors); - void DrawBox(std::vector &detected_faces); + void DrawBox(std::vector &detected_faces, int limit); void DrawCenter(std::vector &detected_faces); void NonMaximumSuppression(std::vector &input_faces, std::vector &output_faces, float iou_threshold); void ConvertBoxCoordsToOriginalSize(std::vector &detected_faces, size_t original_width, size_t original_height); void CropFaceToImage(ofImage &inputImage, BoxfWithLandmarks &face, ofImage &colorImage, int imageSize); void SortDetectedFaces(std::vector &detectedFaces); + void DrawBoxLabels(const std::vector& detected_faces, int limit); private: // Input dimenions of the model -- used for coordinate scaling. size_t modelSize = 640; diff --git a/src/onxProcess.cpp b/src/onxProcess.cpp index 094db2f..e04c69d 100644 --- a/src/onxProcess.cpp +++ b/src/onxProcess.cpp @@ -25,6 +25,10 @@ void onxProcess::setup(ofImage* img) { fdThread.setup(&onxFaceDetection); fdThread.start(); + + // Load Shaders + grayscaleShader.load("shaders/grayscale/grayscale"); + grayscaleRender.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA); } void onxProcess::update(ofImage& frame) { @@ -99,9 +103,12 @@ void onxProcess::updateEmotions() { void onxProcess::draw() { // Drawing code here - //videoFrame.draw(0, 0); - //yolo.DrawBox(detectedFaces); + convertToGrayscale(); + //drawGrid(); + +} +void onxProcess::drawGrid() { int faceSize = modelInputDimensionsFer; int facesPerRow = ofGetWindowWidth() / faceSize; @@ -116,30 +123,16 @@ void onxProcess::draw() { } } -void onxProcess::drawGrid() { - ofImage temp; - int faceSize = 384; - int facesPerRow = ofGetWindowWidth() / faceSize; - int totalRows = (detectedFaces.size() + facesPerRow - 1) / facesPerRow; - - for (int row = 0; row < totalRows; ++row) { - // Calculate number of faces in this row - int startIdx = row * facesPerRow; - int endIdx = std::min(startIdx + facesPerRow, (int)detectedFaces.size()); - int facesInThisRow = endIdx - startIdx; - - // Calculate horizontal offset to center faces in this row - int rowWidth = facesInThisRow * faceSize; - int xOffset = (ofGetWindowWidth() - rowWidth) / 2; - - for (int i = 0; i < facesInThisRow; ++i) { - int idx = startIdx + i; - yolo.CropFaceToImage(videoFrame, detectedFaces[idx], temp, faceSize); - - int x = xOffset + i * faceSize; - int y = row * faceSize; - - temp.draw(x, y); - } - } +void onxProcess::convertToGrayscale() { + grayscaleRender.begin(); + ofClear(0, 0, 0, 255); + grayscaleShader.begin(); + grayscaleShader.setUniformTexture("tex0", videoFrame.getTexture(), 0); + videoFrame.draw(0, 0, videoFrame.getWidth(), videoFrame.getHeight()); + grayscaleShader.end(); + yolo.DrawBox(detectedFaces, batchSizeFer); + yolo.DrawBoxLabels(detectedFaces, batchSizeFer); + grayscaleRender.end(); + + grayscaleRender.draw(0, 0); } \ No newline at end of file diff --git a/src/onxProcess.h b/src/onxProcess.h index 05f0fff..b5680fb 100644 --- a/src/onxProcess.h +++ b/src/onxProcess.h @@ -13,6 +13,7 @@ public: void updateEmotions(); void draw(); void drawGrid(); + void convertToGrayscale(); ofxOnnxRuntime::BaseHandler onxFaceDetection; ofxOnnxRuntime::OnnxThread fdThread; @@ -33,7 +34,7 @@ public: int modelInputHeight = 640; int modelInputDimensionsFer = 260; - int batchSizeFer = 2; + int batchSizeFer = 4; std::string modelPath = "yolov5s-face.onnx"; std::string modelPathFer = "fer.onnx"; @@ -41,4 +42,6 @@ public: std::vector detectedFaces; ofImage videoFrame; + ofShader grayscaleShader; + ofFbo grayscaleRender; }; \ No newline at end of file