SourceEstimate MinimumNorm::calculateInverse(const FiffEvoked &p_fiffEvoked, bool pick_normal) const { // // Set up the inverse according to the parameters // qint32 nave = p_fiffEvoked.nave; if(!m_inverseOperator.check_ch_names(p_fiffEvoked.info)) { qWarning("Channel name check failed."); return SourceEstimate(); } MNEInverseOperator inv = m_inverseOperator.prepare_inverse_operator(nave, m_fLambda, m_bdSPM, m_bsLORETA); // // Pick the correct channels from the data // FiffEvoked t_fiffEvoked = p_fiffEvoked.pick_channels(inv.noise_cov->names); printf("Picked %d channels from the data\n",t_fiffEvoked.info.nchan); printf("Computing inverse..."); MatrixXd K; SparseMatrix<double> noise_norm; QList<VectorXi> vertno; Label label; inv.assemble_kernel(label, m_sMethod, pick_normal, K, noise_norm, vertno); MatrixXd sol = K * t_fiffEvoked.data; //apply imaging kernel if (inv.source_ori == FIFFV_MNE_FREE_ORI) { printf("combining the current components..."); MatrixXd sol1(sol.rows()/3,sol.cols()); for(qint32 i = 0; i < sol.cols(); ++i) { VectorXd* tmp = MNEMath::combine_xyz(sol.block(0,i,sol.rows(),1)); sol1.block(0,i,sol.rows()/3,1) = tmp->cwiseSqrt(); delete tmp; } sol.resize(sol1.rows(),sol1.cols()); sol = sol1; } if (m_bdSPM) { printf("(dSPM)..."); sol = inv.noisenorm*sol; } else if (m_bsLORETA) { printf("(sLORETA)..."); sol = inv.noisenorm*sol; } printf("[done]\n"); //Results float tmin = ((float)t_fiffEvoked.first) / t_fiffEvoked.info.sfreq; float tstep = 1/t_fiffEvoked.info.sfreq; QList<VectorXi> t_qListVertices; for(qint32 h = 0; h < inv.src.size(); ++h) t_qListVertices.push_back(inv.src[h].vertno); return SourceEstimate(sol, t_qListVertices, tmin, tstep); }
void RtAve::generateEvoked(double dTriggerType) { QMutexLocker locker(&m_qMutex); if(m_mapStimAve[dTriggerType].isEmpty()) { return; } //Init evoked FiffEvoked evoked; int iEvokedIdx = -1; for(int i = 0; i < m_pStimEvokedSet->evoked.size(); ++i) { if(m_pStimEvokedSet->evoked.at(i).comment == QString::number(dTriggerType)) { evoked = m_pStimEvokedSet->evoked.at(i); iEvokedIdx = i; break; } } //If the evoked is not yet present add it here if(iEvokedIdx == -1) { float T = 1.0/m_pFiffInfo->sfreq; evoked.setInfo(*m_pFiffInfo.data()); evoked.baseline = m_pairBaselineSec; evoked.times.resize(m_iPreStimSamples + m_iPostStimSamples); evoked.times[0] = -T*m_iPreStimSamples; for(int i = 1; i < evoked.times.size(); ++i) evoked.times[i] = evoked.times[i-1] + T; evoked.first = evoked.times[0]; evoked.last = evoked.times[evoked.times.size()-1]; evoked.comment = QString::number(dTriggerType); } // Generate final evoked MatrixXd finalAverage = MatrixXd::Zero(m_mapStimAve[dTriggerType].first().rows(), m_iPreStimSamples+m_iPostStimSamples); if(m_iAverageMode == 0) { for(int i = 0; i < m_mapStimAve[dTriggerType].size(); ++i) { finalAverage += m_mapStimAve[dTriggerType].at(i); } if(m_mapStimAve[dTriggerType].isEmpty()) { finalAverage = finalAverage/1; } else { finalAverage = finalAverage/m_mapStimAve[dTriggerType].size(); } if(m_bDoBaselineCorrection) { finalAverage = MNEMath::rescale(finalAverage, evoked.times, m_pairBaselineSec, QString("mean")); } evoked.data = finalAverage; if(m_mapNumberCalcAverages[dTriggerType] < m_iNumAverages) { m_mapNumberCalcAverages[dTriggerType]++; } evoked.nave = m_mapNumberCalcAverages[dTriggerType]; } else if(m_iAverageMode == 1) { MatrixXd tempMatrix = m_mapStimAve[dTriggerType].last(); if(m_bDoBaselineCorrection) { tempMatrix = MNEMath::rescale(tempMatrix, evoked.times, m_pairBaselineSec, QString("mean")); } evoked += tempMatrix; m_mapNumberCalcAverages[dTriggerType]++; } //Add new data to evoked data set if(iEvokedIdx != -1) { //Evoked data is already present m_pStimEvokedSet->evoked[iEvokedIdx] = evoked; } else { //Evoked data is not present yet m_pStimEvokedSet->evoked.append(evoked); } }
/** * The function main marks the entry point of the program. * By default, main has the storage class extern. * * @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started. * @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started. * @return the value that was set to exit() (which is 0 if exit() is called via quit()). */ int main(int argc, char *argv[]) { QApplication a(argc, argv); // Command Line Parser QCommandLineParser parser; parser.setApplicationDescription("Clustered Inverse Raw Example"); parser.addHelpOption(); QCommandLineOption inputOption("fileIn", "The input file <in>.", "in", "./MNE-sample-data/MEG/sample/sample_audvis_raw.fif"); QCommandLineOption surfOption("surfType", "Surface type <type>.", "type", "inflated"); QCommandLineOption annotOption("annotType", "Annotation type <type>.", "type", "aparc.a2009s"); QCommandLineOption subjectOption("subject", "Selected subject <subject>.", "subject", "sample"); QCommandLineOption subjectPathOption("subjectPath", "Selected subject path <subjectPath>.", "subjectPath", "./MNE-sample-data/subjects"); QCommandLineOption fwdOption("fwd", "Path to forwad solution <file>.", "file", "./MNE-sample-data/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif"); QCommandLineOption covFileOption("cov", "Path to the covariance <file>.", "file", "./MNE-sample-data/MEG/sample/sample_audvis-cov.fif"); QCommandLineOption evokedIndexOption("aveIdx", "The average <index> to choose from the average file.", "index", "1"); QCommandLineOption eventsFileOption("eve", "Path to the event <file>.", "file", "./MNE-sample-data/MEG/sample/sample_audvis_raw-eve.fif"); QCommandLineOption hemiOption("hemi", "Selected hemisphere <hemi>.", "hemi", "2"); QCommandLineOption methodOption("method", "Inverse estimation <method>, i.e., 'MNE', 'dSPM' or 'sLORETA'.", "method", "dSPM");//"MNE" | "dSPM" | "sLORETA" QCommandLineOption snrOption("snr", "The SNR value used for computation <snr>.", "snr", "1.0");//3.0;//0.1;//3.0; QCommandLineOption invFileOutOption("invOut", "Path to inverse <file>, which is to be written.", "file", ""); QCommandLineOption stcFileOutOption("stcOut", "Path to stc <file>, which is to be written.", "file", ""); QCommandLineOption keepCompOption("keepComp", "Keep compensators.", "keepComp", "false"); QCommandLineOption pickAllOption("pickAll", "Pick all channels.", "pickAll", "true"); QCommandLineOption destCompsOption("destComps", "<Destination> of the compensator which is to be calculated.", "destination", "0"); parser.addOption(inputOption); parser.addOption(surfOption); parser.addOption(annotOption); parser.addOption(subjectOption); parser.addOption(subjectPathOption); parser.addOption(fwdOption); parser.addOption(covFileOption); parser.addOption(evokedIndexOption); parser.addOption(eventsFileOption); parser.addOption(hemiOption); parser.addOption(methodOption); parser.addOption(snrOption); parser.addOption(invFileOutOption); parser.addOption(stcFileOutOption); parser.addOption(keepCompOption); parser.addOption(pickAllOption); parser.addOption(destCompsOption); parser.process(a); // Load files QFile t_fileFwd(parser.value(fwdOption)); QFile t_fileCov(parser.value(covFileOption)); QFile t_fileRaw(parser.value(inputOption)); QString t_sEventName = parser.value(eventsFileOption); SurfaceSet t_surfSet (parser.value(subjectOption), parser.value(hemiOption).toInt(), parser.value(surfOption), parser.value(subjectPathOption)); AnnotationSet t_annotationSet (parser.value(subjectOption), parser.value(hemiOption).toInt(), parser.value(annotOption), parser.value(subjectPathOption)); qint32 event = parser.value(evokedIndexOption).toInt(); float tmin = -0.2f; float tmax = 0.4f; bool keep_comp = false; if(parser.value(keepCompOption) == "false" || parser.value(keepCompOption) == "0") { keep_comp = false; } else if(parser.value(keepCompOption) == "true" || parser.value(keepCompOption) == "1") { keep_comp = true; } fiff_int_t dest_comp = parser.value(destCompsOption).toInt(); bool pick_all = false; if(parser.value(pickAllOption) == "false" || parser.value(pickAllOption) == "0") { pick_all = false; } else if(parser.value(pickAllOption) == "true" || parser.value(pickAllOption) == "1") { pick_all = true; } qint32 k, p; // // Setup for reading the raw data // FiffRawData raw(t_fileRaw); RowVectorXi picks; if (pick_all) { // // Pick all // picks.resize(raw.info.nchan); for(k = 0; k < raw.info.nchan; ++k) picks(k) = k; // } else { QStringList include; include << "STI 014"; bool want_meg = true; bool want_eeg = false; bool want_stim = false; // picks = Fiff::pick_types(raw.info, want_meg, want_eeg, want_stim, include, raw.info.bads); picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);//prefer member function } QStringList ch_names; for(k = 0; k < picks.cols(); ++k) ch_names << raw.info.ch_names[picks(0,k)]; // // Set up projection // if (raw.info.projs.size() == 0) printf("No projector specified for these data\n"); else { // // Activate the projection items // for (k = 0; k < raw.info.projs.size(); ++k) raw.info.projs[k].active = true; printf("%d projection items activated\n",raw.info.projs.size()); // // Create the projector // // fiff_int_t nproj = MNE::make_projector_info(raw.info, raw.proj); Using the member function instead fiff_int_t nproj = raw.info.make_projector(raw.proj); if (nproj == 0) { printf("The projection vectors do not apply to these channels\n"); } else { printf("Created an SSP operator (subspace dimension = %d)\n",nproj); } } // // Set up the CTF compensator // // qint32 current_comp = MNE::get_current_comp(raw.info); qint32 current_comp = raw.info.get_current_comp(); if (current_comp > 0) printf("Current compensation grade : %d\n",current_comp); if (keep_comp) dest_comp = current_comp; if (current_comp != dest_comp) { qDebug() << "This part needs to be debugged"; if(MNE::make_compensator(raw.info, current_comp, dest_comp, raw.comp)) { // raw.info.chs = MNE::set_current_comp(raw.info.chs,dest_comp); raw.info.set_current_comp(dest_comp); printf("Appropriate compensator added to change to grade %d.\n",dest_comp); } else { printf("Could not make the compensator\n"); return 0; } } // // Read the events // QFile t_EventFile; MatrixXi events; if (t_sEventName.size() == 0) { p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_sEventName = t_fileRaw.fileName().replace(p, 4, "-eve.fif"); } else { printf("Raw file name does not end properly\n"); return 0; } // events = mne_read_events(t_sEventName); t_EventFile.setFileName(t_sEventName); MNE::read_events(t_EventFile, events); printf("Events read from %s\n",t_sEventName.toUtf8().constData()); } else { // // Binary file // p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_EventFile.setFileName(t_sEventName); if(!MNE::read_events(t_EventFile, events)) { printf("Error while read events.\n"); return 0; } printf("Binary event file %s read\n",t_sEventName.toUtf8().constData()); } else { // // Text file // printf("Text file %s is not supported jet.\n",t_sEventName.toUtf8().constData()); // try // events = load(eventname); // catch // error(me,mne_omit_first_line(lasterr)); // end // if size(events,1) < 1 // error(me,'No data in the event file'); // end // // // // Convert time to samples if sample number is negative // // // for p = 1:size(events,1) // if events(p,1) < 0 // events(p,1) = events(p,2)*raw.info.sfreq; // end // end // // // // Select the columns of interest (convert to integers) // // // events = int32(events(:,[1 3 4])); // // // // New format? // // // if events(1,2) == 0 && events(1,3) == 0 // fprintf(1,'The text event file %s is in the new format\n',eventname); // if events(1,1) ~= raw.first_samp // error(me,'This new format event file is not compatible with the raw data'); // end // else // fprintf(1,'The text event file %s is in the old format\n',eventname); // // // // Offset with first sample // // // events(:,1) = events(:,1) + raw.first_samp; // end } } // // Select the desired events // qint32 count = 0; MatrixXi selected = MatrixXi::Zero(1, events.rows()); for (p = 0; p < events.rows(); ++p) { if (events(p,1) == 0 && events(p,2) == event) { selected(0,count) = p; ++count; } } selected.conservativeResize(1, count); if (count > 0) printf("%d matching events found\n",count); else { printf("No desired events found.\n"); return 0; } fiff_int_t event_samp, from, to; MatrixXd timesDummy; MNEEpochDataList data; MNEEpochData* epoch = NULL; MatrixXd times; for (p = 0; p < count; ++p) { // // Read a data segment // event_samp = events(selected(p),0); from = event_samp + tmin*raw.info.sfreq; to = event_samp + floor(tmax*raw.info.sfreq + 0.5); epoch = new MNEEpochData(); if(raw.read_raw_segment(epoch->epoch, timesDummy, from, to, picks)) { if (p == 0) { times.resize(1, to-from+1); for (qint32 i = 0; i < times.cols(); ++i) times(0, i) = ((float)(from-event_samp+i)) / raw.info.sfreq; } epoch->event = event; epoch->tmin = ((float)(from)-(float)(raw.first_samp))/raw.info.sfreq; epoch->tmax = ((float)(to)-(float)(raw.first_samp))/raw.info.sfreq; data.append(MNEEpochData::SPtr(epoch));//List takes ownwership of the pointer - no delete need } else { printf("Can't read the event data segments"); return 0; } } if(data.size() > 0) { printf("Read %d epochs, %d samples each.\n",data.size(),(qint32)data[0]->epoch.cols()); //DEBUG std::cout << data[0]->epoch.block(0,0,10,10) << std::endl; qDebug() << data[0]->epoch.rows() << " x " << data[0]->epoch.cols(); std::cout << times.block(0,0,1,10) << std::endl; qDebug() << times.rows() << " x " << times.cols(); } // Calculate the average // Option 1 - Random selection VectorXi vecSel(50); srand (time(NULL)); // initialize random seed for(qint32 i = 0; i < vecSel.size(); ++i) { qint32 val = rand() % count; vecSel(i) = val; } // //Option 3 - Take all epochs // VectorXi vecSel(data.size()); // for(qint32 i = 0; i < vecSel.size(); ++i) // { // vecSel(i) = i; // } // //Option 3 - Manual selection // VectorXi vecSel(20); // vecSel << 76, 74, 13, 61, 97, 94, 75, 71, 60, 56, 26, 57, 56, 0, 52, 72, 33, 86, 96, 67; std::cout << "Select following epochs to average:\n" << vecSel << std::endl; FiffEvoked evoked = data.average(raw.info, tmin*raw.info.sfreq, floor(tmax*raw.info.sfreq + 0.5), vecSel); //######################################################################################## // Source Estimate // // Settings // double snr = parser.value(snrOption).toDouble(); QString method(parser.value(methodOption)); QString t_sFileNameClusteredInv(parser.value(invFileOutOption)); QString t_sFileNameStc(parser.value(stcFileOutOption)); double lambda2 = 1.0 / pow(snr, 2); qDebug() << "Start calculation with: SNR" << snr << "; Lambda" << lambda2 << "; Method" << method << "; stc:" << t_sFileNameStc; // // Load data // MNEForwardSolution t_Fwd(t_fileFwd); if(t_Fwd.isEmpty()) return 1; FiffCov noise_cov(t_fileCov); // // regularize noise covariance // noise_cov = noise_cov.regularize(evoked.info, 0.05, 0.05, 0.1, true); // // Cluster forward solution; // MatrixXd D; MNEForwardSolution t_clusteredFwd = t_Fwd.cluster_forward_solution(t_annotationSet, 20, D, noise_cov, evoked.info); // // make an inverse operators // FiffInfo info = evoked.info; MNEInverseOperator inverse_operator(info, t_clusteredFwd, noise_cov, 0.2f, 0.8f); // // save clustered inverse // if(!t_sFileNameClusteredInv.isEmpty()) { QFile t_fileClusteredInverse(t_sFileNameClusteredInv); inverse_operator.write(t_fileClusteredInverse); } // // Compute inverse solution // MinimumNorm minimumNorm(inverse_operator, lambda2, method); #ifdef BENCHMARK // // Set up the inverse according to the parameters // minimumNorm.doInverseSetup(vecSel.size(),false); MNESourceEstimate sourceEstimate; QList<qint64> qVecElapsedTime; for(qint32 i = 0; i < 100; ++i) { //Benchmark time QElapsedTimer timer; timer.start(); sourceEstimate = minimumNorm.calculateInverse(evoked.data, evoked.times(0), evoked.times(1)-evoked.times(0)); qVecElapsedTime.append(timer.elapsed()); } double meanTime = 0.0; qint32 offset = 19; qint32 c = 0; for(qint32 i = offset; i < qVecElapsedTime.size(); ++i) { meanTime += qVecElapsedTime[i]; ++c; } meanTime /= (double)c; double varTime = 0; for(qint32 i = offset; i < qVecElapsedTime.size(); ++i) varTime += pow(qVecElapsedTime[i] - meanTime,2); varTime /= (double)c - 1.0f; varTime = sqrt(varTime); qDebug() << "MNE calculation took" << meanTime << "+-" << varTime << "ms in average"; #else MNESourceEstimate sourceEstimate = minimumNorm.calculateInverse(evoked); #endif if(sourceEstimate.isEmpty()) return 1; // View activation time-series std::cout << "\nsourceEstimate:\n" << sourceEstimate.data.block(0,0,10,10) << std::endl; std::cout << "time\n" << sourceEstimate.times.block(0,0,1,10) << std::endl; std::cout << "timeMin\n" << sourceEstimate.times[0] << std::endl; std::cout << "timeMax\n" << sourceEstimate.times[sourceEstimate.times.size()-1] << std::endl; std::cout << "time step\n" << sourceEstimate.tstep << std::endl; //Condition Numbers // MatrixXd mags(102, t_Fwd.sol->data.cols()); // qint32 count = 0; // for(qint32 i = 2; i < 306; i += 3) // { // mags.row(count) = t_Fwd.sol->data.row(i); // ++count; // } // MatrixXd magsClustered(102, t_clusteredFwd.sol->data.cols()); // count = 0; // for(qint32 i = 2; i < 306; i += 3) // { // magsClustered.row(count) = t_clusteredFwd.sol->data.row(i); // ++count; // } // MatrixXd grads(204, t_Fwd.sol->data.cols()); // count = 0; // for(qint32 i = 0; i < 306; i += 3) // { // grads.row(count) = t_Fwd.sol->data.row(i); // ++count; // grads.row(count) = t_Fwd.sol->data.row(i+1); // ++count; // } // MatrixXd gradsClustered(204, t_clusteredFwd.sol->data.cols()); // count = 0; // for(qint32 i = 0; i < 306; i += 3) // { // gradsClustered.row(count) = t_clusteredFwd.sol->data.row(i); // ++count; // gradsClustered.row(count) = t_clusteredFwd.sol->data.row(i+1); // ++count; // } VectorXd s; double t_dConditionNumber = MNEMath::getConditionNumber(t_Fwd.sol->data, s); double t_dConditionNumberClustered = MNEMath::getConditionNumber(t_clusteredFwd.sol->data, s); std::cout << "Condition Number:\n" << t_dConditionNumber << std::endl; std::cout << "Clustered Condition Number:\n" << t_dConditionNumberClustered << std::endl; std::cout << "ForwardSolution" << t_Fwd.sol->data.block(0,0,10,10) << std::endl; std::cout << "Clustered ForwardSolution" << t_clusteredFwd.sol->data.block(0,0,10,10) << std::endl; // double t_dConditionNumberMags = MNEMath::getConditionNumber(mags, s); // double t_dConditionNumberMagsClustered = MNEMath::getConditionNumber(magsClustered, s); // std::cout << "Condition Number Magnetometers:\n" << t_dConditionNumberMags << std::endl; // std::cout << "Clustered Condition Number Magnetometers:\n" << t_dConditionNumberMagsClustered << std::endl; // double t_dConditionNumberGrads = MNEMath::getConditionNumber(grads, s); // double t_dConditionNumberGradsClustered = MNEMath::getConditionNumber(gradsClustered, s); // std::cout << "Condition Number Gradiometers:\n" << t_dConditionNumberGrads << std::endl; // std::cout << "Clustered Condition Number Gradiometers:\n" << t_dConditionNumberGradsClustered << std::endl; //Source Estimate end //######################################################################################## // //only one time point - P100 // qint32 sample = 0; // for(qint32 i = 0; i < sourceEstimate.times.size(); ++i) // { // if(sourceEstimate.times(i) >= 0) // { // sample = i; // break; // } // } // sample += (qint32)ceil(0.106/sourceEstimate.tstep); //100ms // sourceEstimate = sourceEstimate.reduce(sample, 1); View3D::SPtr testWindow = View3D::SPtr(new View3D()); Data3DTreeModel::SPtr p3DDataModel = Data3DTreeModel::SPtr(new Data3DTreeModel()); testWindow->setModel(p3DDataModel); p3DDataModel->addSurfaceSet(parser.value(subjectOption), "MRI", t_surfSet, t_annotationSet); if(MneEstimateTreeItem* pRTDataItem = p3DDataModel->addSourceData(parser.value(subjectOption), evoked.comment, sourceEstimate, t_clusteredFwd)) { pRTDataItem->setLoopState(true); pRTDataItem->setTimeInterval(17); pRTDataItem->setNumberAverages(1); pRTDataItem->setStreamingActive(true); pRTDataItem->setNormalization(QVector3D(0.0,0.5,20.0)); pRTDataItem->setVisualizationType("Smoothing based"); pRTDataItem->setColortable("Hot"); } testWindow->show(); Control3DWidget::SPtr control3DWidget = Control3DWidget::SPtr(new Control3DWidget()); control3DWidget->init(p3DDataModel, testWindow); control3DWidget->show(); if(!t_sFileNameStc.isEmpty()) { QFile t_fileClusteredStc(t_sFileNameStc); sourceEstimate.write(t_fileClusteredStc); } return a.exec(); }
/** * The function main marks the entry point of the program. * By default, main has the storage class extern. * * @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started. * @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started. * @return the value that was set to exit() (which is 0 if exit() is called via quit()). */ int main(int argc, char *argv[]) { QApplication a(argc, argv); QFile t_fileRaw("./MNE-sample-data/MEG/sample/sample_audvis_raw.fif"); QString t_sEventName = "./MNE-sample-data/MEG/sample/sample_audvis_raw-eve.fif"; QFile t_fileFwd("./MNE-sample-data/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif"); AnnotationSet t_annotationSet("./MNE-sample-data/subjects/sample/label/lh.aparc.a2009s.annot", "./MNE-sample-data/subjects/sample/label/rh.aparc.a2009s.annot"); SurfaceSet t_surfSet("./MNE-sample-data/subjects/sample/surf/lh.white", "./MNE-sample-data/subjects/sample/surf/rh.white"); // QFile t_fileRaw("E:/Data/sl_data/MEG/mind006/mind006_051209_auditory01_raw.fif"); // QString t_sEventName = "E:/Data/sl_data/MEG/mind006/mind006_051209_auditory01_raw-eve.fif"; // QFile t_fileFwd("E:/Data/sl_data/MEG/mind006/mind006_051209_auditory01_raw-oct-6p-fwd.fif"); // AnnotationSet t_annotationSet("E:/Data/sl_data/subjects/mind006/label/lh.aparc.a2009s.annot", "E:/Data/sl_data/subjects/mind006/label/rh.aparc.a2009s.annot"); // SurfaceSet t_surfSet("E:/Data/sl_data/subjects/mind006/surf/lh.white", "E:/Data/sl_data/subjects/mind006/surf/rh.white"); // QFile t_fileRaw("E:/Data/sl_data/MEG/mind006/mind006_051209_median01_raw.fif"); // QString t_sEventName = "E:/Data/sl_data/MEG/mind006/mind006_051209_median01_raw-eve.fif"; // QFile t_fileFwd("E:/Data/sl_data/MEG/mind006/mind006_051209_median01_raw-oct-6-fwd.fif"); // AnnotationSet t_annotationSet("E:/Data/sl_data/subjects/mind006/label/lh.aparc.a2009s.annot", "E:/Data/sl_data/subjects/mind006/label/rh.aparc.a2009s.annot"); // SurfaceSet t_surfSet("E:/Data/sl_data/subjects/mind006/surf/lh.white", "E:/Data/sl_data/subjects/mind006/surf/rh.white"); QString t_sFileNameStc("");//("mind006_051209_auditory01.stc"); bool doMovie = false;//true; qint32 numDipolePairs = 7; qint32 event = 1; float tmin = -0.2f; float tmax = 0.4f; bool keep_comp = false; fiff_int_t dest_comp = 0; bool pick_all = true; qint32 k, p; // Parse command line parameters for(qint32 i = 0; i < argc; ++i) { if(strcmp(argv[i], "-stc") == 0 || strcmp(argv[i], "--stc") == 0) { if(i + 1 < argc) t_sFileNameStc = QString::fromUtf8(argv[i+1]); } } // // Load data // MNEForwardSolution t_Fwd(t_fileFwd); if(t_Fwd.isEmpty()) return 1; // // Setup for reading the raw data // FiffRawData raw(t_fileRaw); RowVectorXi picks; if (pick_all) { // // Pick all // picks.resize(raw.info.nchan); for(k = 0; k < raw.info.nchan; ++k) picks(k) = k; // } else { QStringList include; include << "STI 014"; bool want_meg = true; bool want_eeg = false; bool want_stim = false; picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);//prefer member function } QStringList ch_names; for(k = 0; k < picks.cols(); ++k) ch_names << raw.info.ch_names[picks(0,k)]; // // Set up projection // if (raw.info.projs.size() == 0) printf("No projector specified for these data\n"); else { // // Activate the projection items // for (k = 0; k < raw.info.projs.size(); ++k) raw.info.projs[k].active = true; printf("%d projection items activated\n",raw.info.projs.size()); // // Create the projector // // fiff_int_t nproj = MNE::make_projector_info(raw.info, raw.proj); Using the member function instead fiff_int_t nproj = raw.info.make_projector(raw.proj); if (nproj == 0) { printf("The projection vectors do not apply to these channels\n"); } else { printf("Created an SSP operator (subspace dimension = %d)\n",nproj); } } // // Set up the CTF compensator // qint32 current_comp = raw.info.get_current_comp(); if (current_comp > 0) printf("Current compensation grade : %d\n",current_comp); if (keep_comp) dest_comp = current_comp; if (current_comp != dest_comp) { qDebug() << "This part needs to be debugged"; if(MNE::make_compensator(raw.info, current_comp, dest_comp, raw.comp)) { raw.info.set_current_comp(dest_comp); printf("Appropriate compensator added to change to grade %d.\n",dest_comp); } else { printf("Could not make the compensator\n"); return 0; } } // // Read the events // QFile t_EventFile; MatrixXi events; if (t_sEventName.size() == 0) { p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_sEventName = t_fileRaw.fileName().replace(p, 4, "-eve.fif"); } else { printf("Raw file name does not end properly\n"); return 0; } // events = mne_read_events(t_sEventName); t_EventFile.setFileName(t_sEventName); MNE::read_events(t_EventFile, events); printf("Events read from %s\n",t_sEventName.toUtf8().constData()); } else { // // Binary file // p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_EventFile.setFileName(t_sEventName); if(!MNE::read_events(t_EventFile, events)) { printf("Error while read events.\n"); return 0; } printf("Binary event file %s read\n",t_sEventName.toUtf8().constData()); } else { // // Text file // printf("Text file %s is not supported jet.\n",t_sEventName.toUtf8().constData()); // try // events = load(eventname); // catch // error(me,mne_omit_first_line(lasterr)); // end // if size(events,1) < 1 // error(me,'No data in the event file'); // end // // // // Convert time to samples if sample number is negative // // // for p = 1:size(events,1) // if events(p,1) < 0 // events(p,1) = events(p,2)*raw.info.sfreq; // end // end // // // // Select the columns of interest (convert to integers) // // // events = int32(events(:,[1 3 4])); // // // // New format? // // // if events(1,2) == 0 && events(1,3) == 0 // fprintf(1,'The text event file %s is in the new format\n',eventname); // if events(1,1) ~= raw.first_samp // error(me,'This new format event file is not compatible with the raw data'); // end // else // fprintf(1,'The text event file %s is in the old format\n',eventname); // // // // Offset with first sample // // // events(:,1) = events(:,1) + raw.first_samp; // end } } // // Select the desired events // qint32 count = 0; MatrixXi selected = MatrixXi::Zero(1, events.rows()); for (p = 0; p < events.rows(); ++p) { if (events(p,1) == 0 && events(p,2) == event) { selected(0,count) = p; ++count; } } selected.conservativeResize(1, count); if (count > 0) printf("%d matching events found\n",count); else { printf("No desired events found.\n"); return 0; } fiff_int_t event_samp, from, to; MatrixXd timesDummy; MNEEpochDataList data; MNEEpochData* epoch = NULL; MatrixXd times; for (p = 0; p < count; ++p) { // // Read a data segment // event_samp = events(selected(p),0); from = event_samp + tmin*raw.info.sfreq; to = event_samp + floor(tmax*raw.info.sfreq + 0.5); epoch = new MNEEpochData(); if(raw.read_raw_segment(epoch->epoch, timesDummy, from, to, picks)) { if (p == 0) { times.resize(1, to-from+1); for (qint32 i = 0; i < times.cols(); ++i) times(0, i) = ((float)(from-event_samp+i)) / raw.info.sfreq; } epoch->event = event; epoch->tmin = ((float)(from)-(float)(raw.first_samp))/raw.info.sfreq; epoch->tmax = ((float)(to)-(float)(raw.first_samp))/raw.info.sfreq; data.append(MNEEpochData::SPtr(epoch));//List takes ownwership of the pointer - no delete need } else { printf("Can't read the event data segments"); return 0; } } if(data.size() > 0) { printf("Read %d epochs, %d samples each.\n",data.size(),(qint32)data[0]->epoch.cols()); //DEBUG std::cout << data[0]->epoch.block(0,0,10,10) << std::endl; qDebug() << data[0]->epoch.rows() << " x " << data[0]->epoch.cols(); std::cout << times.block(0,0,1,10) << std::endl; qDebug() << times.rows() << " x " << times.cols(); } // // calculate the average // // //Option 1 // qint32 numAverages = 99; // VectorXi vecSel(numAverages); // srand (time(NULL)); // initialize random seed // for(qint32 i = 0; i < vecSel.size(); ++i) // { // qint32 val = rand() % data.size(); // vecSel(i) = val; // } //Option 2 // VectorXi vecSel(20); //// vecSel << 76, 74, 13, 61, 97, 94, 75, 71, 60, 56, 26, 57, 56, 0, 52, 72, 33, 86, 96, 67; // vecSel << 65, 22, 47, 55, 16, 29, 14, 36, 57, 97, 89, 46, 9, 93, 83, 52, 71, 52, 3, 96; //Option 3 Newest // VectorXi vecSel(10); // vecSel << 0, 96, 80, 55, 66, 25, 26, 2, 55, 58, 6, 88; VectorXi vecSel(1); vecSel << 0; std::cout << "Select following epochs to average:\n" << vecSel << std::endl; FiffEvoked evoked = data.average(raw.info, tmin*raw.info.sfreq, floor(tmax*raw.info.sfreq + 0.5), vecSel); QStringList ch_sel_names = t_Fwd.info.ch_names; FiffEvoked pickedEvoked = evoked.pick_channels(ch_sel_names); //######################################################################################## // RAP MUSIC Source Estimate // // Cluster forward solution; // MNEForwardSolution t_clusteredFwd = t_Fwd.cluster_forward_solution(t_annotationSet, 20);//40); // // Compute inverse solution // RapMusic t_rapMusic(t_clusteredFwd, false, numDipolePairs); if(doMovie) t_rapMusic.setStcAttr(200,0.5); MNESourceEstimate sourceEstimate = t_rapMusic.calculateInverse(pickedEvoked); if(sourceEstimate.isEmpty()) return 1; // // View activation time-series // std::cout << "\nsourceEstimate:\n" << sourceEstimate.data.block(0,0,10,10) << std::endl; // std::cout << "time\n" << sourceEstimate.times.block(0,0,1,10) << std::endl; // std::cout << "timeMin\n" << sourceEstimate.times[0] << std::endl; // std::cout << "timeMax\n" << sourceEstimate.times[sourceEstimate.times.size()-1] << std::endl; // std::cout << "time step\n" << sourceEstimate.tstep << std::endl; //Source Estimate end //######################################################################################## // //only one time point - P100 // qint32 sample = 0; // for(qint32 i = 0; i < sourceEstimate.times.size(); ++i) // { // if(sourceEstimate.times(i) >= 0) // { // sample = i; // break; // } // } // sample += (qint32)ceil(0.106/sourceEstimate.tstep); //100ms // sourceEstimate = sourceEstimate.reduce(sample, 1); View3D::SPtr testWindow = View3D::SPtr(new View3D()); testWindow->addBrainData("Subject01", "HemiLRSet", t_surfSet, t_annotationSet); QList<BrainRTSourceLocDataTreeItem*> rtItemList = testWindow->addRtBrainData("Subject01", "HemiLRSet", sourceEstimate, t_clusteredFwd); testWindow->show(); Control3DWidget::SPtr control3DWidget = Control3DWidget::SPtr(new Control3DWidget()); control3DWidget->setView3D(testWindow); control3DWidget->show(); if(!t_sFileNameStc.isEmpty()) { QFile t_fileClusteredStc(t_sFileNameStc); sourceEstimate.write(t_fileClusteredStc); } return a.exec();//1;//a.exec(); }
/** * The function main marks the entry point of the program. * By default, main has the storage class extern. * * @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started. * @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started. * @return the value that was set to exit() (which is 0 if exit() is called via quit()). */ int main(int argc, char *argv[]) { QApplication a(argc, argv); // Command Line Parser QCommandLineParser parser; parser.setApplicationDescription("Clustered Inverse Powell Rap Music Raw Example"); parser.addHelpOption(); QCommandLineOption inputOption("fileIn", "The input file <in>.", "in", QCoreApplication::applicationDirPath() + "/MNE-sample-data/MEG/sample/sample_audvis_raw.fif"); QCommandLineOption eventsFileOption("eve", "Path to the event <file>.", "file", QCoreApplication::applicationDirPath() + "/MNE-sample-data/MEG/sample/sample_audvis_raw-eve.fif"); QCommandLineOption fwdOption("fwd", "Path to forwad solution <file>.", "file", QCoreApplication::applicationDirPath() + "/MNE-sample-data/MEG/sample/sample_audvis-meg-eeg-oct-6-fwd.fif"); QCommandLineOption surfOption("surfType", "Surface type <type>.", "type", "orig"); QCommandLineOption annotOption("annotType", "Annotation type <type>.", "type", "aparc.a2009s"); QCommandLineOption subjectOption("subject", "Selected subject <subject>.", "subject", "sample"); QCommandLineOption subjectPathOption("subjectPath", "Selected subject path <subjectPath>.", "subjectPath", QCoreApplication::applicationDirPath() + "/MNE-sample-data/subjects"); QCommandLineOption stcFileOption("stcOut", "Path to stc <file>, which is to be written.", "file", ""); QCommandLineOption numDipolePairsOption("numDip", "<number> of dipole pairs to localize.", "number", "7"); QCommandLineOption evokedIdxOption("aveIdx", "The average <index> to choose from the average file.", "index", "1"); QCommandLineOption hemiOption("hemi", "Selected hemisphere <hemi>.", "hemi", "2"); QCommandLineOption doMovieOption("doMovie", "Create overlapping movie.", "doMovie", "false"); QCommandLineOption keepCompOption("keepComp", "Keep compensators.", "keepComp", "false"); QCommandLineOption pickAllOption("pickAll", "Pick all channels.", "pickAll", "true"); QCommandLineOption destCompsOption("destComps", "<Destination> of the compensator which is to be calculated.", "destination", "0"); parser.addOption(inputOption); parser.addOption(eventsFileOption); parser.addOption(fwdOption); parser.addOption(surfOption); parser.addOption(annotOption); parser.addOption(subjectOption); parser.addOption(subjectPathOption); parser.addOption(stcFileOption); parser.addOption(numDipolePairsOption); parser.addOption(evokedIdxOption); parser.addOption(hemiOption); parser.addOption(doMovieOption); parser.addOption(keepCompOption); parser.addOption(pickAllOption); parser.addOption(destCompsOption); parser.process(a); //Load data QFile t_fileRaw(parser.value(inputOption)); QString t_sEventName = parser.value(eventsFileOption); QFile t_fileFwd(parser.value(fwdOption)); SurfaceSet t_surfSet (parser.value(subjectOption), parser.value(hemiOption).toInt(), parser.value(surfOption), parser.value(subjectPathOption)); AnnotationSet t_annotationSet (parser.value(subjectOption), parser.value(hemiOption).toInt(), parser.value(annotOption), parser.value(subjectPathOption)); QString t_sFileNameStc(parser.value(stcFileOption)); qint32 numDipolePairs = parser.value(numDipolePairsOption).toInt(); //Choose average qint32 event = parser.value(evokedIdxOption).toInt(); float tmin = 0.1f; float tmax = 0.2f; bool keep_comp = false; if(parser.value(keepCompOption) == "false" || parser.value(keepCompOption) == "0") { keep_comp = false; } else if(parser.value(keepCompOption) == "true" || parser.value(keepCompOption) == "1") { keep_comp = true; } fiff_int_t dest_comp = parser.value(destCompsOption).toInt(); bool pick_all = false; if(parser.value(pickAllOption) == "false" || parser.value(pickAllOption) == "0") { pick_all = false; } else if(parser.value(pickAllOption) == "true" || parser.value(pickAllOption) == "1") { pick_all = true; } qint32 k, p; bool doMovie = false; if(parser.value(doMovieOption) == "false" || parser.value(doMovieOption) == "0") { pick_all = false; } else if(parser.value(doMovieOption) == "true" || parser.value(doMovieOption) == "1") { pick_all = true; } // // Load data // MNEForwardSolution t_Fwd(t_fileFwd); if(t_Fwd.isEmpty()) return 1; // // Setup for reading the raw data // FiffRawData raw(t_fileRaw); RowVectorXi picks; if (pick_all) { // // Pick all // picks.resize(raw.info.nchan); for(k = 0; k < raw.info.nchan; ++k) picks(k) = k; // } else { QStringList include; include << "STI 014"; bool want_meg = true; bool want_eeg = false; bool want_stim = false; picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);//prefer member function } QStringList ch_names; for(k = 0; k < picks.cols(); ++k) ch_names << raw.info.ch_names[picks(0,k)]; // // Set up projection // if (raw.info.projs.size() == 0) printf("No projector specified for these data\n"); else { // // Activate the projection items // for (k = 0; k < raw.info.projs.size(); ++k) raw.info.projs[k].active = true; printf("%d projection items activated\n",raw.info.projs.size()); // // Create the projector // // fiff_int_t nproj = MNE::make_projector_info(raw.info, raw.proj); Using the member function instead fiff_int_t nproj = raw.info.make_projector(raw.proj); if (nproj == 0) { printf("The projection vectors do not apply to these channels\n"); } else { printf("Created an SSP operator (subspace dimension = %d)\n",nproj); } } // // Set up the CTF compensator // qint32 current_comp = raw.info.get_current_comp(); if (current_comp > 0) printf("Current compensation grade : %d\n",current_comp); if (keep_comp) dest_comp = current_comp; if (current_comp != dest_comp) { qDebug() << "This part needs to be debugged"; if(MNE::make_compensator(raw.info, current_comp, dest_comp, raw.comp)) { raw.info.set_current_comp(dest_comp); printf("Appropriate compensator added to change to grade %d.\n",dest_comp); } else { printf("Could not make the compensator\n"); return 0; } } // // Read the events // QFile t_EventFile; MatrixXi events; if (t_sEventName.size() == 0) { p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_sEventName = t_fileRaw.fileName().replace(p, 4, "-eve.fif"); } else { printf("Raw file name does not end properly\n"); return 0; } // events = mne_read_events(t_sEventName); t_EventFile.setFileName(t_sEventName); MNE::read_events(t_EventFile, events); printf("Events read from %s\n",t_sEventName.toUtf8().constData()); } else { // // Binary file // p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_EventFile.setFileName(t_sEventName); if(!MNE::read_events(t_EventFile, events)) { printf("Error while read events.\n"); return 0; } printf("Binary event file %s read\n",t_sEventName.toUtf8().constData()); } else { // // Text file // printf("Text file %s is not supported jet.\n",t_sEventName.toUtf8().constData()); // try // events = load(eventname); // catch // error(me,mne_omit_first_line(lasterr)); // end // if size(events,1) < 1 // error(me,'No data in the event file'); // end // // // // Convert time to samples if sample number is negative // // // for p = 1:size(events,1) // if events(p,1) < 0 // events(p,1) = events(p,2)*raw.info.sfreq; // end // end // // // // Select the columns of interest (convert to integers) // // // events = int32(events(:,[1 3 4])); // // // // New format? // // // if events(1,2) == 0 && events(1,3) == 0 // fprintf(1,'The text event file %s is in the new format\n',eventname); // if events(1,1) ~= raw.first_samp // error(me,'This new format event file is not compatible with the raw data'); // end // else // fprintf(1,'The text event file %s is in the old format\n',eventname); // // // // Offset with first sample // // // events(:,1) = events(:,1) + raw.first_samp; // end } } // // Select the desired events // qint32 count = 0; MatrixXi selected = MatrixXi::Zero(1, events.rows()); for (p = 0; p < events.rows(); ++p) { if (events(p,1) == 0 && events(p,2) == event) { selected(0,count) = p; ++count; } } selected.conservativeResize(1, count); if (count > 0) printf("%d matching events found\n",count); else { printf("No desired events found.\n"); return 0; } fiff_int_t event_samp, from, to; MatrixXd timesDummy; MNEEpochDataList data; MNEEpochData* epoch = NULL; MatrixXd times; for (p = 0; p < count; ++p) { // // Read a data segment // event_samp = events(selected(p),0); from = event_samp + tmin*raw.info.sfreq; to = event_samp + floor(tmax*raw.info.sfreq + 0.5); epoch = new MNEEpochData(); if(raw.read_raw_segment(epoch->epoch, timesDummy, from, to, picks)) { if (p == 0) { times.resize(1, to-from+1); for (qint32 i = 0; i < times.cols(); ++i) times(0, i) = ((float)(from-event_samp+i)) / raw.info.sfreq; } epoch->event = event; epoch->tmin = ((float)(from)-(float)(raw.first_samp))/raw.info.sfreq; epoch->tmax = ((float)(to)-(float)(raw.first_samp))/raw.info.sfreq; data.append(MNEEpochData::SPtr(epoch));//List takes ownwership of the pointer - no delete need } else { printf("Can't read the event data segments"); return 0; } } if(data.size() > 0) { printf("Read %d epochs, %d samples each.\n",data.size(),(qint32)data[0]->epoch.cols()); // //DEBUG // std::cout << data[0]->epoch.block(0,0,10,10) << std::endl; // qDebug() << data[0]->epoch.rows() << " x " << data[0]->epoch.cols(); // std::cout << times.block(0,0,1,10) << std::endl; // qDebug() << times.rows() << " x " << times.cols(); } // Calculate the average // Option 1 - Random selection VectorXi vecSel(2); srand (time(NULL)); // initialize random seed for(qint32 i = 0; i < vecSel.size(); ++i) { qint32 val = rand() % count; vecSel(i) = val; } // //Option 3 - Take all epochs // VectorXi vecSel(data.size()); // for(qint32 i = 0; i < vecSel.size(); ++i) // { // vecSel(i) = i; // } // //Option 3 - Manual selection // VectorXi vecSel(20); // vecSel << 76, 74, 13, 61, 97, 94, 75, 71, 60, 56, 26, 57, 56, 0, 52, 72, 33, 86, 96, 67; std::cout << "Select following epochs to average:\n" << vecSel << std::endl; FiffEvoked evoked = data.average(raw.info, tmin*raw.info.sfreq, floor(tmax*raw.info.sfreq + 0.5), vecSel); QStringList ch_sel_names = t_Fwd.info.ch_names; FiffEvoked pickedEvoked = evoked.pick_channels(ch_sel_names); //######################################################################################## // RAP MUSIC Source Estimate // // Cluster forward solution; // MNEForwardSolution t_clusteredFwd = t_Fwd.cluster_forward_solution(t_annotationSet, 20);//40); // // Compute inverse solution // PwlRapMusic t_pwlRapMusic(t_clusteredFwd, false, numDipolePairs); #ifdef BENCHMARK MNESourceEstimate sourceEstimate; QList<qint64> qVecElapsedTime; for(qint32 i = 0; i < 100; ++i) { //Benchmark time QElapsedTimer timer; timer.start(); sourceEstimate = t_pwlRapMusic.calculateInverse(pickedEvoked); qVecElapsedTime.append(timer.elapsed()); } double meanTime = 0.0; qint32 offset = 19; qint32 c = 0; for(qint32 i = offset; i < qVecElapsedTime.size(); ++i) { meanTime += qVecElapsedTime[i]; ++c; } meanTime /= (double)c; double varTime = 0; for(qint32 i = offset; i < qVecElapsedTime.size(); ++i) varTime += pow(qVecElapsedTime[i] - meanTime,2); varTime /= (double)c - 1.0f; varTime = sqrt(varTime); qDebug() << "RAP-MUSIC calculation took" << meanTime << "+-" << varTime << "ms in average"; #else int iWinSize = 200; if(doMovie) { t_pwlRapMusic.setStcAttr(iWinSize, 0.6f); } MNESourceEstimate sourceEstimate = t_pwlRapMusic.calculateInverse(pickedEvoked); if(doMovie) { //Select only the activations once MatrixXd dataPicked(sourceEstimate.data.rows(), int(std::floor(sourceEstimate.data.cols()/iWinSize))); for(int i = 0; i < dataPicked.cols(); ++i) { dataPicked.col(i) = sourceEstimate.data.col(i*iWinSize); } sourceEstimate.data = dataPicked; } if(sourceEstimate.isEmpty()) { return 1; } #endif if(sourceEstimate.isEmpty()) return 1; // // View activation time-series // std::cout << "\nsourceEstimate:\n" << sourceEstimate.data.block(0,0,10,10) << std::endl; // std::cout << "time\n" << sourceEstimate.times.block(0,0,1,10) << std::endl; // std::cout << "timeMin\n" << sourceEstimate.times[0] << std::endl; // std::cout << "timeMax\n" << sourceEstimate.times[sourceEstimate.times.size()-1] << std::endl; // std::cout << "time step\n" << sourceEstimate.tstep << std::endl; //Source Estimate end //######################################################################################## // //only one time point - P100 // qint32 sample = 0; // for(qint32 i = 0; i < sourceEstimate.times.size(); ++i) // { // if(sourceEstimate.times(i) >= 0) // { // sample = i; // break; // } // } // sample += (qint32)ceil(0.106/sourceEstimate.tstep); //100ms // sourceEstimate = sourceEstimate.reduce(sample, 1); AbstractView::SPtr p3DAbstractView = AbstractView::SPtr(new AbstractView()); Data3DTreeModel::SPtr p3DDataModel = p3DAbstractView->getTreeModel(); p3DDataModel->addSurfaceSet(parser.value(subjectOption), evoked.comment, t_surfSet, t_annotationSet); //Add rt source loc data and init some visualization values if(MneEstimateTreeItem* pRTDataItem = p3DDataModel->addSourceData(parser.value(subjectOption), evoked.comment, sourceEstimate, t_clusteredFwd, t_surfSet, t_annotationSet)) { pRTDataItem->setLoopState(true); pRTDataItem->setTimeInterval(17); pRTDataItem->setNumberAverages(1); pRTDataItem->setStreamingState(true); pRTDataItem->setThresholds(QVector3D(0.01f,0.5f,1.0f)); pRTDataItem->setVisualizationType("Annotation based"); pRTDataItem->setColormapType("Hot"); } p3DAbstractView->show(); QList<Label> t_qListLabels; QList<RowVector4i> t_qListRGBAs; //ToDo overload toLabels using instead of t_surfSet rr of MNESourceSpace t_annotationSet.toLabels(t_surfSet, t_qListLabels, t_qListRGBAs); if(!t_sFileNameStc.isEmpty()) { QFile t_fileClusteredStc(t_sFileNameStc); sourceEstimate.write(t_fileClusteredStc); } return a.exec();//1;//a.exec(); }
/** * The function main marks the entry point of the program. * By default, main has the storage class extern. * * @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started. * @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started. * @return the value that was set to exit() (which is 0 if exit() is called via quit()). */ int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QGuiApplication::setApplicationName("RTC Evaluation"); QGuiApplication::setApplicationVersion("Revision 1"); ///////////////////////////////////// #1 CLI Parser ///////////////////////////////////// QCommandLineParser parser; parser.setApplicationDescription("RTC Evaluation"); parser.addHelpOption(); parser.addVersionOption(); // MEG Source Directory QCommandLineOption srcDirectoryOption(QStringList() << "s" << "meg-source-directory", QCoreApplication::translate("main", "Read MEG (fwd, cov, raw, eve) source files from <directory>."), QCoreApplication::translate("main", "directory"), "./MNE-sample-data/MEG/sample/"); parser.addOption(srcDirectoryOption); // Forward Solution File QCommandLineOption fwdFileOption(QStringList() << "fwd" << "forward-solution", QCoreApplication::translate("main", "The forward solution <file>."), QCoreApplication::translate("main", "file"), "sample_audvis-meg-eeg-oct-6-fwd.fif"); parser.addOption(fwdFileOption); // Raw MEG File QCommandLineOption rawFileOption(QStringList() << "raw" << "raw-file", QCoreApplication::translate("main", "The raw MEG data <file>."), QCoreApplication::translate("main", "file"), "sample_audvis_raw.fif"); parser.addOption(rawFileOption); // Event File QCommandLineOption eveFileOption(QStringList() << "eve" << "event-file", QCoreApplication::translate("main", "The event <file>."), QCoreApplication::translate("main", "file"), "sample_audvis_raw-eve.fif"); parser.addOption(eveFileOption); // Event Num QCommandLineOption evenNumOption(QStringList() << "evenum" << "event-number", QCoreApplication::translate("main", "The <event number>."), QCoreApplication::translate("main", "event"), "1");//2;//3;//4; parser.addOption(evenNumOption); // FS Subject Directory QCommandLineOption subjDirectoryOption(QStringList() << "subjdir" << "subject-directory", QCoreApplication::translate("main", "The FreeSurfer <subjects directory>."), QCoreApplication::translate("main", "directory"), "./MNE-sample-data/subjects"); parser.addOption(subjDirectoryOption); // FS Subject QCommandLineOption subjIdOption(QStringList() << "subjid" << "subject-id", QCoreApplication::translate("main", "The FreeSurfer <subject id>."), QCoreApplication::translate("main", "subject id"), "sample"); parser.addOption(subjIdOption); // Target Directory QCommandLineOption targetDirectoryOption(QStringList() << "t" << "target-directory", QCoreApplication::translate("main", "Copy all result files into <directory>."), QCoreApplication::translate("main", "directory")); parser.addOption(targetDirectoryOption); // Target Prefix QCommandLineOption targetPrefixOption(QStringList() << "p" << "prefix", QCoreApplication::translate("main", "The result file's <prefix>."), QCoreApplication::translate("main", "prefix")); parser.addOption(targetPrefixOption); // tmin QCommandLineOption tMinOption(QStringList() << "tmin" << "t-min", QCoreApplication::translate("main", "The starting time point <tmin>."), QCoreApplication::translate("main", "tmin"), "0.1"); parser.addOption(tMinOption); // tmax QCommandLineOption tMaxOption(QStringList() << "tmax" << "t-max", QCoreApplication::translate("main", "The end time point <tmax>."), QCoreApplication::translate("main", "tmax"), "0.2"); parser.addOption(tMaxOption); // Process the actual command line arguments given by the user parser.process(app); //////////////////////////////// #2 get parsed values ///////////////////////////////// //Sources QString sFwdName = parser.value(srcDirectoryOption)+parser.value(fwdFileOption); qDebug() << "Forward Solution" << sFwdName; QString sRawName = parser.value(srcDirectoryOption)+parser.value(rawFileOption); qDebug() << "Raw data" << sRawName; QString t_sEventName = parser.value(srcDirectoryOption)+parser.value(eveFileOption); qDebug() << "Events" << t_sEventName; qint32 eveNum = (qint32)parser.value(evenNumOption).toInt(); qDebug() << "Event Number" << eveNum; QString t_sSubjectsDir = parser.value(subjDirectoryOption); qDebug() << "Subjects Directory" << t_sSubjectsDir; QString t_sSubject = parser.value(subjIdOption); qDebug() << "Subject" << t_sSubject; //Targets QString sTargetDir = parser.value(targetDirectoryOption); qDebug() << "Target Directory" << sTargetDir; QString sTargetPrefix = parser.value(targetPrefixOption); qDebug() << "Target Prefix" << sTargetPrefix; //Parameters float tmin = (float)parser.value(tMinOption).toFloat(); qDebug() << "tMin" << tmin; float tmax = (float)parser.value(tMaxOption).toFloat(); qDebug() << "tMax" << tmax; QFile t_fileFwd(sFwdName); // // Load data // MNEForwardSolution t_Fwd(t_fileFwd); if(t_Fwd.isEmpty()) return 1; AnnotationSet t_annotationSet(t_sSubject, 2, "aparc.a2009s", t_sSubjectsDir); // std::cout << "LabelIDs:\n" << t_annotationSet[0].getColortable().getLabelIds() << std::endl; // // Cluster forward solution; // MNEForwardSolution t_clusteredFwd = t_Fwd.cluster_forward_solution(t_annotationSet, 20);//40); QFile t_fileRaw(sRawName); // bool doMovie = false;//true; qint32 numDipolePairs = 1; bool keep_comp = false; fiff_int_t dest_comp = 0; bool pick_all = true; qint32 k, p; // // Setup for reading the raw data // FiffRawData raw(t_fileRaw); RowVectorXi picks; if (pick_all) { // // Pick all // picks.resize(raw.info.nchan); for(k = 0; k < raw.info.nchan; ++k) picks(k) = k; // } else { QStringList include; include << "STI 014"; bool want_meg = true; bool want_eeg = false; bool want_stim = false; picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);//prefer member function } QStringList ch_names; for(k = 0; k < picks.cols(); ++k) ch_names << raw.info.ch_names[picks(0,k)]; // // Set up projection // if (raw.info.projs.size() == 0) printf("No projector specified for these data\n"); else { // // Activate the projection items // for (k = 0; k < raw.info.projs.size(); ++k) raw.info.projs[k].active = true; printf("%d projection items activated\n",raw.info.projs.size()); // // Create the projector // // fiff_int_t nproj = MNE::make_projector_info(raw.info, raw.proj); Using the member function instead fiff_int_t nproj = raw.info.make_projector(raw.proj); if (nproj == 0) { printf("The projection vectors do not apply to these channels\n"); } else { printf("Created an SSP operator (subspace dimension = %d)\n",nproj); } } // // Set up the CTF compensator // qint32 current_comp = raw.info.get_current_comp(); if (current_comp > 0) printf("Current compensation grade : %d\n",current_comp); if (keep_comp) dest_comp = current_comp; if (current_comp != dest_comp) { qDebug() << "This part needs to be debugged"; if(MNE::make_compensator(raw.info, current_comp, dest_comp, raw.comp)) { raw.info.set_current_comp(dest_comp); printf("Appropriate compensator added to change to grade %d.\n",dest_comp); } else { printf("Could not make the compensator\n"); return 0; } } // // Read the events // QFile t_EventFile; MatrixXi events; if (t_sEventName.size() == 0) { p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_sEventName = t_fileRaw.fileName().replace(p, 4, "-eve.fif"); } else { printf("Raw file name does not end properly\n"); return 0; } // events = mne_read_events(t_sEventName); t_EventFile.setFileName(t_sEventName); MNE::read_events(t_EventFile, events); printf("Events read from %s\n",t_sEventName.toUtf8().constData()); } else { // // Binary file // p = t_fileRaw.fileName().indexOf(".fif"); if (p > 0) { t_EventFile.setFileName(t_sEventName); if(!MNE::read_events(t_EventFile, events)) { printf("Error while read events.\n"); return 0; } printf("Binary event file %s read\n",t_sEventName.toUtf8().constData()); } else { // // Text file // printf("Text file %s is not supported jet.\n",t_sEventName.toUtf8().constData()); // try // events = load(eventname); // catch // error(me,mne_omit_first_line(lasterr)); // end // if size(events,1) < 1 // error(me,'No data in the event file'); // end // // // // Convert time to samples if sample number is negative // // // for p = 1:size(events,1) // if events(p,1) < 0 // events(p,1) = events(p,2)*raw.info.sfreq; // end // end // // // // Select the columns of interest (convert to integers) // // // events = int32(events(:,[1 3 4])); // // // // New format? // // // if events(1,2) == 0 && events(1,3) == 0 // fprintf(1,'The text event file %s is in the new format\n',eventname); // if events(1,1) ~= raw.first_samp // error(me,'This new format event file is not compatible with the raw data'); // end // else // fprintf(1,'The text event file %s is in the old format\n',eventname); // // // // Offset with first sample // // // events(:,1) = events(:,1) + raw.first_samp; // end } } // std::cout << "Events:\n" << events << std::endl; // // Select the desired events // qint32 count = 0; MatrixXi selected = MatrixXi::Zero(1, events.rows()); for (p = 0; p < events.rows(); ++p) { if (events(p,1) == 0 && events(p,2) == eveNum) { selected(0,count) = p; ++count; } } selected.conservativeResize(1, count); if (count > 0) printf("%d matching events found\n",count); else { printf("No desired events found.\n"); return 0; } fiff_int_t event_samp, from, to; MatrixXd timesDummy; MNEEpochDataList data; MNEEpochData* epoch = NULL; MatrixXd times; for (p = 0; p < count; ++p) { // // Read a data segment // event_samp = events(selected(p),0); from = event_samp + tmin*raw.info.sfreq; to = event_samp + floor(tmax*raw.info.sfreq + 0.5); epoch = new MNEEpochData(); if(raw.read_raw_segment(epoch->epoch, timesDummy, from, to, picks)) { if (p == 0) { times.resize(1, to-from+1); for (qint32 i = 0; i < times.cols(); ++i) times(0, i) = ((float)(from-event_samp+i)) / raw.info.sfreq; } epoch->event = eveNum; epoch->tmin = ((float)(from)-(float)(raw.first_samp))/raw.info.sfreq; epoch->tmax = ((float)(to)-(float)(raw.first_samp))/raw.info.sfreq; data.append(MNEEpochData::SPtr(epoch));//List takes ownwership of the pointer - no delete need } else { printf("Can't read the event data segments"); return 0; } } if(data.size() > 0) { printf("Read %d epochs, %d samples each.\n",data.size(),(qint32)data[0]->epoch.cols()); // //DEBUG // std::cout << data[0]->epoch.block(0,0,10,10) << std::endl; // qDebug() << data[0]->epoch.rows() << " x " << data[0]->epoch.cols(); // std::cout << times.block(0,0,1,10) << std::endl; // qDebug() << times.rows() << " x " << times.cols(); } // // Init RAP-MUSIC // RapMusic t_rapMusic(t_clusteredFwd, false, numDipolePairs); // // calculate the average // for(qint32 numAverages = 1; numAverages <= 20; numAverages += 1) { for(qint32 it = 0; it <= 30; ++it) { // // calculate the average // VectorXi vecSel(numAverages); srand (time(NULL)); // initialize random seed for(qint32 i = 0; i < vecSel.size(); ++i) { qint32 val = rand() % data.size(); vecSel(i) = val; } // std::cout << "Select following epochs to average:\n" << vecSel << std::endl; // QString sSelFile = QString("aveInfo_%1_%2.txt").arg(numAverages).arg(it); // std::ofstream selFile(sSelFile.toLatin1().constData()); // if (selFile.is_open()) // { // selFile << vecSel << '\n'; // } FiffEvoked evoked = data.average(raw.info, tmin*raw.info.sfreq, floor(tmax*raw.info.sfreq + 0.5), vecSel); QStringList ch_sel_names = t_Fwd.info.ch_names; FiffEvoked pickedEvoked = evoked.pick_channels(ch_sel_names); //######################################################################################## // RAP MUSIC Source Estimate // if(doMovie) // t_pwlRapMusic.setStcAttr(200,0.5); MNESourceEstimate sourceEstimate = t_rapMusic.calculateInverse(pickedEvoked); // std::cout << "Source Estimate:\n" << sourceEstimate.data << std::endl; // std::cout << "Source Estimate vertices:\n" << sourceEstimate.vertices << std::endl; if(!sourceEstimate.isEmpty()) { QString t_sFileNameStc = sTargetDir+QString("%1_%2_ave_it_%3.stc").arg(sTargetPrefix).arg(numAverages).arg(it); qDebug() << "Write to:" << t_sFileNameStc; QDir dir(sTargetDir); if (!dir.exists()) { dir.mkpath("."); } if(!t_sFileNameStc.isEmpty()) { QFile t_fileClusteredStc(t_sFileNameStc); sourceEstimate.write(t_fileClusteredStc); } } } } return 0;//app.exec(); }
bool FiffEvoked::read(QIODevice& p_IODevice, FiffEvoked& p_FiffEvoked, QVariant setno, QPair<QVariant,QVariant> baseline, bool proj, fiff_int_t p_aspect_kind) { p_FiffEvoked.clear(); // // Open the file // FiffStream::SPtr t_pStream(new FiffStream(&p_IODevice)); QString t_sFileName = t_pStream->streamName(); printf("Reading %s ...\n",t_sFileName.toUtf8().constData()); FiffDirTree t_Tree; QList<FiffDirEntry> t_Dir; if(!t_pStream->open(t_Tree, t_Dir)) return false; // // Read the measurement info // FiffInfo info; FiffDirTree meas; if(!t_pStream->read_meas_info(t_Tree, info, meas)) return false; info.filename = t_sFileName; //move fname storage to read_meas_info member function // // Locate the data of interest // QList<FiffDirTree> processed = meas.dir_tree_find(FIFFB_PROCESSED_DATA); if (processed.size() == 0) { qWarning("Could not find processed data"); return false; } // QList<FiffDirTree> evoked_node = meas.dir_tree_find(FIFFB_EVOKED); if (evoked_node.size() == 0) { qWarning("Could not find evoked data"); return false; } // convert setno to an integer if(!setno.isValid()) { if (evoked_node.size() > 1) { QStringList comments; QList<fiff_int_t> aspect_kinds; QString t; if(!t_pStream->get_evoked_entries(evoked_node, comments, aspect_kinds, t)) t = QString("None found, must use integer"); qWarning("%d datasets present, setno parameter must be set. Candidate setno names:\n%s", evoked_node.size(), t.toLatin1().constData()); return false; } else setno = 0; } else { // find string-based entry bool t_bIsInteger = true; setno.toInt(&t_bIsInteger); if(!t_bIsInteger) { if(p_aspect_kind != FIFFV_ASPECT_AVERAGE && p_aspect_kind != FIFFV_ASPECT_STD_ERR) { qWarning("kindStat must be \"FIFFV_ASPECT_AVERAGE\" or \"FIFFV_ASPECT_STD_ERR\""); return false; } QStringList comments; QList<fiff_int_t> aspect_kinds; QString t; t_pStream->get_evoked_entries(evoked_node, comments, aspect_kinds, t); bool found = false; for(qint32 i = 0; i < comments.size(); ++i) { if(comments[i].compare(setno.toString()) == 0 && p_aspect_kind == aspect_kinds[i]) { setno = i; found = true; break; } } if(!found) { qWarning() << "setno " << setno << " (" << p_aspect_kind << ") not found, out of found datasets:\n " << t; return false; } } } if (setno.toInt() >= evoked_node.size() || setno.toInt() < 0) { qWarning("Data set selector out of range"); return false; } FiffDirTree my_evoked = evoked_node[setno.toInt()]; // // Identify the aspects // QList<FiffDirTree> aspects = my_evoked.dir_tree_find(FIFFB_ASPECT); if(aspects.size() > 1) printf("\tMultiple (%d) aspects found. Taking first one.\n", aspects.size()); FiffDirTree my_aspect = aspects[0]; // // Now find the data in the evoked block // fiff_int_t nchan = 0; float sfreq = -1.0f; QList<FiffChInfo> chs; fiff_int_t kind, pos, first=0, last=0; FiffTag::SPtr t_pTag; QString comment(""); qint32 k; for (k = 0; k < my_evoked.nent; ++k) { kind = my_evoked.dir[k].kind; pos = my_evoked.dir[k].pos; switch (kind) { case FIFF_COMMENT: FiffTag::read_tag(t_pStream.data(),t_pTag,pos); comment = t_pTag->toString(); break; case FIFF_FIRST_SAMPLE: FiffTag::read_tag(t_pStream.data(),t_pTag,pos); first = *t_pTag->toInt(); break; case FIFF_LAST_SAMPLE: FiffTag::read_tag(t_pStream.data(),t_pTag,pos); last = *t_pTag->toInt(); break; case FIFF_NCHAN: FiffTag::read_tag(t_pStream.data(),t_pTag,pos); nchan = *t_pTag->toInt(); break; case FIFF_SFREQ: FiffTag::read_tag(t_pStream.data(),t_pTag,pos); sfreq = *t_pTag->toFloat(); break; case FIFF_CH_INFO: FiffTag::read_tag(t_pStream.data(), t_pTag, pos); chs.append( t_pTag->toChInfo() ); break; } } if (comment.isEmpty()) comment = QString("No comment"); // // Local channel information? // if (nchan > 0) { if (chs.size() == 0) { qWarning("Local channel information was not found when it was expected."); return false; } if (chs.size() != nchan) { qWarning("Number of channels and number of channel definitions are different."); return false; } info.chs = chs; info.nchan = nchan; printf("\tFound channel information in evoked data. nchan = %d\n",nchan); if (sfreq > 0.0f) info.sfreq = sfreq; } qint32 nsamp = last-first+1; printf("\tFound the data of interest:\n"); printf("\t\tt = %10.2f ... %10.2f ms (%s)\n", 1000*(float)first/info.sfreq, 1000*(float)last/info.sfreq,comment.toUtf8().constData()); if (info.comps.size() > 0) printf("\t\t%d CTF compensation matrices available\n", info.comps.size()); // // Read the data in the aspect block // fiff_int_t aspect_kind = -1; fiff_int_t nave = -1; QList<FiffTag> epoch; for (k = 0; k < my_aspect.nent; ++k) { kind = my_aspect.dir[k].kind; pos = my_aspect.dir[k].pos; switch (kind) { case FIFF_COMMENT: FiffTag::read_tag(t_pStream.data(), t_pTag, pos); comment = t_pTag->toString(); break; case FIFF_ASPECT_KIND: FiffTag::read_tag(t_pStream.data(), t_pTag, pos); aspect_kind = *t_pTag->toInt(); break; case FIFF_NAVE: FiffTag::read_tag(t_pStream.data(), t_pTag, pos); nave = *t_pTag->toInt(); break; case FIFF_EPOCH: FiffTag::read_tag(t_pStream.data(), t_pTag, pos); epoch.append(FiffTag(t_pTag.data())); break; } } if (nave == -1) nave = 1; printf("\t\tnave = %d - aspect type = %d\n", nave, aspect_kind); qint32 nepoch = epoch.size(); MatrixXd all_data; if (nepoch == 1) { // // Only one epoch // all_data = epoch[0].toFloatMatrix().cast<double>(); all_data.transposeInPlace(); // // May need a transpose if the number of channels is one // if (all_data.cols() == 1 && info.nchan == 1) all_data.transposeInPlace(); } else { // // Put the old style epochs together // all_data = epoch[0].toFloatMatrix().cast<double>(); all_data.transposeInPlace(); qint32 oldsize; for (k = 1; k < nepoch; ++k) { oldsize = all_data.rows(); MatrixXd tmp = epoch[k].toFloatMatrix().cast<double>(); tmp.transposeInPlace(); all_data.conservativeResize(oldsize+tmp.rows(), all_data.cols()); all_data.block(oldsize, 0, tmp.rows(), tmp.cols()) = tmp; } } if (all_data.cols() != nsamp) { qWarning("Incorrect number of samples (%d instead of %d)", (int) all_data.cols(), nsamp); return false; } // // Calibrate // printf("\n\tPreprocessing...\n"); printf("\t%d channels remain after picking\n",info.nchan); typedef Eigen::Triplet<double> T; std::vector<T> tripletList; tripletList.reserve(info.nchan); for(k = 0; k < info.nchan; ++k) tripletList.push_back(T(k, k, info.chs[k].cal)); SparseMatrix<double> cals(info.nchan, info.nchan); cals.setFromTriplets(tripletList.begin(), tripletList.end()); all_data = cals * all_data; RowVectorXf times = RowVectorXf(last-first+1); for (k = 0; k < times.size(); ++k) times[k] = ((float)(first+k)) / info.sfreq; // // Set up projection // if(info.projs.size() == 0 || !proj) { printf("\tNo projector specified for these data.\n"); p_FiffEvoked.proj = MatrixXd(); } else { // Create the projector MatrixXd projection; qint32 nproj = info.make_projector(projection); if(nproj == 0) { printf("\tThe projection vectors do not apply to these channels\n"); p_FiffEvoked.proj = MatrixXd(); } else { printf("\tCreated an SSP operator (subspace dimension = %d)\n", nproj); p_FiffEvoked.proj = projection; } // The projection items have been activated FiffProj::activate_projs(info.projs); } if(p_FiffEvoked.proj.rows() > 0) { all_data = p_FiffEvoked.proj * all_data; printf("\tSSP projectors applied to the evoked data\n"); } // Run baseline correction all_data = MNEMath::rescale(all_data, times, baseline, QString("mean")); printf("Applying baseline correction ... (mode: mean)"); // Put it all together p_FiffEvoked.info = info; p_FiffEvoked.nave = nave; p_FiffEvoked.aspect_kind = aspect_kind; p_FiffEvoked.first = first; p_FiffEvoked.last = last; p_FiffEvoked.comment = comment; p_FiffEvoked.times = times; p_FiffEvoked.data = all_data; return true; }