File indexing completed on 2024-12-22 04:18:09
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2007 The University of Toronto * 0004 * netterfield@astro.utoronto.ca * 0005 * copyright : (C) 2005 University of British Columbia * 0006 * dscott@phas.ubc.ca * 0007 * * 0008 * This program is free software; you can redistribute it and/or modify * 0009 * it under the terms of the GNU General Public License as published by * 0010 * the Free Software Foundation; either version 2 of the License, or * 0011 * (at your option) any later version. * 0012 * * 0013 ***************************************************************************/ 0014 0015 0016 #include "filterdespike.h" 0017 #include "objectstore.h" 0018 #include "ui_filterdespikeconfig.h" 0019 0020 static const QString& VECTOR_IN = "Y Vector"; 0021 static const QString& SCALAR_NSIGMA_IN = "NSigma Scalar"; 0022 static const QString& SCALAR_SPACING_IN = "Spacing Scalar"; 0023 static const QString& VECTOR_OUT = "Y"; 0024 0025 class ConfigWidgetFilterDespikePlugin : public Kst::DataObjectConfigWidget, public Ui_FilterDespikeConfig { 0026 public: 0027 ConfigWidgetFilterDespikePlugin(QSettings* cfg) : DataObjectConfigWidget(cfg), Ui_FilterDespikeConfig() { 0028 _store = 0; 0029 setupUi(this); 0030 } 0031 0032 ~ConfigWidgetFilterDespikePlugin() {} 0033 0034 void setObjectStore(Kst::ObjectStore* store) { 0035 _store = store; 0036 _vector->setObjectStore(store); 0037 _scalarNSigma->setObjectStore(store); 0038 _scalarSpacing->setObjectStore(store); 0039 _scalarNSigma->setDefaultValue(5.0); 0040 _scalarSpacing->setDefaultValue(1.0); 0041 } 0042 0043 void setupSlots(QWidget* dialog) { 0044 if (dialog) { 0045 connect(_vector, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified())); 0046 connect(_scalarNSigma, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified())); 0047 connect(_scalarSpacing, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified())); 0048 } 0049 } 0050 0051 void setVectorX(Kst::VectorPtr vector) { 0052 setSelectedVector(vector); 0053 } 0054 0055 void setVectorY(Kst::VectorPtr vector) { 0056 setSelectedVector(vector); 0057 } 0058 0059 void setVectorsLocked(bool locked = true) { 0060 _vector->setEnabled(!locked); 0061 } 0062 0063 Kst::VectorPtr selectedVector() { return _vector->selectedVector(); }; 0064 void setSelectedVector(Kst::VectorPtr vector) { return _vector->setSelectedVector(vector); }; 0065 0066 Kst::ScalarPtr selectedNSigmaScalar() { return _scalarNSigma->selectedScalar(); }; 0067 void setSelectedNSigmaScalar(Kst::ScalarPtr scalar) { return _scalarNSigma->setSelectedScalar(scalar); }; 0068 0069 Kst::ScalarPtr selectedSpacingScalar() { return _scalarSpacing->selectedScalar(); }; 0070 void setSelectedSpacingScalar(Kst::ScalarPtr scalar) { return _scalarSpacing->setSelectedScalar(scalar); }; 0071 0072 virtual void setupFromObject(Kst::Object* dataObject) { 0073 if (FilterDespikeSource* source = static_cast<FilterDespikeSource*>(dataObject)) { 0074 setSelectedVector(source->vector()); 0075 setSelectedNSigmaScalar(source->nSigmaScalar()); 0076 setSelectedSpacingScalar(source->spacingScalar()); 0077 } 0078 } 0079 0080 virtual bool configurePropertiesFromXml(Kst::ObjectStore *store, QXmlStreamAttributes& attrs) { 0081 Q_UNUSED(store); 0082 Q_UNUSED(attrs); 0083 0084 bool validTag = true; 0085 0086 // QStringRef av; 0087 // av = attrs.value("value"); 0088 // if (!av.isNull()) { 0089 // _configValue = QVariant(av.toString()).toBool(); 0090 // } 0091 0092 return validTag; 0093 } 0094 0095 public slots: 0096 virtual void save() { 0097 if (_cfg) { 0098 _cfg->beginGroup("Filter Despike Plugin"); 0099 _cfg->setValue("Input Vector", _vector->selectedVector()->Name()); 0100 _cfg->setValue("Spacing Scalar", _scalarSpacing->selectedScalar()->Name()); 0101 _cfg->setValue("NSigma Scalar", _scalarNSigma->selectedScalar()->Name()); 0102 _cfg->endGroup(); 0103 } 0104 } 0105 0106 virtual void load() { 0107 if (_cfg && _store) { 0108 _cfg->beginGroup("Filter Despike Plugin"); 0109 QString vectorName = _cfg->value("Input Vector").toString(); 0110 Kst::Object* object = _store->retrieveObject(vectorName); 0111 Kst::Vector* vector = static_cast<Kst::Vector*>(object); 0112 if (vector) { 0113 setSelectedVector(vector); 0114 } 0115 QString scalarName = _cfg->value("Spacing Scalar").toString(); 0116 _scalarSpacing->setSelectedScalar(scalarName); 0117 0118 scalarName = _cfg->value("NSigma Scalar").toString(); 0119 _scalarNSigma->setSelectedScalar(scalarName); 0120 0121 _cfg->endGroup(); 0122 } 0123 } 0124 0125 private: 0126 Kst::ObjectStore *_store; 0127 0128 }; 0129 0130 0131 FilterDespikeSource::FilterDespikeSource(Kst::ObjectStore *store) 0132 : Kst::BasicPlugin(store) { 0133 } 0134 0135 0136 FilterDespikeSource::~FilterDespikeSource() { 0137 } 0138 0139 0140 QString FilterDespikeSource::_automaticDescriptiveName() const { 0141 if (vector()) { 0142 return tr("%1 Despiked", "arg 1 is the name of the vector which has been despiked").arg(vector()->descriptiveName()); 0143 } else { 0144 return tr("Despike"); 0145 } 0146 } 0147 0148 0149 QString FilterDespikeSource::descriptionTip() const { 0150 QString tip; 0151 0152 tip = tr("Despike Filter: %1\n Spacing: %2\n NSigma: %3").arg(Name()).arg(spacingScalar()->value()).arg(nSigmaScalar()->value()); 0153 0154 tip += tr("\nInput: %1").arg(vector()->descriptionTip()); 0155 return tip; 0156 } 0157 0158 void FilterDespikeSource::change(Kst::DataObjectConfigWidget *configWidget) { 0159 if (ConfigWidgetFilterDespikePlugin* config = static_cast<ConfigWidgetFilterDespikePlugin*>(configWidget)) { 0160 setInputVector(VECTOR_IN, config->selectedVector()); 0161 setInputScalar(SCALAR_NSIGMA_IN, config->selectedNSigmaScalar()); 0162 setInputScalar(SCALAR_SPACING_IN, config->selectedSpacingScalar()); 0163 } 0164 } 0165 0166 0167 void FilterDespikeSource::setupOutputs() { 0168 setOutputVector(VECTOR_OUT, ""); 0169 } 0170 0171 0172 bool FilterDespikeSource::algorithm() { 0173 Kst::VectorPtr inputVector = _inputVectors[VECTOR_IN]; 0174 Kst::ScalarPtr nSigmaScalar = _inputScalars[SCALAR_NSIGMA_IN]; 0175 Kst::ScalarPtr spacingScalar = _inputScalars[SCALAR_SPACING_IN]; 0176 Kst::VectorPtr outputVector; 0177 // maintain kst file compatibility if the output vector name is changed. 0178 if (_outputVectors.contains(VECTOR_OUT)) { 0179 outputVector = _outputVectors[VECTOR_OUT]; 0180 } else { 0181 outputVector = _outputVectors.values().at(0); 0182 } 0183 0184 int N = inputVector->length(); 0185 double last_good; 0186 double mdev = 0; 0187 double cut = nSigmaScalar->value(); 0188 int dx = int(spacingScalar->value()); 0189 int i; 0190 int spike_start = -1; 0191 int border = dx*2; 0192 0193 if ( (N < 1) || (cut <= 0) || (dx < 1) || (dx > N/2) ) { 0194 return false; 0195 } 0196 0197 /* get mean deviation of 3 pt difference */ 0198 for (i=dx; i<N-dx; ++i) { 0199 mdev += fabs(inputVector->value(i)-(inputVector->value(i-dx) + inputVector->value(i+dx))*0.5); 0200 } 0201 mdev /= double(N); 0202 0203 cut *= mdev; 0204 0205 // resize the output array 0206 outputVector->resize(inputVector->length(), false); 0207 0208 // for first dx points, do a 2 point difference 0209 last_good = inputVector->value(0); 0210 for (i=0; i<dx; ++i) { 0211 if (fabs(inputVector->value(i) - inputVector->value(i+dx))>cut) { 0212 if (spike_start<0) { 0213 spike_start = i-border; 0214 if (spike_start<0) { 0215 spike_start = 0; 0216 } 0217 } 0218 } else { 0219 if (spike_start>=0) { 0220 i += 4*border-1; 0221 if (i>=N) { 0222 i=N-1; 0223 } 0224 for (int j=spike_start; j<=i; j++) { 0225 outputVector->raw_V_ptr()[j] = last_good; 0226 } 0227 spike_start = -1; 0228 } 0229 last_good = outputVector->raw_V_ptr()[i] = inputVector->value(i); 0230 } 0231 } 0232 // do a 3 point difference where it is possible 0233 for (i=dx; i<N-dx; ++i) { 0234 if (fabs(inputVector->value(i) - (inputVector->value(i-dx) + inputVector->value(i+dx))*0.5)>cut) { 0235 if (spike_start<0) { 0236 spike_start = i-border; 0237 if (spike_start<0) { 0238 spike_start = 0; 0239 } 0240 } 0241 } else { 0242 if (spike_start>=0) { 0243 i += 4*border-1; 0244 if (i>=N) { 0245 i=N-1; 0246 } 0247 for (int j=spike_start; j<=i; j++) { 0248 outputVector->raw_V_ptr()[j] = last_good; 0249 } 0250 spike_start = -1; 0251 } else { 0252 last_good = outputVector->raw_V_ptr()[i] = inputVector->value(i); 0253 } 0254 } 0255 } 0256 // do a 2 point difference for last dx points 0257 for (i=N-dx-1; i<N; ++i) { 0258 if (fabs(inputVector->value(i-dx) - inputVector->value(i))>cut) { 0259 if (spike_start<0) { 0260 spike_start = i-border; 0261 if (spike_start<0) { 0262 spike_start = 0; 0263 } 0264 } 0265 } else { 0266 if (spike_start>=0) { 0267 i += 4*border-1; 0268 if (i>=N) { 0269 i=N-1; 0270 } 0271 for (int j=spike_start; j<=i; j++) { 0272 outputVector->raw_V_ptr()[j] = last_good; 0273 } 0274 spike_start = -1; 0275 } else { 0276 last_good = outputVector->raw_V_ptr()[i] = inputVector->value(i); 0277 } 0278 } 0279 } 0280 if (spike_start>=0) { 0281 for (int j=spike_start; j<N; j++) { 0282 outputVector->raw_V_ptr()[j] = last_good; 0283 } 0284 } 0285 0286 Kst::LabelInfo label_info = inputVector->labelInfo(); 0287 label_info.name = tr("Despiked %1").arg(label_info.name); 0288 outputVector->setLabelInfo(label_info); 0289 0290 return true; 0291 } 0292 0293 0294 Kst::VectorPtr FilterDespikeSource::vector() const { 0295 return _inputVectors[VECTOR_IN]; 0296 } 0297 0298 0299 Kst::ScalarPtr FilterDespikeSource::spacingScalar() const { 0300 return _inputScalars[SCALAR_SPACING_IN]; 0301 } 0302 0303 0304 Kst::ScalarPtr FilterDespikeSource::nSigmaScalar() const { 0305 return _inputScalars[SCALAR_NSIGMA_IN]; 0306 } 0307 0308 0309 QStringList FilterDespikeSource::inputVectorList() const { 0310 return QStringList( VECTOR_IN ); 0311 } 0312 0313 0314 QStringList FilterDespikeSource::inputScalarList() const { 0315 QStringList inputScalars( SCALAR_NSIGMA_IN ); 0316 inputScalars += SCALAR_SPACING_IN; 0317 return inputScalars; 0318 } 0319 0320 0321 QStringList FilterDespikeSource::inputStringList() const { 0322 return QStringList( /*STRING_IN*/ ); 0323 } 0324 0325 0326 QStringList FilterDespikeSource::outputVectorList() const { 0327 return QStringList( VECTOR_OUT ); 0328 } 0329 0330 0331 QStringList FilterDespikeSource::outputScalarList() const { 0332 return QStringList( /*SCALAR_OUT*/ ); 0333 } 0334 0335 0336 QStringList FilterDespikeSource::outputStringList() const { 0337 return QStringList( /*STRING_OUT*/ ); 0338 } 0339 0340 0341 void FilterDespikeSource::saveProperties(QXmlStreamWriter &s) { 0342 Q_UNUSED(s); 0343 // s.writeAttribute("value", _configValue); 0344 } 0345 0346 0347 // Name used to identify the plugin. Used when loading the plugin. 0348 QString FilterDespikePlugin::pluginName() const { return tr("Despike Filter"); } 0349 QString FilterDespikePlugin::pluginDescription() const { return tr("Finds and removes spikes using a 3 point difference."); } 0350 0351 0352 Kst::DataObject *FilterDespikePlugin::create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs) const { 0353 0354 if (ConfigWidgetFilterDespikePlugin* config = static_cast<ConfigWidgetFilterDespikePlugin*>(configWidget)) { 0355 0356 FilterDespikeSource* object = store->createObject<FilterDespikeSource>(); 0357 0358 if (setupInputsOutputs) { 0359 object->setInputScalar(SCALAR_SPACING_IN, config->selectedSpacingScalar()); 0360 object->setInputScalar(SCALAR_NSIGMA_IN, config->selectedNSigmaScalar()); 0361 object->setupOutputs(); 0362 object->setInputVector(VECTOR_IN, config->selectedVector()); 0363 } 0364 0365 object->setPluginName(pluginName()); 0366 0367 object->writeLock(); 0368 object->registerChange(); 0369 object->unlock(); 0370 0371 return object; 0372 } 0373 return 0; 0374 } 0375 0376 0377 Kst::DataObjectConfigWidget *FilterDespikePlugin::configWidget(QSettings *settingsObject) const { 0378 ConfigWidgetFilterDespikePlugin *widget = new ConfigWidgetFilterDespikePlugin(settingsObject); 0379 return widget; 0380 } 0381 0382 #ifndef QT5 0383 Q_EXPORT_PLUGIN2(kstplugin_FilterDespikePlugin, FilterDespikePlugin) 0384 #endif 0385 0386 // vim: ts=2 sw=2 et