aboutsummaryrefslogtreecommitdiff
path: root/pix_linNN/pix_linNN.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pix_linNN/pix_linNN.cpp')
-rwxr-xr-xpix_linNN/pix_linNN.cpp541
1 files changed, 541 insertions, 0 deletions
diff --git a/pix_linNN/pix_linNN.cpp b/pix_linNN/pix_linNN.cpp
new file mode 100755
index 0000000..515a6a2
--- /dev/null
+++ b/pix_linNN/pix_linNN.cpp
@@ -0,0 +1,541 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// GEM - Graphics Environment for Multimedia
+//
+// pix_linNN
+//
+// Implementation file
+//
+// Copyright (c) 2004 Georg Holzmann <grh@gmx.at>
+// (and of course lot's of other developers for PD and GEM)
+//
+// For information on usage and redistribution, and for a DISCLAIMER OF ALL
+// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "pix_linNN.h"
+
+CPPEXTERN_NEW_WITH_TWO_ARGS(pix_linNN, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT)
+
+//----------------------------------------------------------
+/* Constructor
+ */
+ pix_linNN::pix_linNN(t_floatarg arg0=64, t_floatarg arg1=1) :
+ m_data_(NULL), m_xsize_(0), m_ysize_(0), m_csize_(0),
+ train_on_(false), net_(NULL)
+{
+ // init args ?????????????????????????????????
+ neuron_nr_=2048; //static_cast<int>((arg0<0)?2:arg0);
+ precision_=2; //static_cast<int>((arg1<1)?1:arg1);
+ //post("arg0: %d, arg1: %d",arg0,arg1);
+
+ // generate the in- and outlet:
+ out0_ = outlet_new(this->x_obj, &s_signal);
+ inlet_new(this->x_obj, &this->x_obj->ob_pd, &s_signal, &s_signal);
+
+ // set random seed:
+ srand( (unsigned)time(NULL) );
+
+ // creates the nets
+ net_ = new LinNeuralNet[neuron_nr_](3);
+ if(!net_)
+ {
+ post("pix_linNN~: no memory for neural nets!");
+ return;
+ }
+
+ for(int i=0; i<neuron_nr_; i++)
+ {
+ if( !net_[i].createNeurons() )
+ {
+ post("pix_linNN~: error in creating the net!");
+ return;
+ }
+ if( !net_[i].initNetworkRand(-1,1) )
+ {
+ post("pix_linNN~: error in initializing the net!");
+ return;
+ }
+
+ net_[i].setRange(255);
+ net_[i].setLearningRate(0.01);
+ }
+}
+
+//----------------------------------------------------------
+/* Destructor
+ */
+pix_linNN::~pix_linNN()
+{
+ outlet_free(out0_);
+ m_data_ = NULL;
+ m_xsize_ = 0;
+ m_ysize_ = 0;
+
+ // delete weight matrix and bias vector
+ delete[] net_;
+}
+
+//----------------------------------------------------------
+/* processImage
+ */
+void pix_linNN::processImage(imageStruct &image)
+{
+ m_data_ = image.data;
+ m_xsize_ = image.xsize;
+ m_ysize_ = image.ysize;
+ m_csize_ = image.csize;
+ m_format_ = image.format;
+}
+
+//----------------------------------------------------------
+/* DSP perform
+ */
+t_int* pix_linNN::perform(t_int* w)
+{
+ pix_linNN *x = GetMyClass((void*)w[1]);
+ t_float* in_signal = (t_float*)(w[2]);
+ t_float* out_signal = (t_float*)(w[3]);
+ int blocksize = (t_int)(w[4]);
+
+ if(blocksize != x->neuron_nr_)
+ {
+ post("pix_linNN~: neurons and buffersize are different! You MUST have the same neuron nr as the buffersize !!!");
+ post("neurons: %d, buffersize: %d", x->neuron_nr_, blocksize);
+ return (w+5);
+ }
+
+
+ // some needed data
+ long int pix_size = x->m_xsize_ * x->m_ysize_;
+ int pix_blocksize = (blocksize<pix_size)?blocksize:pix_size;
+
+ // splits the frame into slices, so that the average
+ // of one slice can be used for the network input
+ // there are as much slices as the buffsize is
+
+ float nr = sqrt(blocksize); // the number of slices at the
+ // x- and y-axis
+
+ float x_slice = x->m_xsize_ / nr; // x size of a slice in pixels
+ float y_slice = x->m_ysize_ / nr; // x size of a slice in pixels
+ int x_slice_int = static_cast<int>( x_slice );
+ int y_slice_int = static_cast<int>( y_slice );
+
+ // the number of slices on one axis (is the float nr
+ // from above rounded up)
+ int slice_nr = static_cast<int>(nr) + 1;
+
+ if (x->m_data_)
+ {
+ switch(x->m_format_)
+ {
+ case GL_RGBA:
+ for(int n=0; n<pix_blocksize; n++)
+ {
+ //post("Block %d:",n);
+
+ // calulate the pixel in left upper edge of every slice
+ int lu_pix_x = static_cast<int>( (n % slice_nr) * x_slice );
+ int lu_pix_y = static_cast<int>( static_cast<int>(n / slice_nr) * y_slice );
+
+ //post("lu_pix: %d, %d", lu_pix_x, lu_pix_y);
+
+ // now sum up all the pixels of one slice and then divide through the
+ // number of pixels
+ unsigned long int temp_data[3] = { 0, 0, 0 }; // the storage to sum the pixels
+ t_float average_pix[3] = { 0, 0, 0 }; // the average of the pixels
+
+ // only for optimization:
+ int helper1 = x->m_xsize_ * x->m_csize_;
+ int add_count = 0;
+
+ for(int i=0; i<x_slice_int; i+=x->precision_)
+ {
+ for(int j=0; j<y_slice_int; j+=x->precision_)
+ {
+ // the way to access the pixels: (C=chRed, chBlue, ...)
+ //data[Y * xsize * csize + X * csize + C]
+
+ //post("current pixel: %d %d",
+ // ((lu_pix_x+i)%x->m_xsize), ((lu_pix_y+j)%x->m_ysize) );
+
+ temp_data[0] += x->m_data_[
+ (lu_pix_y+j) * helper1
+ + (lu_pix_x+i) * x->m_csize_ + chRed ];
+
+ temp_data[1] += x->m_data_[
+ ((lu_pix_y+j)) * helper1
+ + ((lu_pix_x+i)) * x->m_csize_ + chGreen ];
+
+ temp_data[2] += x->m_data_[
+ ((lu_pix_y+j)%x->m_ysize_) * helper1
+ + ((lu_pix_x+i)%x->m_xsize_) * x->m_csize_ + chBlue ];
+
+ add_count++;
+ }
+ }
+ average_pix[0] = temp_data[0] / add_count;
+ average_pix[1] = temp_data[1] / add_count;
+ average_pix[2] = temp_data[2] / add_count;
+
+ // the calculation of the network:
+ *out_signal = x->net_[n].calculateNet(average_pix);
+
+ //post("%d: RGBav: %f %f %f, out_signal: %f",
+ //n,average_pix[0],average_pix[1],average_pix[2],*out_signal);
+
+ // learning:
+ if(x->train_on_)
+ x->net_[n].trainNet(average_pix, *out_signal, *in_signal);
+
+ out_signal++;
+ in_signal++;
+ }
+ break;
+ default:
+ post("RGB only for now");
+ }
+ }
+ else
+ {
+ pix_blocksize=blocksize;
+ while (pix_blocksize--) *out_signal++=0;
+ }
+
+ x->train_on_=false;
+ return (w+5);
+}
+
+//----------------------------------------------------------
+/* DSP-Message
+ */
+void pix_linNN::dspMess(void *data, t_signal** sp)
+{
+ dsp_add(perform, 4, data, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+//----------------------------------------------------------
+/* saves the contents of the current net to file
+ * (it saves the neuron_nr_, learning rate
+ * IW-matrix and b1-vector of the net)
+ */
+void pix_linNN::saveNet(string filename)
+{
+ // open and check outfile
+ ofstream outfile;
+ outfile.open(filename.c_str());
+ if(!outfile)
+ {
+ post("pix_linNN~: failed to open output-file!");
+ return;
+ }
+
+ // write XML-header
+ outfile << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>" << endl;
+
+ // start-tag
+ outfile << "<linNN>" << endl;
+
+ // neuron_nr_(=size) and learning rate
+ outfile << "\t<neurons> " << neuron_nr_ << " </neurons>" << endl;
+ outfile << "\t<learnrate> " << net_[0].getLearningRate()
+ << " </learnrate>" << endl;
+
+ // now the IW-matrix of the neural net
+ outfile << "\t<IW>" << endl;
+ for(int i=0; i<neuron_nr_; i++)
+ {
+ outfile << "\t\t" << net_[i].getIW()[0] << " "
+ << net_[i].getIW()[1] << " "
+ << net_[i].getIW()[2] << endl;
+ }
+ outfile << "\t</IW>" << endl;
+
+ // and the b1-vector
+ outfile << "\t<b1>" << endl << "\t\t";
+ for(int i=0; i<neuron_nr_; i++)
+ {
+ outfile << net_[i].getb1() << " ";
+ }
+ outfile << endl << "\t</b1>" << endl;
+
+ // end-tag
+ outfile << "</linNN>" << endl;
+
+
+ outfile.close();
+ post("pix_linNN~: saved to output-file %s", filename.c_str());
+ return;
+}
+
+//----------------------------------------------------------
+/* loads the parameters of the net from file
+ * (it loads the neuron_nr_, learning rate
+ * IW-matrix and b1-vector of the net)
+ */
+void pix_linNN::loadNet(string filename)
+{
+ // temp variables
+ float IW[3];
+ float b1, learnrate;
+
+ ifstream infile;
+ infile.open(filename.c_str());
+
+ if(!infile)
+ {
+ post("pix_linNN~: cannot open input-file!");
+ return;
+ }
+
+ post("pix_linNN~: loading input-file %s",filename.c_str());
+
+ int state = 0, IWcount = 0, b1count = 0;
+ bool tag=false;
+ string line, temp;
+
+ while (getline(infile, line))
+ {
+ istringstream instream(line);
+ instream >> temp;
+
+ // specify the tags
+ //post("input: %s",temp.c_str());
+ if( temp == "<neurons>" )
+ {state=1; }
+ if( temp == "<learnrate>" )
+ {state=2; }
+ if( temp == "<IW>" )
+ {state=3; }
+ if( temp == "<b1>" )
+ {state=4; }
+ if( !strncmp(temp.c_str(),"</",2) )
+ {state=0;}
+
+ if( !strncmp(temp.c_str(),"<",1) )
+ {tag=true; }
+ else
+ {tag=false; }
+
+ // make string stream again
+ instream.str(line);
+ if(tag)
+ instream >> temp; // if theres a tag, stream it
+
+
+ bool go_on=false;
+ while(!go_on)
+ {
+ // end of a line
+ if(instream.eof() || !state)
+ {
+ go_on=true;
+ break;
+ }
+
+
+ // <neuron>
+ if(state == 1)
+ {
+ instream >> neuron_nr_;
+ if(!net_)
+ {
+ // creates new nets
+ net_ = new LinNeuralNet[neuron_nr_](3);
+ if(!net_)
+ {
+ post("pix_linNN~: no memory for neural nets!");
+ break;
+ }
+ }
+ for(int i=0; i<neuron_nr_; i++)
+ {
+ if( !net_[i].createNeurons() )
+ {
+ post("pix_linNN~: error in creating the net!");
+ break;
+ }
+ }
+
+ go_on=false;
+ break;
+ }
+
+ // <learnrate>
+ if(state == 2)
+ {
+ instream >> learnrate;
+
+ for(int i=0; i<neuron_nr_; i++)
+ net_[i].setLearningRate(learnrate);
+
+ go_on=false;
+ break;
+ }
+
+ // <IW>
+ if(state == 3)
+ {
+ instream >> IW[0];
+ instream >> IW[1];
+ instream >> IW[2];
+
+ if(IWcount<neuron_nr_)
+ net_[IWcount++].setIW(IW);
+ else
+ {
+ go_on = false;
+ break;
+ }
+ }
+
+ // <b1>
+ if(state == 4)
+ {
+ for(int i=0; i<neuron_nr_; i++)
+ {
+ instream >> b1;
+ net_[b1count++].setb1(b1);
+ }
+
+ go_on = false;
+ break;
+ }
+
+ //else:
+ go_on=false;
+ break;
+ }
+ }
+
+ infile.close();
+ return;
+}
+
+//----------------------------------------------------------
+/* setup callback
+ */
+void pix_linNN::obj_setupCallback(t_class *classPtr)
+{
+ class_addcreator((t_newmethod)_classpix_linNN, gensym("pix_linNN~"), A_NULL);
+
+ class_addmethod(classPtr, (t_method)pix_linNN::setNeurons,
+ gensym("neurons"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::getNeurons,
+ gensym("getneurons"), A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::setPrecision,
+ gensym("precision"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::getPrecision,
+ gensym("getprecision"), A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::setTrainOn,
+ gensym("train"), A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::setLearnrate,
+ gensym("learnrate"), A_FLOAT, A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::getLearnrate,
+ gensym("getlearnrate"), A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::saveToFile,
+ gensym("save"), A_SYMBOL, A_NULL);
+ class_addmethod(classPtr, (t_method)pix_linNN::loadFromFile,
+ gensym("load"), A_SYMBOL, A_NULL);
+
+ class_addmethod(classPtr, (t_method)pix_linNN::dspMessCallback,
+ gensym("dsp"), A_NULL);
+ class_addmethod(classPtr, nullfn, gensym("signal"), A_NULL);
+}
+
+//----------------------------------------------------------
+/* DSP callback
+ */
+void pix_linNN::dspMessCallback(void *data, t_signal** sp)
+{
+ GetMyClass(data)->dspMess(data, sp);
+}
+
+//----------------------------------------------------------
+/* sets the precision
+ */
+void pix_linNN::setPrecision(void *data, t_floatarg precision)
+{
+ GetMyClass(data)->precision_ =
+ (precision<1) ? 1 : static_cast<int>(precision);
+}
+void pix_linNN::getPrecision(void *data)
+{
+ post("pix_linNN~: precision: %d",GetMyClass(data)->precision_);
+}
+
+//----------------------------------------------------------
+/* method to train the network
+ */
+void pix_linNN::setTrainOn(void *data)
+{
+ GetMyClass(data)->train_on_ = true;
+}
+
+//----------------------------------------------------------
+/* changes the number of neurons
+ * (which should be the same as the audio buffer)
+ * ATTENTION: a new IW-matrix and b1-vector will be initialized
+ */
+void pix_linNN::setNeurons(void *data, t_floatarg neurons)
+{
+ GetMyClass(data)->neuron_nr_ =
+ (neurons<1) ? 1 : static_cast<int>(neurons);
+
+ if(GetMyClass(data)->net_)
+ delete[] GetMyClass(data)->net_;
+
+ // creates the nets
+ GetMyClass(data)->net_ = new LinNeuralNet[GetMyClass(data)->neuron_nr_](3);
+ if(!GetMyClass(data)->net_)
+ {
+ post("pix_linNN~: no memory for neural nets!");
+ return;
+ }
+
+ for(int i=0; i<GetMyClass(data)->neuron_nr_; i++)
+ {
+ if( !GetMyClass(data)->net_[i].createNeurons() )
+ {
+ post("pix_linNN~: error in creating the net!");
+ return;
+ }
+ if( !GetMyClass(data)->net_[i].initNetworkRand(-1,1) )
+ {
+ post("pix_linNN~: error in initializing the net!");
+ return;
+ }
+ }
+}
+void pix_linNN::getNeurons(void *data)
+{
+ post("pix_linNN~: nr of neurons: %d (MUST be the same as buffersize!)",
+ GetMyClass(data)->neuron_nr_);
+}
+
+//----------------------------------------------------------
+/* sets the learnrate of the net
+ */
+void pix_linNN::setLearnrate(void *data, t_floatarg learn_rate)
+{
+ for(int i=0; i<GetMyClass(data)->neuron_nr_; i++)
+ GetMyClass(data)->net_[i].setLearningRate(learn_rate);
+}
+void pix_linNN::getLearnrate(void *data)
+{
+ post("pix_linNN~: learning rate: %f",GetMyClass(data)->net_[0].getLearningRate());
+}
+
+//----------------------------------------------------------
+/* FileIO-stuff
+ */
+void pix_linNN::saveToFile(void *data, t_symbol *filename)
+{
+ GetMyClass(data)->saveNet(filename->s_name);
+}
+void pix_linNN::loadFromFile(void *data, t_symbol *filename)
+{
+ GetMyClass(data)->loadNet(filename->s_name);
+}