* demo/demat/demat.pro, * demo/demat/demat.qrc, * demo/demat/src/doc_type.hh, * demo/demat/src/main.cc, * demo/demat/src/main_window.cc, * demo/demat/src/main_window.hh, * demo/demat/src/mln_widgets.cc, * demo/demat/src/preprocessing_task.hh, * demo/demat/src/process_args.hh, * demo/demat/src/runner.cc, * demo/demat/src/runner.hh, * demo/demat/ui/main_window.ui: New.
* demo/shared/src/crop_item.cc, * demo/shared/src/crop_item.hh, * demo/shared/src/image_viewer.cc, * demo/shared/src/image_viewer.hh, * demo/shared/ui/image_viewer.ui: Update according the needs of this new demo. --- scribo/ChangeLog | 24 ++ scribo/demo/demat/demat.pro | 37 ++ scribo/demo/demat/demat.qrc | 4 + scribo/demo/{wizard => demat}/src/doc_type.hh | 0 scribo/demo/demat/src/main.cc | 27 ++ scribo/demo/demat/src/main_window.cc | 240 +++++++++++++ scribo/demo/demat/src/main_window.hh | 91 +++++ scribo/demo/demat/src/mln_widgets.cc | 11 + .../{wizard => demat}/src/preprocessing_task.hh | 0 scribo/demo/demat/src/process_args.hh | 47 +++ scribo/demo/demat/src/runner.cc | 316 +++++++++++++++++ scribo/demo/demat/src/runner.hh | 93 +++++ scribo/demo/demat/ui/main_window.ui | 366 ++++++++++++++++++++ scribo/demo/shared/src/crop_item.cc | 45 ++- scribo/demo/shared/src/crop_item.hh | 12 +- scribo/demo/shared/src/image_viewer.cc | 65 +++- scribo/demo/shared/src/image_viewer.hh | 14 +- scribo/demo/shared/ui/image_viewer.ui | 34 ++- 18 files changed, 1398 insertions(+), 28 deletions(-) create mode 100644 scribo/demo/demat/demat.pro create mode 100644 scribo/demo/demat/demat.qrc copy scribo/demo/{wizard => demat}/src/doc_type.hh (100%) create mode 100644 scribo/demo/demat/src/main.cc create mode 100644 scribo/demo/demat/src/main_window.cc create mode 100644 scribo/demo/demat/src/main_window.hh create mode 100644 scribo/demo/demat/src/mln_widgets.cc copy scribo/demo/{wizard => demat}/src/preprocessing_task.hh (100%) create mode 100644 scribo/demo/demat/src/process_args.hh create mode 100644 scribo/demo/demat/src/runner.cc create mode 100644 scribo/demo/demat/src/runner.hh create mode 100644 scribo/demo/demat/ui/main_window.ui
diff --git a/scribo/ChangeLog b/scribo/ChangeLog index 40a5fb4..68ec602 100644 --- a/scribo/ChangeLog +++ b/scribo/ChangeLog @@ -1,5 +1,29 @@ 2010-03-19 Guillaume Lazzara z@lrde.epita.fr
+ Add a new demo in Scribo. + + * demo/demat/demat.pro, + * demo/demat/demat.qrc, + * demo/demat/src/doc_type.hh, + * demo/demat/src/main.cc, + * demo/demat/src/main_window.cc, + * demo/demat/src/main_window.hh, + * demo/demat/src/mln_widgets.cc, + * demo/demat/src/preprocessing_task.hh, + * demo/demat/src/process_args.hh, + * demo/demat/src/runner.cc, + * demo/demat/src/runner.hh, + * demo/demat/ui/main_window.ui: New. + + * demo/shared/src/crop_item.cc, + * demo/shared/src/crop_item.hh, + * demo/shared/src/image_viewer.cc, + * demo/shared/src/image_viewer.hh, + * demo/shared/ui/image_viewer.ui: Update according the needs of + this new demo. + +2010-03-19 Guillaume Lazzara z@lrde.epita.fr + Small fixes in Scribo.
* binarization/sauvola_ms.hh: Fix compilation issues on MacOS X. diff --git a/scribo/demo/demat/demat.pro b/scribo/demo/demat/demat.pro new file mode 100644 index 0000000..4f4af23 --- /dev/null +++ b/scribo/demo/demat/demat.pro @@ -0,0 +1,37 @@ +# -*- c++ -*- +###################################################################### +# Automatically generated by qmake (2.01a) Tue Feb 9 12:02:10 2010 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . src +INCLUDEPATH += . ../ ../shared $(OLN)/milena $(OLN) + +QMAKE_CXXFLAGS += -g + +LIBS += `Magick++-config --ldflags --libs` + +DEFINES += NDEBUG MLN_INCLUDE_ONLY + +# Input + HEADERS += \ + ../shared/src/image_viewer.hh \ + ../shared/src/internal/interactive_scene.hh \ + ../shared/src/crop_item.hh \ + ../shared/src/browse_widget.hh \ + src/runner.hh \ + src/main_window.hh + +SOURCES += \ + ../shared/src/crop_item.cc \ + ../shared/src/internal/interactive_scene.cc \ + ../shared/src/browse_widget.cc \ + src/mln_widgets.cc + +FORMS += \ + ../shared/ui/image_viewer.ui \ + ui/main_window.ui + + +RESOURCES += ../shared/shared.qrc demat.qrc diff --git a/scribo/demo/demat/demat.qrc b/scribo/demo/demat/demat.qrc new file mode 100644 index 0000000..68031c7 --- /dev/null +++ b/scribo/demo/demat/demat.qrc @@ -0,0 +1,4 @@ +<RCC> + <qresource prefix="images" > + </qresource> +</RCC> diff --git a/scribo/demo/wizard/src/doc_type.hh b/scribo/demo/demat/src/doc_type.hh similarity index 100% copy from scribo/demo/wizard/src/doc_type.hh copy to scribo/demo/demat/src/doc_type.hh diff --git a/scribo/demo/demat/src/main.cc b/scribo/demo/demat/src/main.cc new file mode 100644 index 0000000..ee35a48 --- /dev/null +++ b/scribo/demo/demat/src/main.cc @@ -0,0 +1,27 @@ +#include <QtGui> +#include <src/main_window.hh> +#include <src/preprocessing_task.hh> + +namespace scribo { namespace demo {extern QString basedir_; } } + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + qRegisterMetaType<preprocessing_task_set_t>("preprocessing_task_set_t"); + + if (argc == 2) + { + scribo::demo::basedir_ = argv[1]; + } + else + { + qDebug() << "Usage: " << argv[0] << " <path_to_scribo/src>"; + return 1; + } + + scribo::demo::demat::main_window win; + win.show(); + + return app.exec(); +} diff --git a/scribo/demo/demat/src/main_window.cc b/scribo/demo/demat/src/main_window.cc new file mode 100644 index 0000000..ee82ca1 --- /dev/null +++ b/scribo/demo/demat/src/main_window.cc @@ -0,0 +1,240 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see http://www.gnu.org/licenses/. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#include <src/main_window.hh> + +#include <src/doc_type.hh> +#include <src/preprocessing_task.hh> +#include <src/process_args.hh> + +#include <mln/data/convert.hh> +#include <mln/convert/to_qimage_nocopy.hh> +#include <mln/core/routine/duplicate.hh> +#include <mln/make/box2d.hh> +#include <mln/data/paste.hh> +#include <mln/io/magick/load.hh> + +namespace scribo +{ + + namespace demo + { + + namespace demat + { + + // FIXME: move it as attribute. + static mln::image2dmln::value::rgb8 input_; + + + main_window::main_window() + { + setupUi(this); + + text_->hide(); + + connect(action_Open, SIGNAL(activated()), + this, SLOT(open_file_slot())); + + connect(run_btn, SIGNAL(clicked()), this, SLOT(run())); + + + // Connections to/from task runner. + connect(&runner_, SIGNAL(new_progress_label(const QString&)), + this, SLOT(update_progress_label_slot(const QString&))); + + connect(&runner_, SIGNAL(progress(unsigned)), + this, SLOT(progress_slot(unsigned))); + connect(&runner_, SIGNAL(finished()), + this, SLOT(process_finished_slot())); + + // Connections for dock windows. + connect(advanced_dock_, SIGNAL(visibilityChanged(bool)), + actionAdvanced_options, SLOT(setChecked(bool))); + connect(options_dock_, SIGNAL(visibilityChanged(bool)), + actionOptions, SLOT(setChecked(bool))); + + connect(actionAdvanced_options, SIGNAL(triggered(bool)), + advanced_dock_, SLOT(setVisible(bool))); + connect(actionOptions, SIGNAL(triggered(bool)), + options_dock_, SLOT(setVisible(bool))); + + progress_ = new QProgressDialog(); + progress_->setLabelText("Processing..."); + progress_->setCancelButton(0); + progress_->setAutoClose(true); + + // Setup crop tool. + viewer_->set_selection_enabled(true); + connect(viewer_, SIGNAL(ready_for_crop()), this, SLOT(crop_slot())); + } + + + void main_window::open_file_slot() + { + QFileDialog dialog; + QStringList filters; + filters << tr("Image (*.ppm *.pbm *.pgm *.png *.jpg)"); + dialog.setNameFilters(filters); + + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setLabelText(QFileDialog::LookIn, + tr("Choose an existing file")); + + if (dialog.exec() && current_image_ != dialog.selectedFiles().at(0)) + { + current_image_ = dialog.selectedFiles().at(0); + load(); + } + + } + + + void main_window::load() + { + text_->hide(); + + mln::io::magick::load(input_, current_image_.toStdString()); + + input_dsp_ = QPixmap::fromImage(mln::convert::to_qimage_nocopy(input_)); + + viewer_->draw_image(input_dsp_); + } + + + void main_window::run() + { + preprocessing_task_set_t tasks = get_tasks(); + + prepare_progress_bar(tasks.size()); + + process_args args; // Nothing for now. + + runner_.start(current_image_, input_, Text_Doc, tasks, args); + } + + + preprocessing_task_set_t main_window::get_tasks() + { + preprocessing_task_set_t tasks; + + if (removeBg->isChecked()) + tasks.insert(RemoveBg); + + if (unskew->isChecked()) + tasks.insert(Unskew); + + if (removeNoise->isChecked()) + tasks.insert(RemoveNoise); + + if (improveContrast->isChecked()) + tasks.insert(ImproveContrast); + + if (reduceSize->isChecked()) + tasks.insert(ReduceSize); + + if (binarizationCBox->currentIndex() == 0) + tasks.insert(BinarizationSimple); + else if (binarizationCBox->currentIndex() == 1) + tasks.insert(BinarizationSauvola); + else if (binarizationCBox->currentIndex() == 2) + tasks.insert(BinarizationSauvolaMs); + + return tasks; + } + + + void main_window::prepare_progress_bar(unsigned max) + { + progress_->show(); + progress_->setValue(0); + progress_->setMaximum(max + 3); + } + + + void main_window::progress_slot(unsigned i) + { + progress_->setValue(progress_->value() + i); + } + + + void main_window::update_progress_label_slot(const QString& msg) + { + progress_->setLabelText(msg); + } + + + void main_window::process_finished_slot() + { + text_->clear(); + + QFile file("/tmp/out.txt"); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + + QTextStream in(&file); + in.setCodec("UTF-8"); + while (!in.atEnd()) + { + QString line = in.readLine(); + text_->append(line); + } + + + text_->show(); + } + + + void main_window::crop_slot() + { + mln::box2d b = input_.domain(); + QRectF selection = viewer_->selection(); + + mln::box2d sbox = mln::make::box2d(selection.topLeft().y(), + selection.topLeft().x(), + selection.bottomRight().y(), + selection.bottomRight().x()); + + sbox.crop_wrt(b); + + if (sbox.is_valid()) + { + // Update underlying data. + mln::image2dmln::value::rgb8 output(sbox); + mln::data::fill(output, input_); + input_ = output; + + // Update display + viewer_->draw_image(input_); + } + + viewer_->enable_crop_tool(false); // Disable crop tool + } + + } // end of namespace scribo::demo::demat + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/demat/src/main_window.hh b/scribo/demo/demat/src/main_window.hh new file mode 100644 index 0000000..f52f171 --- /dev/null +++ b/scribo/demo/demat/src/main_window.hh @@ -0,0 +1,91 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see http://www.gnu.org/licenses/. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_DEMAT_SRC_MAIN_WINDOW_HH +# define SCRIBO_DEMO_DEMAT_SRC_MAIN_WINDOW_HH + +# include <QtGui/QMainWindow> +# include <ui_main_window.h> +# include <src/doc_type.hh> +# include <src/preprocessing_task.hh> +# include <src/runner.hh> + +# include <mln/core/image/image2d.hh> +# include <mln/core/image/dmorph/image_if.hh> +# include <mln/pw/all.hh> +# include <mln/value/rgb8.hh> + + +namespace scribo +{ + + namespace demo + { + + namespace demat + { + + + class main_window : public QMainWindow, private Ui::MainWindow + { + Q_OBJECT; + + public: + main_window(); + + private slots: + void run(); + void open_file_slot(); + void progress_slot(unsigned i); + void update_progress_label_slot(const QString&); + void process_finished_slot(); + + void crop_slot(); + + private: // members + void load(); + + void prepare_progress_bar(unsigned max); + Doc_Type get_doc_type(); + preprocessing_task_set_t get_tasks(); + + private: // attributes + QPixmap input_dsp_; + + QString current_image_; + + QProgressDialog* progress_; + runner runner_; + }; + + + } // end of namespace scribo::demo::demat + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_DEMAT_SRC_MAIN_WINDOW_HH diff --git a/scribo/demo/demat/src/mln_widgets.cc b/scribo/demo/demat/src/mln_widgets.cc new file mode 100644 index 0000000..079fc7f --- /dev/null +++ b/scribo/demo/demat/src/mln_widgets.cc @@ -0,0 +1,11 @@ +#undef MLN_INCLUDE_ONLY + +// Windows +#include <src/main_window.cc> + +// Widgets +#include <shared/src/image_viewer.cc> + +// Misc +#include <src/main.cc> +#include <src/runner.cc> diff --git a/scribo/demo/wizard/src/preprocessing_task.hh b/scribo/demo/demat/src/preprocessing_task.hh similarity index 100% copy from scribo/demo/wizard/src/preprocessing_task.hh copy to scribo/demo/demat/src/preprocessing_task.hh diff --git a/scribo/demo/demat/src/process_args.hh b/scribo/demo/demat/src/process_args.hh new file mode 100644 index 0000000..5ca72cf --- /dev/null +++ b/scribo/demo/demat/src/process_args.hh @@ -0,0 +1,47 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see http://www.gnu.org/licenses/. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_PROCESS_ARGS_HH +# define SCRIBO_DEMO_SHARED_SRC_PROCESS_ARGS_HH + + +namespace scribo +{ + + namespace demo + { + + struct process_args + { + unsigned scale; + }; + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // !SCRIBO_DEMO_SHARED_SRC_PROCESS_ARGS_HH diff --git a/scribo/demo/demat/src/runner.cc b/scribo/demo/demat/src/runner.cc new file mode 100644 index 0000000..6972902 --- /dev/null +++ b/scribo/demo/demat/src/runner.cc @@ -0,0 +1,316 @@ +#include <src/runner.hh> + +#include <shared/src/to_mln_image.hh> +#include <src/preprocessing_task.hh> +#include <src/doc_type.hh> + +#include <mln/convert/to_qimage.hh> +#include <mln/convert/to_qimage_nocopy.hh> +#include <mln/fun/v2v/rgb_to_int_u.hh> +#include <mln/value/int_u8.hh> +#include <mln/value/rgb8.hh> +#include <mln/data/convert.hh> +#include <mln/data/paste_without_localization.hh> +#include <mln/io/pbm/save.hh> +#include <mln/io/magick/load.hh> +#include <mln/subsampling/antialiased.hh> + +#include <scribo/preprocessing/split_bg_fg.hh> +#include <scribo/preprocessing/denoise.hh> +#include <scribo/preprocessing/homogeneous_contrast.hh> +#include <scribo/preprocessing/unskew.hh> +#include <scribo/binarization/sauvola.hh> +#include <scribo/binarization/sauvola_ms.hh> +#include <scribo/binarization/simple.hh> + +#include <mln/logical/not.hh> + +namespace scribo +{ + + namespace demo + { + + QString basedir_ = ""; + + // FIXME: move as attribute. + mln::image2dmln::value::rgb8 input_; + + + runner::runner(QObject *parent) + : QThread(parent) + { + process_.moveToThread(this); + } + + + void runner::start(const QString& filename, + const mln::image2dmln::value::rgb8& input, + const Doc_Type& doc_type, + const preprocessing_task_set_t& tasks, + const process_args& args) + { + filename_ = filename; + doc_type_ = doc_type; + tasks_ = tasks; + args_ = args; + input_ = input; + + QThread::start(); + } + + + void runner::run() + { + // Notification of the number of tasks. + emit new_progress_max_value(tasks_.size() + 2); + + qDebug() << "progress steps : " << tasks_.size() + 2; + + image2dvalue::rgb8 ima = load(); + + preprocess(ima); + + process(); + } + + + image2dvalue::rgb8 runner::load() + { + emit new_progress_label("Loading image"); + + image2dvalue::rgb8 output(input_.nrows(), input_.ncols(), + input_.border()); + data::paste_without_localization(input_, output); + +// io::magick::load(output, filename_.toStdString()); + + emit progress(1); + + return output; + } + + + void runner::preprocess(const image2dvalue::rgb8& ima) + { + + image2dvalue::rgb8 tmp_color = duplicate(ima); + + + //================== + // Remove background + //================== + if (tasks_.contains(RemoveBg)) + { + std::cout << "Foreground extraction" << std::endl; + emit new_progress_label("Foreground Extraction"); + + tmp_color = scribo::preprocessing::split_bg_fg(tmp_color, 10000, 32).second(); + + emit progress(1); + } + + + //============================================= + // Convert to grayscale image (always happens). + //============================================= + emit new_progress_label("Convert to gray-scale image"); + image2dvalue::int_u8 + intensity_ima = data::transform(tmp_color, + mln::fun::v2v::rgb_to_int_u<8>()); + emit progress(1); + + + // FIXME: SUbsampling should be done at the very beginning!!!! + // + //========== + // Subsample + //========== + if (tasks_.contains(ReduceSize)) + { + emit new_progress_label("Subsampling input image"); + intensity_ima = mln::subsampling::antialiased(intensity_ima, + find_best_scale(intensity_ima)); + emit progress(1); + } + + + //============================= + // Improve contrast homogeneity + //============================= + if (tasks_.contains(ImproveContrast)) + { + std::cout << "Improve contrast homogeneity" << std::endl; + emit new_progress_label("Improve contrast homogeneity"); + + intensity_ima = arith::revert(preprocessing::homogeneous_contrast(intensity_ima, 75)); + + emit progress(1); + } + + + std::cout << intensity_ima.domain() << std::endl; + io::pgm::save(intensity_ima, "intensity_ima.pgm"); + + //============================== + // Binarization (always happens) + //============================== + image2d<bool> out_bool; + emit new_progress_label("Binarization"); + + if (tasks_.contains(BinarizationSauvola)) + { + // FIXME: sauvola should not negate the image. + std::cout << "Binarization Sauvola" << std::endl; + out_bool = binarization::sauvola(intensity_ima); + } + else if (tasks_.contains(BinarizationSauvolaMs)) + { + // FIXME: sauvola should not negate the image. + std::cout << "Binarization Sauvola_ms" << std::endl; + out_bool = binarization::sauvola_ms(intensity_ima, 51, 2, 67); + } + else if (tasks_.contains(BinarizationSimple)) + { + std::cout << "Binarization Simple" << std::endl; + out_bool = scribo::binarization::simple(intensity_ima); + } + else + { + std::cout << "Binary image conversion" << std::endl; + out_bool = data::convert(bool(), intensity_ima); + } + + emit progress(1); + + + // FIXME: remove! +// logical::not_inplace(out_bool); + + //======== + // Denoise + //======== +// if (tasks_.contains(RemoveNoise)) +// { +// std::cout << "Remove noise" << std::endl; +// emit new_progress_label("Remove noise"); + +// out_bool = preprocessing::denoise(out_bool, c8(), 2, 2); + +// emit progress(1); +// } + + //======= + // Unskew + //======= + if (tasks_.contains(Unskew)) + { + std::cout << "Unskew" << std::endl; + emit new_progress_label("Unskew"); + + out_bool = scribo::preprocessing::unskew(out_bool).first(); + + emit progress(1); + } + + + //========================= + // Save preprocessed image. + //========================= + io::pbm::save(out_bool, "/tmp/tmp.pbm"); + } + + + void runner::process() + { + QStringList args; + + + // FIXME: require binaries to ask for a filename for bboxes + // output files. + switch(doc_type_) + { + case Text_Doc: + emit new_progress_label("Finding text in document..."); + qDebug() << "Running text_in_article_pbm"; + args << "/tmp/tmp.pbm" << "/tmp/out.txt"; + + // Denoise. + if (! tasks_.contains(RemoveNoise)) + args << "0"; + else + { + args << "1"; + emit progress(1); // Consider denoising as done even though it is performed later. + } + + args << "/tmp/"; + + if (process_.execute(basedir_ + "/text_in_article_pbm", args)) + { + qDebug() << "Error while running text_in_article_pbm."; + return; + } + break; + + case Picture: + emit new_progress_label("Finding text in picture..."); + qDebug() << "Running text_in_photo_pbm_fast"; + args << "/tmp/tmp.pbm" << "/tmp/out.ppm" << "1" << "1" << "1"; + if (process_.execute(basedir_ + "/text_in_photo_pbm_fast", args)) + { + qDebug() << "Error while running text_in_photo_pbm_fast."; + return; + } + break; + + case Mixed_Doc: + qDebug() << "Running pbm_text_in_mixed_doc"; + if (process_.execute(basedir_ + "/pbm_text_in_mixed_doc", args)) + { + qDebug() << "Error while running pbm_text_in_mixed_doc."; + return; + } + break; + + default: + case Invalid_Doc: + qDebug() << "runner - Invalid doc type..."; + return; + } + + process_.waitForFinished(-1); + + emit progress(1); + + emit finished(); + qDebug() << "Done"; + } + + + void runner::stop() + { + process_.kill(); + terminate(); + } + + + template <typename V> + unsigned runner::find_best_scale(const image2d<V>& ima) + { + if (ima.nrows() > 2500 + && ima.nrows() < 5000 + && ima.ncols() > 2500 + && ima.ncols() < 5000) + return 2; + + if (ima.nrows() > 5000 + && ima.ncols() > 5000) + return 3; + + return 1; + } + + } // end of namespace scribo::demo + +} // end of namespace scribo diff --git a/scribo/demo/demat/src/runner.hh b/scribo/demo/demat/src/runner.hh new file mode 100644 index 0000000..93e91bc --- /dev/null +++ b/scribo/demo/demat/src/runner.hh @@ -0,0 +1,93 @@ +// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Olena. If not, see http://www.gnu.org/licenses/. +// +// As a special exception, you may use this file as part of a free +// software project without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to produce +// an executable, this file does not by itself cause the resulting +// executable to be covered by the GNU General Public License. This +// exception does not however invalidate any other reasons why the +// executable file might be covered by the GNU General Public License. + +#ifndef SCRIBO_DEMO_SHARED_SRC_RUNNER_HH +# define SCRIBO_DEMO_SHARED_SRC_RUNNER_HH + +# include <QtGui> +# include <QProcess> + +# include <src/preprocessing_task.hh> +# include <src/doc_type.hh> + +# include <mln/core/image/image2d.hh> +# include <mln/value/qt/rgb32.hh> + +#include <src/process_args.hh> + +namespace scribo +{ + + namespace demo + { + + + class runner : public QThread + { + Q_OBJECT; + + public: + runner(QObject *parent = 0); + + void start(const QString& filename, + const mln::image2dmln::value::rgb8& input, + const Doc_Type& doc_type, + const preprocessing_task_set_t& tasks, + const process_args& args); + + void stop(); + + signals: + void new_intermediate_result(const QImage& ima); + void new_progress_max_value(unsigned i); + void new_progress_label(const QString& msg); + void progress(unsigned i); + void finished(); + + private: // members + mln::image2dmln::value::rgb8 load(); + void preprocess(const mln::image2dmln::value::rgb8& ima); + void process(); + virtual void run(); + + template <typename V> + unsigned find_best_scale(const mln::image2d<V>& ima); + + private: // attributes + QProcess process_; + Doc_Type doc_type_; + QSet<Preprocessing_Task> tasks_; + QString filename_; + process_args args_; + }; + + + + } // end of namespace scribo::demo + +} // end of namespace scribo + + +#endif // ! SCRIBO_DEMO_SHARED_SRC_RUNNER_HH diff --git a/scribo/demo/demat/ui/main_window.ui b/scribo/demo/demat/ui/main_window.ui new file mode 100644 index 0000000..a552500 --- /dev/null +++ b/scribo/demo/demat/ui/main_window.ui @@ -0,0 +1,366 @@ +<ui version="4.0" > + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>666</width> + <height>647</height> + </rect> + </property> + <property name="windowTitle" > + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget" > + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QSplitter" name="splitter" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <widget class="scribo::demo::shared::image_viewer" name="viewer_" /> + <widget class="QTextEdit" name="text_" /> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="run_btn" > + <property name="text" > + <string>&Run</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>666</width> + <height>24</height> + </rect> + </property> + <widget class="QMenu" name="menu_File" > + <property name="title" > + <string>&File</string> + </property> + <addaction name="action_Open" /> + <addaction name="separator" /> + <addaction name="action_Quit" /> + </widget> + <widget class="QMenu" name="menuWindow" > + <property name="title" > + <string>&Dialogs</string> + </property> + <addaction name="actionOptions" /> + <addaction name="actionAdvanced_options" /> + </widget> + <addaction name="menu_File" /> + <addaction name="menuWindow" /> + </widget> + <widget class="QStatusBar" name="statusbar" /> + <widget class="QDockWidget" name="options_dock_" > + <property name="font" > + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="floating" > + <bool>false</bool> + </property> + <property name="features" > + <set>QDockWidget::AllDockWidgetFeatures</set> + </property> + <property name="allowedAreas" > + <set>Qt::AllDockWidgetAreas</set> + </property> + <property name="windowTitle" > + <string>Options</string> + </property> + <attribute name="dockWidgetArea" > + <number>1</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents" > + <layout class="QVBoxLayout" name="verticalLayout_7" > + <item> + <layout class="QVBoxLayout" name="verticalLayout_4" > + <item> + <widget class="QCheckBox" name="removeBg" > + <property name="font" > + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="text" > + <string>Remove background (slow)</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="unskew" > + <property name="font" > + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="text" > + <string>Unskew</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="removeNoise" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="font" > + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="text" > + <string>Remove noise</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="improveContrast" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="font" > + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="text" > + <string>Improve brightness/contrast</string> + </property> + <property name="checked" > + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_3" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <widget class="QDockWidget" name="advanced_dock_" > + <property name="font" > + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="windowTitle" > + <string>Advanced options</string> + </property> + <attribute name="dockWidgetArea" > + <number>1</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents_3" > + <layout class="QVBoxLayout" name="verticalLayout_8" > + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2" > + <item> + <widget class="QCheckBox" name="reduceSize" > + <property name="font" > + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="text" > + <string>Run on subsampled image</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_6" > + <item> + <widget class="QLabel" name="binarizeLbl" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font" > + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="text" > + <string>Binarization method:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="binarizationCBox" > + <property name="font" > + <font> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="currentIndex" > + <number>2</number> + </property> + <item> + <property name="text" > + <string>Global threshold</string> + </property> + </item> + <item> + <property name="text" > + <string>Local threshold</string> + </property> + </item> + <item> + <property name="text" > + <string>Local threshold multi-scale</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_2" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + <action name="action_Open" > + <property name="text" > + <string>&Open</string> + </property> + <property name="shortcut" > + <string>Ctrl+O</string> + </property> + </action> + <action name="action_Quit" > + <property name="text" > + <string>&Quit</string> + </property> + </action> + <action name="actionDocument_Type" > + <property name="checkable" > + <bool>true</bool> + </property> + <property name="checked" > + <bool>true</bool> + </property> + <property name="text" > + <string>Document Type</string> + </property> + </action> + <action name="actionOptions" > + <property name="checkable" > + <bool>true</bool> + </property> + <property name="checked" > + <bool>true</bool> + </property> + <property name="text" > + <string>Options</string> + </property> + </action> + <action name="actionAdvanced_options" > + <property name="checkable" > + <bool>true</bool> + </property> + <property name="checked" > + <bool>true</bool> + </property> + <property name="text" > + <string>Advanced options</string> + </property> + </action> + </widget> + <customwidgets> + <customwidget> + <class>scribo::demo::shared::image_viewer</class> + <extends>QGraphicsView</extends> + <header location="global" >shared/src/image_viewer.hh</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>action_Quit</sender> + <signal>activated()</signal> + <receiver>MainWindow</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel" > + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel" > + <x>332</x> + <y>298</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/scribo/demo/shared/src/crop_item.cc b/scribo/demo/shared/src/crop_item.cc index 100ac7d..70598fa 100644 --- a/scribo/demo/shared/src/crop_item.cc +++ b/scribo/demo/shared/src/crop_item.cc @@ -46,6 +46,11 @@ namespace scribo grabMouse(); }
+ crop_item::~crop_item() + { + + } + void crop_item::reset() { if (parentItem()) @@ -54,15 +59,15 @@ namespace scribo cropRect_ = QRectF(20, 20, 100, 70); }
- const QRectF& crop_item::cropRect() const + QRectF crop_item::cropRect() const { - return cropRect_; + return mapToScene(cropRect_).boundingRect(); }
QRectF crop_item::boundingRect() const { - return parentItem()->boundingRect(); + return scene()->sceneRect(); }
void crop_item::paint(QPainter *painter, @@ -84,15 +89,16 @@ namespace scribo painter->fillPath(windowPath, QColor(0x33, 0x33, 0x33, 0xcc));
// Draw Crop Rect - painter->setPen(QPen(QColor(0xdd, 0xdd, 0xdd), 1)); + // QColor(0xdd, 0xdd, 0xdd) + painter->setPen(QPen(Qt::magenta, 3)); painter->drawPath(cropPath);
int topRightX = cropRect_.x() + cropRect_.width(); int bottomY = cropRect_.y() + cropRect_.height();
QPainterPath borderPath; - int corner_width = cropRect_.width() / 6.f; - int corner_height = cropRect_.height() / 6.f; + int corner_width = std::min(int(cropRect_.width() / 6.f), 80); + int corner_height = std::min(int(cropRect_.height() / 6.f), 80);
// Top-Left Corner painter->drawRect(QRectF(cropRect_.x(), cropRect_.y(), @@ -128,8 +134,8 @@ namespace scribo cropResize_ = CropItemResizeNone; if (event->buttons() & Qt::LeftButton) { - int wsize = cropRect_.width() / 6.f; - int hsize = cropRect_.height() / 6.f; + int wsize = std::min(int(cropRect_.width() / 6.f), 80); + int hsize = std::min(int(cropRect_.height() / 6.f), 80);
int rightX = cropRect_.x() + cropRect_.width() - wsize; int leftX = cropRect_.x(); @@ -305,6 +311,29 @@ namespace scribo }
+ void crop_item::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event) + { + QGraphicsItem::mouseDoubleClickEvent(event); + + switch (cropResize_) + { + case CropItemResizeNone: + if (!cropRect_.contains(event->pos())) + return; + + setCursor(Qt::SizeAllCursor); + + if (!(event->buttons() & Qt::LeftButton)) + return; + + emit ready_for_crop(); + break; + + default: + break; + } + } + } // end of namespace scribo::demo::shared
} // end of namespace scribo::demo diff --git a/scribo/demo/shared/src/crop_item.hh b/scribo/demo/shared/src/crop_item.hh index c0b1394..d342f23 100644 --- a/scribo/demo/shared/src/crop_item.hh +++ b/scribo/demo/shared/src/crop_item.hh @@ -50,11 +50,15 @@ namespace scribo namespace shared {
- class crop_item : public QGraphicsItem + class crop_item : public QObject, public QGraphicsItem { + Q_OBJECT; + public: crop_item(QGraphicsItem *parent); - const QRectF& cropRect() const; + virtual ~crop_item(); + + QRectF cropRect() const;
QRectF boundingRect() const; void paint (QPainter *painter, @@ -67,9 +71,13 @@ namespace scribo void mousePressEvent (QGraphicsSceneMouseEvent *event); void mouseReleaseEvent (QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event);
// void updateCursor(QGraphicsSceneMouseEvent *event);
+ signals: + void ready_for_crop(); + private: enum CropItemResize { diff --git a/scribo/demo/shared/src/image_viewer.cc b/scribo/demo/shared/src/image_viewer.cc index b61f86b..f9467dc 100644 --- a/scribo/demo/shared/src/image_viewer.cc +++ b/scribo/demo/shared/src/image_viewer.cc @@ -38,7 +38,8 @@ namespace scribo {
image_viewer::image_viewer(QWidget *parent) - : QWidget(parent), image_(0), selection_(0), angle_(0) + : QWidget(parent), image_(0), selection_(0), angle_(0), + zoom_fixed_(false) { setupUi(this);
@@ -87,7 +88,8 @@ namespace scribo viewer_->show(); }
- void image_viewer::draw_image(const mln::image2d<dsp_data_t>& ima) + template <typename V> + void image_viewer::draw_image(const mln::image2d<V>& ima) { QImage qima = mln::convert::to_qimage_nocopy(ima); @@ -127,18 +129,15 @@ namespace scribo if (pixmap.width() > viewer_->maximumViewportSize().width()) viewer_->fitInView(image_->boundingRect(), Qt::KeepAspectRatio);
- zoomLabel->setEnabled(true); - zoomIn->setEnabled(true); - zoomOut->setEnabled(true); - zoomFixed->setEnabled(true); - zoomOriginal->setEnabled(true); + enable_widgets(true);
image_->translate(origin.x(), origin.y());
+ viewer_->setSceneRect(image_->sceneBoundingRect());
// Restore selection mode if needed - set_selection_enabled(restore_selection); + on_crop_btn_toggled(restore_selection); }
@@ -150,8 +149,11 @@ namespace scribo
void image_viewer::resizeEvent(QResizeEvent * event) { - if (image_ != 0) - resize_image(image_->boundingRect()); + if (zoom_fixed_) + on_zoomFixed_clicked(); + else + on_zoomOriginal_clicked(); + event->ignore(); }
@@ -238,12 +240,14 @@ namespace scribo
void image_viewer::on_zoomFixed_clicked() { + zoom_fixed_ = true; if (image_ != 0) resize_image(image_->boundingRect()); }
void image_viewer::on_zoomOriginal_clicked() { + zoom_fixed_ = false; if (image_ != 0) resize_image(viewer_->viewport()->geometry()); } @@ -259,12 +263,17 @@ namespace scribo } }
- void image_viewer::set_selection_enabled(bool b) + void image_viewer::on_crop_btn_toggled(bool b) { if (b) { if (selection_ == 0) + { selection_ = new crop_item(image_); + connect(selection_, SIGNAL(ready_for_crop()), + this, SIGNAL(ready_for_crop())); + + } } else { @@ -274,6 +283,18 @@ namespace scribo }
+ void image_viewer::enable_crop_tool(bool b) + { + crop_btn->setChecked(b); + } + + + void image_viewer::set_selection_enabled(bool b) + { + crop_btn->setVisible(b); + } + + void image_viewer::set_rotation_enabled(bool b) { angle_ = 0; @@ -290,12 +311,11 @@ namespace scribo }
- const QRectF& image_viewer::selection() const + QRectF image_viewer::selection() const { static QRectF invalid_selection; - mln_assertion(has_selection());
- if (selection_) + if (has_selection()) return selection_->cropRect();
return invalid_selection; @@ -337,6 +357,23 @@ namespace scribo on_slider_valueChanged(sli); }
+ + void image_viewer::enable_widgets(bool b) + { + zoomLabel->setEnabled(b); + zoomIn->setEnabled(b); + zoomOut->setEnabled(b); + zoomFixed->setEnabled(b); + zoomOriginal->setEnabled(b); + + rotate_ccw_btn->setEnabled(b); + rotate_cw_btn->setEnabled(b); + rotate_lbl->setEnabled(b); + + crop_btn->setEnabled(b); + } + + } // end of namespace scribo::demo::shared
} // end of namespace scribo::demo diff --git a/scribo/demo/shared/src/image_viewer.hh b/scribo/demo/shared/src/image_viewer.hh index 628f5d4..3fe23ab 100644 --- a/scribo/demo/shared/src/image_viewer.hh +++ b/scribo/demo/shared/src/image_viewer.hh @@ -60,7 +60,8 @@ namespace scribo image_viewer(QWidget *parent = 0); ~image_viewer();
- void draw_image(const mln::image2d<dsp_data_t>& ima); + template <typename V> + void draw_image(const mln::image2d<V>& ima); void draw_image(const QPixmap& pixmap); void draw_image(const QPixmap& pixmap, const QPoint& origin);
@@ -76,7 +77,7 @@ namespace scribo
bool has_selection() const; - const QRectF& selection() const; + QRectF selection() const;
bool has_rotation() const; qreal rotation() const; @@ -91,12 +92,16 @@ namespace scribo void keyPressEvent(QKeyEvent *event); void resizeEvent(QResizeEvent * event);
+ void enable_widgets(bool b); + private slots: void visible_slider(bool b);
void move_vertical_sliders(int value); void move_horizontal_sliders(int value);
+ void on_crop_btn_toggled(bool b); + void on_slider_valueChanged(int sli);
void on_rotate_cw_btn_clicked(); @@ -111,10 +116,11 @@ namespace scribo public slots: void set_image_layer_count(unsigned nslis); void update_image(const mln::image2d<dsp_data_t>& ima); - + void enable_crop_tool(bool b);
signals: void slider_valueChanged(int sli); + void ready_for_crop();
private: // attributes QGraphicsPixmapItem* image_; @@ -122,6 +128,8 @@ namespace scribo bool mouse_moving_; QPoint p_start_; qreal angle_; + + bool zoom_fixed_; };
diff --git a/scribo/demo/shared/ui/image_viewer.ui b/scribo/demo/shared/ui/image_viewer.ui index d6f80cb..c129b97 100644 --- a/scribo/demo/shared/ui/image_viewer.ui +++ b/scribo/demo/shared/ui/image_viewer.ui @@ -5,7 +5,7 @@ <rect> <x>0</x> <y>0</y> - <width>464</width> + <width>529</width> <height>350</height> </rect> </property> @@ -37,7 +37,33 @@ </spacer> </item> <item> + <widget class="QPushButton" name="crop_btn" > + <property name="enabled" > + <bool>false</bool> + </property> + <property name="maximumSize" > + <size> + <width>16777215</width> + <height>20</height> + </size> + </property> + <property name="text" > + <string>Crop</string> + </property> + <property name="icon" > + <iconset resource="../shared.qrc" > + <normaloff>:/icons/icons/crop-icon.png</normaloff>:/icons/icons/crop-icon.png</iconset> + </property> + <property name="checkable" > + <bool>true</bool> + </property> + </widget> + </item> + <item> <widget class="QLabel" name="rotate_lbl" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="text" > <string>Rotate:</string> </property> @@ -45,6 +71,9 @@ </item> <item> <widget class="QPushButton" name="rotate_cw_btn" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="toolTip" > <string>Rotate clock-wise</string> </property> @@ -59,6 +88,9 @@ </item> <item> <widget class="QPushButton" name="rotate_ccw_btn" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="toolTip" > <string>Rotate counter-clock-wise</string> </property>