erosion-cli.cpp 3.84 KB
Newer Older
Edwin Carlinet's avatar
Edwin Carlinet committed
1
2
#include <mln/core/image/experimental/ndimage.hpp>

3
#include <mln/core/se/rect2d.hpp>
4

Edwin Carlinet's avatar
Edwin Carlinet committed
5
6
7
8
9
10
11
12
13
#include <mln/morpho/experimental/closing.hpp>
#include <mln/morpho/experimental/dilation.hpp>
#include <mln/morpho/experimental/erosion.hpp>
#include <mln/morpho/experimental/opening.hpp>
#include <mln/morpho/experimental/median_filter.hpp>

#include <mln/io/experimental/imread.hpp>
#include <mln/io/experimental/imsave.hpp>

14
15
16

#include <algorithm>
#include <boost/program_options.hpp>
Michaël Roynard's avatar
Michaël Roynard committed
17
#include <cctype>
18
#include <iostream>
Michaël Roynard's avatar
Michaël Roynard committed
19
#include <string>
20
21
22
23
24
25
26
27
28
29
30

namespace po = boost::program_options;

enum se_type
{
  kSquare,
  kDisc,
  kDiamond
};


Edwin Carlinet's avatar
Edwin Carlinet committed
31
32
33
34
35
int tolower_safe(int c)
{
  return std::tolower(static_cast<unsigned char>(c));
}

Michaël Roynard's avatar
Michaël Roynard committed
36
std::istream& operator>>(std::istream& in, se_type& se)
37
38
39
{
  std::string token;
  in >> token;
Edwin Carlinet's avatar
Edwin Carlinet committed
40
  std::transform(token.begin(), token.end(), token.begin(), tolower_safe);
41
42
43
44
45
46
47
  if (token == "square")
    se = kSquare;
  else if (token == "disc")
    se = kDisc;
  else if (token == "diamond")
    se = kDiamond;
  else
Michaël Roynard's avatar
Michaël Roynard committed
48
    throw po::invalid_option_value("Invalid SE");
49
50
51
52
53
54
55
56
  return in;
}

enum morpho_op_type
{
  kErosion,
  kDilation,
  kOpening,
Edwin Carlinet's avatar
Edwin Carlinet committed
57
58
  kClosing,
  kMedian,
59
60
};

Michaël Roynard's avatar
Michaël Roynard committed
61
std::istream& operator>>(std::istream& in, morpho_op_type& se)
62
63
64
{
  std::string token;
  in >> token;
Edwin Carlinet's avatar
Edwin Carlinet committed
65
  std::transform(token.begin(), token.end(), token.begin(), tolower_safe);
66
67
68
69
70
71
72
73
  if (token == "erosion")
    se = kErosion;
  else if (token == "dilation")
    se = kDilation;
  else if (token == "opening")
    se = kOpening;
  else if (token == "closing")
    se = kClosing;
Edwin Carlinet's avatar
Edwin Carlinet committed
74
75
  else if (token == "median")
    se = kMedian;
76
  else
Michaël Roynard's avatar
Michaël Roynard committed
77
    throw po::invalid_option_value("Invalid Operator");
78
79
80
81
82
83
  return in;
}


struct exec_params_type
{
Michaël Roynard's avatar
Michaël Roynard committed
84
  se_type        se;
85
  morpho_op_type op;
Michaël Roynard's avatar
Michaël Roynard committed
86
  int            size;
87
88
89
90
91
};


int main(int argc, char** argv)
{
Michaël Roynard's avatar
Michaël Roynard committed
92
  po::options_description            desc("Allowed options");
93
  po::positional_options_description p;
Michaël Roynard's avatar
Michaël Roynard committed
94
95
96
97
98
99
  p.add("operator", 1).add("se", 1).add("size", 1).add("input", 1).add("output", 1);

  desc.add_options()("help", "produce help message")("operator", po::value<morpho_op_type>()->required(), "")(
      "se", po::value<se_type>()->required(), "")("size", po::value<int>()->required(), "Size of the SE.")(
      "input", po::value<std::string>()->required(),
      "Input image (8u or rgb8)")("output", po::value<std::string>()->required(), "Output image (8u or rgb8)");
100
101

  po::variables_map vm;
Michaël Roynard's avatar
Michaël Roynard committed
102
  int               size;
103
104
105
106
107
108
109
110
111
112
113
114
115
  try
  {
    po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
    po::notify(vm);
    size = vm["size"].as<int>();
    if (size < 1 || size % 2 == 0)
    {
      std::cerr << "Size must be positive and odd.\n";
      return 1;
    }
  }
  catch (...)
  {
Michaël Roynard's avatar
Michaël Roynard committed
116
117
118
119
120
121
122
    std::cout << "Usage: " << argv[0]
              << " [-h,--help] OPERATOR SE size input output\n"
                 "OPERATOR\t Morphological operation to perform [erosion | dilation]\n"
                 "SE\t Structuring element to use [square | disc | diamond]\n"
                 "size\t Size of the SE\n"
                 "input\t Input image (u8)\n"
                 "output\t Output image (u8)\n";
123
124
125
    return 1;
  }

Edwin Carlinet's avatar
Edwin Carlinet committed
126
127
  mln::experimental::image2d<mln::uint8> input, output;
  mln::io::experimental::imread(vm["input"].as<std::string>(), input);
128
129


Edwin Carlinet's avatar
Edwin Carlinet committed
130
  mln::experimental::se::rect2d nbh(size, size);
131
132
133
134

  switch (vm["operator"].as<morpho_op_type>())
  {
  case kErosion:
Edwin Carlinet's avatar
Edwin Carlinet committed
135
    output = mln::morpho::experimental::erosion(input, nbh);
136
137
    break;
  case kDilation:
Edwin Carlinet's avatar
Edwin Carlinet committed
138
    output = mln::morpho::experimental::dilation(input, nbh);
139
140
    break;
  case kOpening:
Edwin Carlinet's avatar
Edwin Carlinet committed
141
    output = mln::morpho::experimental::opening(input, nbh);
142
143
    break;
  case kClosing:
Edwin Carlinet's avatar
Edwin Carlinet committed
144
145
146
147
    output = mln::morpho::experimental::closing(input, nbh);
    break;
  case kMedian:
    output = mln::morpho::experimental::median_filter(input, nbh, mln::extension::bm::mirror{});
148
149
150
    break;
  }

Edwin Carlinet's avatar
Edwin Carlinet committed
151
  mln::io::experimental::imsave(output, vm["output"].as<std::string>());
152
}