Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / MFC

Face Detection C++ Library with Skin and Motion Analysis

Rate me:
Please Sign up or sign in to vote.
4.92/5 (242 votes)
16 Jan 2008GPL319 min read 1.1M   70.8K   744  
The article demonstrates face detection SSE optimized C++ library for color and gray scale data with skin detection, motion estimation for faster processing, small sized SVM and NN rough face prefiltering, PCA/LDA/ICA/any dimensionality reduction/projection and final NN classification

#include "stdafx.h"
#include "annetwork.h"
#include "annlayer.h"
#include "vec2d.h"



//////////////////////////////////////////////////constructor/destructor////////////////////////////////////////////////////////
ANNetwork::ANNetwork(const wchar_t* fname) : m_status(-1),
                m_nrule(0.2f), m_alpha(0.7f),
                m_input_vec(0), m_add_vec(0), m_mul_vec(0)
{
        int res = 0;
        unsigned int neurons_num = 0;
        float w = 0.0f;
        unsigned int layers_num = 0;

        FILE* fp = _wfopen(fname, L"rt");
        if (fp != 0) {

                //get num of layers////////////////////////////////////
                if ((res = fwscanf(fp, L"%d", &layers_num)) != 1) {
                        fclose(fp);
                        m_status = -1;
                        return;
                }

                m_neurons.resize(layers_num);

                //get num of Neurons per layer/////////////////////////
                for (unsigned int l = 0; l < layers_num; l++) {
                        if ((res = fwscanf(fp, L"%d", &neurons_num)) != 1) {
                                fclose(fp);
                                m_status = -2;
                                return;
                        } else
                                m_neurons[l] = neurons_num;
                }
                for (unsigned int l = 0; l < layers_num - 1; l++)
                        m_layers.push_back(new AnnLayer(m_neurons[l] + 1, m_neurons[l+1]));


                //activation function for hidden/output layers/////////////////////
                if ((res = fwscanf(fp, L"%d %d", &m_actfun[0], &m_actfun[1])) != 2) {
                        m_actfun[0] = AnnLayer::LINEAR;
                        m_actfun[1] = AnnLayer::SIGMOID;
                }


                //normalization params////////////////////////////////////////////
                m_add_vec = new vec2D(1, m_neurons[0]);
                m_mul_vec = new vec2D(1, m_neurons[0]);
                m_input_vec = new vec2D(1, m_neurons[0]);

                for (unsigned int n = 0; n < m_neurons[0]; n++) {
                        float add, mul;
                        if ((res = fwscanf(fp, L"%f %f", &add, &mul)) != 2) {       //blank network file?
                                for (unsigned int m = 0; m < m_neurons[0]; m++) {
                                        (*m_add_vec)[m] = 0.0f;   //default add = 0
                                        (*m_mul_vec)[m] = 1.0f;   //default mult = 1
                                }
                                break;
                        }
                        (*m_add_vec)[n] = add;
                        (*m_mul_vec)[n] = mul;
                }


                //load weights/////////////////////////////////////////////////////
                for (unsigned int l = 0; l < m_layers.size(); l++) {         //load all weights except input layer
                        vec2D& tW = *m_layers[l]->m_tW;
                        for (unsigned int n = 0; n < tW.height(); n++) {       //num of Neurons in layer
                                for (unsigned int i = 0; i < tW.width(); i++) {      //num of inputs in Neuron
                                        if ((res = fwscanf(fp, L"%f", &w)) != 1) {        //blank network file?
                                                fclose(fp);
                                                m_status = 1;
                                                init_weights((unsigned int)time(0));   //init to random values
                                                return;
                                        } else {
                                                tW(n, i) = w;                                                
                                        }
                                }
                        }
                }

                fclose(fp);
                m_status = 0;
        } else
                m_status = -1;
}

ANNetwork::~ANNetwork()
{
        if (m_input_vec)
                delete m_input_vec;
        if (m_add_vec)
                delete m_add_vec;
        if (m_mul_vec)
                delete m_mul_vec;

        for (unsigned int l = 0; l < m_layers.size(); l++)        //delete layers
                delete m_layers[l];
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////init neuron weights///////////////////////////////////////////////////////
void ANNetwork::init_weights(unsigned int rseed) const
{
        int w;
        srand(rseed);

        //input layer remains with w=1.0
        for (unsigned int l = 0; l < m_layers.size(); l++) {
                vec2D& tW = *m_layers[l]->m_tW;
                for (unsigned int n = 0; n < tW.height(); n++) {
                        for (unsigned int i = 0; i < tW.width(); i++) {
                                w = 0xFFF & rand();
                                w -= 0x800;
                                tW(n, i) = (float)w / 2048.0f;                                
                        }
                }
        }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////run network////////////////////////////////////////////////////////////////
void ANNetwork::classify(const float* ivec, float* ovec) const
{
        //normalize input Xout = (Xin + add) * mul
        *m_input_vec = ivec;
        m_input_vec->add(*m_input_vec, *m_add_vec);                 //input = input .+ add
        m_input_vec->mule(*m_input_vec, *m_mul_vec);                //input = input .* mul
        m_layers[0]->set_input(*m_input_vec, m_actfun[0]);          //copy m_input_vec to layer[0]->inputs[1:size-1],  0-bias

        //m_layers[0]->get_input().print();
        //hidden layers
        for (unsigned int l = 0; l < m_layers.size(); l++) {
                AnnLayer* pnext = 0;
                if (l + 1 < m_layers.size())
                        pnext = m_layers[l+1];
                m_layers[l]->run(m_actfun[1], pnext);
        }

        //output layer
        m_layers[m_layers.size()-1]->get_output(ovec, m_actfun[1]);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ANNetwork::saveWs(bool file) const
{
        FILE* fp;
        wchar_t fname[256] = L"";

        for (unsigned int i = 0; i < m_layers.size(); i++) {
                swprintf(fname, L"W%d.txt", i + 1);
                if (file && (fp = _wfopen(fname, L"wt"))) {
                        const vec2D &tW = *m_layers[i]->m_tW;
                        for (unsigned int x = 0; x < tW.width(); x++) {
                                for (unsigned int y = 0; y < tW.height(); y++)
                                        fwprintf(fp, L" %f", tW(y, x));
                                fwprintf(fp, L"\n");
                        }
                        fclose(fp);
                } else {
                        const vec2D& tW = *m_layers[i]->m_tW;
                        wprintf(L"W%d %dx%d\n", i + 1, tW.width(), tW.height());
                        for (unsigned int x = 0; x < tW.width(); x++) {
                                for (unsigned int y = 0; y < tW.height(); y++)
                                        wprintf(L" %8.4f", tW(y, x));
                                wprintf(L"\n");
                        }
                }
        }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Engineer
Russian Federation Russian Federation
Highly skilled Engineer with 14 years of experience in academia, R&D and commercial product development supporting full software life-cycle from idea to implementation and further support. During my academic career I was able to succeed in MIT Computers in Cardiology 2006 international challenge, as a R&D and SW engineer gain CodeProject MVP, find algorithmic solutions to quickly resolve tough customer problems to pass product requirements in tight deadlines. My key areas of expertise involve Object-Oriented
Analysis and Design OOAD, OOP, machine learning, natural language processing, face recognition, computer vision and image processing, wavelet analysis, digital signal processing in cardiology.

Comments and Discussions