Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit 15684515 authored by Emmanuel Promayon's avatar Emmanuel Promayon
Browse files

FIXED for Qt<5.6 and modularize/clean/simplify algorithm

parent af6a44ef
......@@ -61,80 +61,45 @@ ActionsInActionAction::~ActionsInActionAction() {
// --------------- apply -------------------
Action::ApplyStatus ActionsInActionAction::apply() {
Action::ApplyStatus status;
PipelineActionStatus pipelineStatus = PipelineActionStatus::OK;
ImageComponent* input = dynamic_cast<ImageComponent*>(getTargets().last());
// apply the resample action (first action in the pipeline) on the last selected component
pipelineStatus = applyResample(getTargets().last());
Action* resampleAction = Application::getAction("Resample");
// If the image has been saved, then it is not modified any more...
if (pipelineStatus == OK) {
if (resampleAction != nullptr) {
// You can most of the time safely ignore the safeguard bits below and simply use:
// Component* resampled = resampleAction->getOutputComponent()
// But in some rare case, the second action of this pipeline is not going to use the correct
// input. For these cases, you need to use:
Component* resampled = getLastTopLevelOutputComponents("Resample");
// set the input
resampleAction->setInputComponent(input);
// apply the Otsu action (second action in the pipeline)
pipelineStatus = applyOtsu(resampled);
// set the parameter
int* dims = input->getImageData()->GetDimensions();
double factor = property("Resample Factor").toDouble();
resampleAction->setProperty("New Image X Dimension", int(dims[0]*factor));
resampleAction->setProperty("New Image Y Dimension", int(dims[1]*factor));
resampleAction->setProperty("New Image Z Dimension", std::max(1,int(dims[2]*factor)));
// apply the action
status = resampleAction->applyInPipeline();
// If the image has been saved, then it is not modified any more...
if (status == Action::SUCCESS) {
input->setModified(false);
auto it = find_if(resampleAction->getOutputComponents().crbegin(), resampleAction->getOutputComponents().crend(), [] (const Component* c) { return c->isTopLevel(); } );
// Equivalent of
// ComponentList::reverse_iterator it = resampleAction->getOutputComponents().rbegin();
// while (it != resampleAction->getOutputComponents().rend() && !(*it)->isTopLevel()) {
// it++;
// }
Component* resampled = (*it);
Action* otsuThreshold = Application::getAction("Otsu Threshold Filter");
if (otsuThreshold != nullptr) {
otsuThreshold->setInputComponent(resampled);
status = otsuThreshold->applyInPipeline();
if (status == Action::SUCCESS) {
// if all goes well, don't show the intermediate result
delete resampled;
}
else {
pipelineStatus = PipelineActionStatus::OTSU_APPLY_ERROR;
}
}
else {
pipelineStatus = PipelineActionStatus::OTSU_NOT_FOUND;
}
}
else {
pipelineStatus = PipelineActionStatus::RESAMPLE_APPLY_ERROR;
if (pipelineStatus == OK) {
// if all goes well, don't show the intermediate result
delete resampled;
}
}
else {
pipelineStatus = PipelineActionStatus::RESAMPLE_NOT_FOUND;
}
switch (pipelineStatus) {
case OTSU_APPLY_ERROR:
CAMITK_ERROR("\"Otsu Threshold Filter\" apply error:" + Action::getStatusAsString(status));
CAMITK_ERROR("\"Otsu Threshold Filter\" apply error");
break;
case OTSU_NOT_FOUND:
CAMITK_ERROR("\"Otsu Threshold Filter\" action not found");
break;
case RESAMPLE_APPLY_ERROR:
CAMITK_ERROR("\"Resample Factor\" apply error:" + Action::getStatusAsString(status));
CAMITK_ERROR("\"Resample Factor\" apply error.");
break;
case RESAMPLE_NOT_FOUND:
CAMITK_ERROR("\"Resample Factor\" action not found");
break;
case OK:
CAMITK_TRACE("Pipeline successful");
break;
}
Application::refresh();
......@@ -142,4 +107,93 @@ Action::ApplyStatus ActionsInActionAction::apply() {
return ((pipelineStatus == OK) ? SUCCESS : ERROR);
}
// --------------- getLastTopLevelOutputComponents -------------------
Component* ActionsInActionAction::getLastTopLevelOutputComponents(const QString& actionName) {
Component* lastOutputComponent = nullptr;
Action* currentAction = Application::getAction(actionName);
if (currentAction != nullptr) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
// it Qt >= 5.6 crbegin() exist and we can use a lambda expression to find the first
// top level component, looking from the end to the beginning of the component list.
auto it = find_if(currentAction->getOutputComponents().crbegin(),
currentAction->getOutputComponents().crend(),
[](const Component * c) {
return c->isTopLevel();
});
// This is equivalent of:
// ComponentList::reverse_iterator it = currentAction->getOutputComponents().rbegin();
// while (it != currentAction->getOutputComponents().rend() && !(*it)->isTopLevel()) {
// it++;
// }
lastOutputComponent = (*it);
#else
// In Qt < 5.6, too bad: crbegin(), crend(), rbegin() and rend() do not exist
unsigned int i = currentAction->getOutputComponents().size() - 1;
while (i > 0 && !currentAction->getOutputComponents().at(i)->isTopLevel()) {
i--;
}
if (i >= 0) {
lastOutputComponent = currentAction->getOutputComponents().at(i);
}
#endif
}
return lastOutputComponent;
}
// --------------- applyResample -------------------
ActionsInActionAction::PipelineActionStatus ActionsInActionAction::applyResample(Component* input) {
Action* resampleAction = Application::getAction("Resample");
if (resampleAction == nullptr) {
return RESAMPLE_NOT_FOUND;
}
else {
// set the input
resampleAction->setInputComponent(input);
// set the parameter
ImageComponent* inputImage = dynamic_cast<ImageComponent*>(input);
// Note: as ActionsInActionAction takes ImageComponent as inputs, the dynamic_cast is
// guaranty to work perfectly well.
int* dims = inputImage->getImageData()->GetDimensions();
double factor = property("Resample Factor").toDouble();
resampleAction->setProperty("New Image X Dimension", int(dims[0]*factor));
resampleAction->setProperty("New Image Y Dimension", int(dims[1]*factor));
resampleAction->setProperty("New Image Z Dimension", std::max(1, int(dims[2]*factor)));
// apply the action
Action::ApplyStatus status = resampleAction->applyInPipeline();
// reset the flag (just in case)
input->setModified(false);
return (status == Action::SUCCESS) ? OK : RESAMPLE_APPLY_ERROR;
}
}
// --------------- applyOtsu -------------------
ActionsInActionAction::PipelineActionStatus ActionsInActionAction::applyOtsu(Component* input) {
Action* otsuThreshold = Application::getAction("Otsu Threshold Filter");
if (otsuThreshold == nullptr) {
return OTSU_NOT_FOUND;
}
else {
// set the input
otsuThreshold->setInputComponent(input);
// nothing special to do on the action parameters
// apply the action
Action::ApplyStatus status = otsuThreshold->applyInPipeline();
return (status == Action::SUCCESS) ? OK : OTSU_APPLY_ERROR;
}
}
......@@ -48,8 +48,8 @@ public slots:
virtual ApplyStatus apply();
private:
// many things can happen during the execution of this action
enum PipelineActionStatus{
/// many things can happen during the execution of this action
enum PipelineActionStatus {
RESAMPLE_NOT_FOUND,
OTSU_NOT_FOUND,
RESAMPLE_APPLY_ERROR,
......@@ -57,6 +57,39 @@ private:
OK,
};
/// Get the last toplevel output component of a given action
/// This is required in some rare specific pipeline execution environment
///
/// Knowing that:
/// - Action::getOutputComponents() method returns all instanciated components during the apply() method
/// **as well** as all the unmodified components (unaware of if this modified components were modified
/// prior to the apply() method).
/// Note that the last instanciated component is at the end of the list.
/// - Action::getOutputComponent() method returns the first instanciated or modified component during the
/// apply().
///
/// There is a specific issue that arise when there are existing components marked as modified
/// **before** the start of the pipeline (e.g., when the action pipeline was run previously
/// and the user left the instanciated component untouched/unsaved or when the user modified
/// a component manually, outside the pipeline).
///
/// The best way (for now) to deal with this issue is to simply get the last top-level component
/// in the ouput list. This will be the last instanciated top-level component during the apply() method.
/// Any components that were modified _before_ the apply() will therefore be ignore
///
/// This is an issue to consider in the Action class.
/// We probably should list in Action::preprocessInPipeline() all the component that were marked modified
/// and ignore them in the output component list (that will not take into account the rare case were a
/// already modified component was modified **as well** during the apply(), but that seems a better
/// behaviour anyway.
///
camitk::Component *getLastTopLevelOutputComponents(const QString & actionName);
/// apply the resample action (modifying the parameter)
PipelineActionStatus applyResample(camitk::Component *input);
/// apply the Otsu action
PipelineActionStatus applyOtsu(camitk::Component *input);
};
#endif // ACTIONSINACTIONACTION_H
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment