I am using two libraries: OpenCV for computer vision functions and OpenSceneGraph for computer graphics functions. Because, the main purpose of the software is augmented reality. The main aim of the software is to create a face-filter like the one in Snapchat, and so far I have done with the facial landmarks (computer vision part) and loading 3d model inside the camera feed of OpenCV with the help of OpenSceneGraph functions. The problem is that I tried to place the 3d model on the top of face landmarks but it did not work perfectly because the coordinates of the model is different from the OpenCV facial landmarks model. So, is there a way where I can place the model on the top of facial landmarks perfectly?
I have tried to change the position of the model based on the facial landmarks coordinate points but without luck, even if I have divided the number by a factor of 10 or 20, because the coordinate points that come from the facial landmarks are huge compared to the ones from the model's position. Note that the position of the model has three coordinate points which are: x, y and z, while points that come from the facial landmarks are only x and y.
main.cpp
#include <iostream>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/PositionAttitudeTransform>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "OpenCVFuncs.hpp"
#include "/home/bardawil/Desktop/OSG-OpenCV-ARDemo/include/BackgroundCamera.h"
#include "/home/bardawil/Desktop/OSG-OpenCV-ARDemo/include/VirtualCamera.h"
using namespace cv;
using namespace cv::face;
using namespace std;
// Initialization: -
// ** OSG Stuff **
int screenWidth, screenHeight, textureWidth, textureHeight;
// Create viewer
osgViewer::Viewer viewer;
// Main Camera
osg::ref_ptr<osg::Camera> camera = viewer.getCamera();
// Background-Camera (OpenCV Feed)
BackgroundCamera bgCamera;
// Load glass Model as Example Scene
osg::ref_ptr<osg::Node> glassModel = osgDB::readNodeFile("priestene test.obj");
// Model position initial value
osg::Vec3 modelPosition(0, 100, 10);
// Model scale initial value
osg::Vec3 modelScale(150, 150, 150);
// ** OpenCV Stuff **
// Video Capture initialization (from desktop camera)
cv::VideoCapture cap(0);
Mat gray;
// Load Face Detector
CascadeClassifier faceDetector("/home/bardawil/Desktop/OSG-OpenCV-ARDemo/haarcascade_frontalface_alt2.xml");
// Create an instance of Facemark
Ptr<Facemark> facemark = FacemarkLBF::create();
struct faceParams faceStruct;
// struct eyesLM eyes;
int main( int argc, char** argv )
{
int count = 0;
facemark->loadModel("/home/bardawil/Desktop/OSG-OpenCV-ARDemo/lbfmodel.yaml");
screenWidth = 640;
screenHeight = 480;
textureWidth = 640;
textureHeight = 480;
// OSG STUFF
viewer.setUpViewInWindow(50,50,screenWidth,screenHeight);
// Virtual Camera setup
VirtualCamera* vCamera = new VirtualCamera(camera);
// OpenCV camera
osg::Camera* backgroundCamera = bgCamera.createCamera(textureWidth, textureHeight);
osg::Group* glassesGroup = new osg::Group();
// Position of glass
osg::PositionAttitudeTransform* position = new osg::PositionAttitudeTransform();
glassesGroup->addChild(position);
position->addChild(glassModel);
// Set Position of Model
position->setPosition(modelPosition);
// Set Scale of Model
position->setScale(modelScale);
// Create new group node
osg::ref_ptr<osg::Group> group = new osg::Group;
osg::Node* background = backgroundCamera;
osg::Node* foreground = glassesGroup;
background->getOrCreateStateSet()->setRenderBinDetails(1,"RenderBin");
foreground->getOrCreateStateSet()->setRenderBinDetails(2,"RenderBin");
group->addChild(background);
group->addChild(foreground);
background->getOrCreateStateSet()->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
foreground->getOrCreateStateSet()->setMode(GL_DEPTH_TEST,osg::StateAttribute::ON);
// Add the groud to the viewer
viewer.setSceneData(group.get());
if(!cap.isOpened())
{
std::cout << "Webcam cannot open!\n";
return 0;
}
while (!viewer.done())
{
// Refresh Background Image
cv::Mat frame;
faceStruct.frame = frame;
cap.read(frame);
// bgCamera.update(frame);
// Update Virtual Camera (these Coordinates should be determined by some AR-Framework/Functionality)
// They are just updated for demonstration purposes..
// Position Parameters: Roll, Pitch, Heading, X, Y, Z
// vCamera->updatePosition(0, 0, 0, 0, 0, 0);
//osg::notify(osg::WARN)<<"Angle: "<< angleRoll <<std::endl;
vector<Rect> faces;
// // Convert frame to grayscale because
// // faceDetector requires grayscale image.
cvtColor(frame, gray, COLOR_BGR2GRAY);
// // Detect faces
// const int scale = 3;
// cv::Mat frame_gray( cvRound( gray.rows / scale ), cvRound( gray.cols / scale ), CV_8UC1 );
// cv::resize( gray, frame_gray, frame_gray.size() );
faceDetector.detectMultiScale(gray, faces, 1.05 , 6, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
vector< vector<Point2f> > landmarks;
// // Run landmark detector
bool success = facemark->fit(frame, faces, landmarks);
if(success){
// eyes = drawLandmarks(frame, landmarks[0]);
vCamera->updatePosition(0, 0, 0, 0, 0, 0);
}
// Display results
// flip(frame, frame, +1);
// vCamera->updatePosition(0, 0, 0, 0, 0, 0);
bgCamera.update(frame);
viewer.frame();
}
return 0;
}