iSpike
2.1
Spike conversion library for robotics
|
00001 //iSpike includes 00002 #include <iSpike/Channel/InputChannel/VisualInputChannel.hpp> 00003 #include <iSpike/ISpikeException.hpp> 00004 #include <iSpike/Log/Log.hpp> 00005 using namespace ispike; 00006 00007 //Names of properties 00008 #define NEURON_WIDTH_NAME "Neuron Width" 00009 #define NEURON_HEIGHT_NAME "Neuron Height" 00010 #define FOVEA_RADIUS_NAME "Fovea Radius" 00011 #define POSITIVE_SIGMA_NAME "Positive Sigma" 00012 #define NEGATIVE_SIGMA_NAME "Negative Sigma" 00013 #define POSITIVE_FACTOR_NAME "Positive Factor" 00014 #define NEGATIVE_FACTOR_NAME "Negative Factor" 00015 #define OPPONENCY_MAP_NAME "Opponency Map" 00016 #define PARAM_A_NAME "Parameter A" 00017 #define PARAM_B_NAME "Parameter B" 00018 #define PARAM_C_NAME "Parameter C" 00019 #define PARAM_D_NAME "Parameter D" 00020 #define CURRENT_FACTOR_NAME "Current Factor" 00021 #define CONSTANT_CURRENT_NAME "Constant Current" 00022 00023 00025 VisualInputChannel::VisualInputChannel() { 00026 // Properties of log polar foveation 00027 addProperty(Property(Property::Integer, 50, NEURON_WIDTH_NAME, "Width of the neuron network", true)); 00028 addProperty(Property(Property::Integer, 50, NEURON_HEIGHT_NAME, "Height of the neuron network", true)); 00029 addProperty(Property(Property::Double, 20.0, FOVEA_RADIUS_NAME, "Radius of the central foveated area", true)); 00030 00031 //Properties of the difference of gaussians filter 00032 addProperty(Property(Property::Double, 2.0, POSITIVE_SIGMA_NAME, "Positive Gaussian Sigma", false)); 00033 addProperty(Property(Property::Double, 4.0, NEGATIVE_SIGMA_NAME, "Negative Gaussian Sigma", false)); 00034 addProperty(Property(Property::Double, 4.0, POSITIVE_FACTOR_NAME, "Multiplication ratio for positive image during subtraction", false)); 00035 addProperty(Property(Property::Double, 2.0, NEGATIVE_FACTOR_NAME, "Multiplication ratio for negative image during subtraction", false)); 00036 vector<string> tmpVector; 00037 tmpVector.push_back("R+G-"); 00038 tmpVector.push_back("G+R-"); 00039 tmpVector.push_back("B+Y-"); 00040 tmpVector.push_back("B&W+B&W-"); 00041 tmpVector.push_back("Motion sensitive"); 00042 tmpVector.push_back("Motion sensitive with log"); 00043 addProperty(Property("R+G-", tmpVector, OPPONENCY_MAP_NAME, "Which opponency map to use.", true)); 00044 00045 //Properties of the neural simulator 00046 addProperty(Property(Property::Double, 0.1, PARAM_A_NAME, "Parameter A of the Izhikevich Neuron Model", false)); 00047 addProperty(Property(Property::Double, 0.2, PARAM_B_NAME,"Parameter B of the Izhikevich Neuron Model",false)); 00048 addProperty(Property(Property::Double, -65, PARAM_C_NAME,"Parameter C of the Izhikevich Neuron Model",false)); 00049 addProperty(Property(Property::Double, 2.0, PARAM_D_NAME, "Parameter D of the Izhikevich Neuron Model",false)); 00050 addProperty(Property(Property::Double, 10.0, CURRENT_FACTOR_NAME, "Incoming current is multiplied by this value",false)); 00051 addProperty(Property(Property::Double, 0.0, CONSTANT_CURRENT_NAME, "This value is added to the incoming current", false)); 00052 00053 //Create the description 00054 channelDescription = Description("Visual Input Channel", "This is a visual input channel", "Visual Reader"); 00055 00056 //Set up visual processing classes and neural simulator 00057 dataReducer = new LogPolarVisualDataReducer(); 00058 dogFilter = new DOGVisualFilter(dataReducer); 00059 00060 //Initialize variables 00061 reader = NULL; 00062 currentImageID = 0; 00063 } 00064 00065 00067 VisualInputChannel::~VisualInputChannel() { 00068 if(isInitialized()) { 00069 delete reader; 00070 delete dogFilter; 00071 delete dataReducer; 00072 } 00073 } 00074 00075 00076 /*--------------------------------------------------------------------*/ 00077 /*--------- PUBLIC METHODS -------*/ 00078 /*--------------------------------------------------------------------*/ 00079 00081 void VisualInputChannel::initialize(Reader* reader, map<string,Property>& properties) { 00082 //This class requires a visual reader, so reinterpret it and check 00083 this->reader = dynamic_cast<VisualReader*>(reader); 00084 if(this->reader == NULL) 00085 throw ISpikeException("Cannot initialize VisualInputChannel with a null reader."); 00086 00087 //Store properties in this and dependent classes 00088 updateProperties(properties); 00089 00090 //Start the reader thread running 00091 this->reader->start(); 00092 00093 //Initialize neural simulator 00094 neuronSim.initialize(size()); 00095 00096 setInitialized(true); 00097 } 00098 00099 00101 void VisualInputChannel::setProperties(map<string,Property>& properties){ 00102 updateProperties(properties); 00103 } 00104 00105 00106 //Inherited from Channel 00107 void VisualInputChannel::step() { 00108 //Check reader for errors 00109 if(reader->isError()){ 00110 LOG(LOG_CRITICAL)<<"AngleReader Error: "<<reader->getErrorMessage(); 00111 throw ISpikeException("Error in AngleReader"); 00112 } 00113 00114 //Update visual maps if necessary 00115 if(reader->getImageID() != currentImageID){ 00116 currentImageID = reader->getImageID(); 00117 dataReducer->setBitmap(reader->getBitmap()); 00118 dogFilter->update(); 00119 } 00120 00121 //Multiplication factor combines the current factor with the size of the value used to store the pixel 00122 double multFactor = currentFactor/ 255.0; 00123 00124 //Load opponency data into neural simulator 00125 Bitmap& opponencyMap = dogFilter->getBitmap(); 00126 if(!opponencyMap.isEmpty()) { 00127 //Get reference to opponency map 00128 int opponencyMapSize = opponencyMap.size(); 00129 unsigned char* opponencyMapContents = opponencyMap.getContents(); 00130 00131 if(opponencyMapSize != size()) 00132 throw ISpikeException("VisualInputChannel: Incoming map size does not match size of visual channel"); 00133 00134 //Convert pixels to currents in simulator 00135 for(int i=0; i<opponencyMapSize; ++i){ 00136 //Set the input current to the neurons 00137 //LOG(LOG_DEBUG)<<"INPUT CURRENT: "<<(multFactor * opponencyMapContents[i] + constantCurrent); 00138 neuronSim.setInputCurrent(i, multFactor * opponencyMapContents[i] + constantCurrent); 00139 } 00140 } 00141 00142 //Step the simulator 00143 neuronSim.step(); 00144 } 00145 00146 00147 /*--------------------------------------------------------------------*/ 00148 /*--------- PROTECTED METHODS -------*/ 00149 /*--------------------------------------------------------------------*/ 00150 00152 void VisualInputChannel::updateProperties(map<string, Property>& properties) { 00153 if(propertyMap.size() != properties.size()) 00154 throw ISpikeException("VisualInputChannel: Current properties do not match new properties."); 00155 00156 //Update properties in the property map and the appropriate class 00157 updatePropertyCount = 0; 00158 for(map<string,Property>::iterator iter = properties.begin(); iter != properties.end(); ++iter) { 00159 //When initialized, only update properties that are not read only 00160 if( (isInitialized() && !iter->second.isReadOnly()) || !isInitialized()) { 00161 string paramName = iter->second.getName(); 00162 switch (iter->second.getType()){ 00163 case Property::Integer: { 00164 if (paramName == NEURON_WIDTH_NAME){ 00165 setWidth(updateIntegerProperty(iter->second)); 00166 dataReducer->setOutputWidth(getWidth()); 00167 } 00168 else if (paramName == NEURON_HEIGHT_NAME){ 00169 setHeight(updateIntegerProperty(iter->second)); 00170 dataReducer->setOutputHeight(getHeight()); 00171 } 00172 break; 00173 } 00174 case Property::Double: { 00175 if (paramName == PARAM_A_NAME) 00176 neuronSim.setParameterA(updateDoubleProperty(iter->second)); 00177 else if (paramName == PARAM_B_NAME) 00178 neuronSim.setParameterB(updateDoubleProperty(iter->second)); 00179 else if (paramName == PARAM_C_NAME) 00180 neuronSim.setParameterC(updateDoubleProperty(iter->second)); 00181 else if (paramName == PARAM_D_NAME) 00182 neuronSim.setParameterD(updateDoubleProperty(iter->second)); 00183 else if (paramName == CURRENT_FACTOR_NAME) 00184 currentFactor = updateDoubleProperty(iter->second); 00185 else if (paramName == CONSTANT_CURRENT_NAME) 00186 constantCurrent = updateDoubleProperty(iter->second); 00187 else if (paramName == POSITIVE_SIGMA_NAME) 00188 dogFilter->setPositiveSigma(updateDoubleProperty(iter->second)); 00189 else if (paramName == NEGATIVE_SIGMA_NAME) 00190 dogFilter->setNegativeSigma(updateDoubleProperty(iter->second)); 00191 else if (paramName == POSITIVE_FACTOR_NAME) 00192 dogFilter->setPositiveFactor(updateDoubleProperty(iter->second)); 00193 else if (paramName == NEGATIVE_FACTOR_NAME) 00194 dogFilter->setNegativeFactor(updateDoubleProperty(iter->second)); 00195 else if (paramName == FOVEA_RADIUS_NAME) 00196 dataReducer->setFoveaRadius(updateDoubleProperty(iter->second)); 00197 break; 00198 } 00199 case Property::Combo: 00200 if(paramName == OPPONENCY_MAP_NAME){ 00201 string mapName = updateComboProperty(iter->second); 00202 if(mapName == "R+G-") 00203 dogFilter->setOpponencyTypeID(0); 00204 else if(mapName == "G+R-") 00205 dogFilter->setOpponencyTypeID(1); 00206 else if(mapName == "B+Y-") 00207 dogFilter->setOpponencyTypeID(2); 00208 else if(mapName == "B&W+B&W-") 00209 dogFilter->setOpponencyTypeID(3); 00210 else if(mapName == "Motion sensitive") 00211 dogFilter->setOpponencyTypeID(4); 00212 else if(mapName == "Motion sensitive with log") 00213 dogFilter->setOpponencyTypeID(5); 00214 else 00215 throw ISpikeException("VisualInputChannel: Opponency map type not recognized"); 00216 } 00217 break; 00218 case Property::String: 00219 break; 00220 default: 00221 throw ISpikeException("Property type not recognized."); 00222 } 00223 } 00224 } 00225 00226 //Check all properties were updated 00227 if(!isInitialized() && updatePropertyCount != propertyMap.size()) 00228 throw ISpikeException("Some or all of the properties were not updated: ", updatePropertyCount); 00229 } 00230