
https://svn/svn/oln/prototypes/proto-1.0/olena Index: ChangeLog from Nicolas Widynski <nicolas.widynski@lrde.epita.fr> Fix bugs and update snakes for multi segmentation. * oln/appli/snakes/snakes.cc: Fix bugs. * oln/appli/snakes/snakes.hh: Update snakes for multi segmentation. snakes.cc | 289 +++++++++++++++++++++++++++++++++++++++++++++----------------- snakes.hh | 75 +++++++++++----- 2 files changed, 269 insertions(+), 95 deletions(-) Index: oln/appli/snakes/snakes.cc --- oln/appli/snakes/snakes.cc (revision 484) +++ oln/appli/snakes/snakes.cc (working copy) @@ -24,12 +24,8 @@ mask[*it] = true; for_all(p) - { if (mask[p] == true) out[p] = 255; - else - out[p] = input[p]; - } } template <typename T> @@ -52,17 +48,30 @@ for (; it2 != vec.end(); it2++) mask[*it2] = true; } - for_all(p) - { if (mask[p] == true) out[p] = 255; - else - out[p] = input[p]; - } } +template <typename T> +void my_copy(const oln::image2d<T>& input, + oln::image2d<T>& out) +{ + oln_iter_type(oln::image2d<T>) p(input); + for_all(p) + out[p] = input[p]; +} + +template <typename T> +bool is_element_vec(const std::vector<T>& v, const T& elt) +{ + typename std::vector<T>::const_iterator it = v.begin(); + for (; it != v.end(); it++) + if (*it == elt) + return true; + return false; +} bool nearly_equal(int x1, int x2, int y1, int y2) { @@ -70,78 +79,130 @@ } template <typename T> -std::vector<oln::point2d> tri_vec(const oln::image2d<T>& ima, +int chemin(const std::vector<oln::point2d>& v, + const oln::image2d<T>& ima, + std::vector<oln::point2d>& seen, + // const oln::point2d& pred, + const oln::point2d& p, + oln::point2d& f, + oln::point2d& tmp, + int& max, + bool& stop) +{ + oln_neighb_type(oln::window2d) q(oln::win_c8p(), p); + bool end = true; + seen.push_back(p); + for_all (q) + { + if (is_element_vec(seen, (oln::point2d)(q)) == 0 and + is_element_vec(v, (oln::point2d)(q))) + { + int res = 1 + chemin(v, ima, seen, q, f, tmp, max, stop); + if (res > max) + { + max = res; + f = tmp; + } + end = false; + } + } + if (end) + { + tmp = p; + return 1; + } + return 0; +} + + +std::vector<oln::point2d> verify_snaxels(const std::vector<oln::point2d>& v_init, const std::vector<oln::point2d>& v) { std::vector<oln::point2d> res; + + if (v_init.size() - v.size() > 5) + { std::vector<oln::point2d>::const_iterator it; - std::vector<oln::point2d>::iterator it2; + for (it = v_init.begin(); it != v_init.end(); it++) + if (is_element_vec(v, *it) == 0) + res.push_back(*it); + } + return res; +} - int ex_1_x = -100; - int ex_1_y = -100; - int ex_2_x = 0; - int ex_2_y = 0; - int save_x = -1; - int save_y = -1; - for (int i = 0; i < 2; i++) +template <typename T> +std::vector<oln::point2d> tri_vec(const oln::image2d<T>& ima, + const std::vector<oln::point2d>& v, + snake_type type) // OUVERT || FERME { - double min = 100000000; + std::vector<oln::point2d> res; + std::vector<oln::point2d>::const_iterator it; + std::vector<oln::point2d>::iterator it2; + oln::point2d dep; + oln::point2d tmp2; + oln::point2d arr; + + bool stop = false; + oln::point2d beg(-1,-1); for (it = v.begin(); it != v.end(); it++) { - if (i and nearly_equal((*it).row(), ex_1_x, (*it).col(), ex_1_y)) - continue; - - double tmp1 = oln::snakes::impl::euclidian_distance((*it).row(), 0, 0, 0); - double tmp2 = oln::snakes::impl::euclidian_distance((*it).row(), ima.nrows(), 0, 0); - double tmp3 = oln::snakes::impl::euclidian_distance(0, 0, (*it).col(), 0); - double tmp4 = oln::snakes::impl::euclidian_distance(0, 0, (*it).col(), ima.ncols()); - - double tmp_min; - - if (tmp1 <= tmp2 and tmp1 <= tmp3 and tmp1 <= tmp4) - tmp_min = tmp1; - if (tmp2 <= tmp1 and tmp2 <= tmp3 and tmp2 <= tmp4) - tmp_min = tmp2; - if (tmp3 <= tmp1 and tmp3 <= tmp2 and tmp3 <= tmp4) - tmp_min = tmp3; - if (tmp4 <= tmp1 and tmp4 <= tmp2 and tmp4 <= tmp3) - tmp_min = tmp4; - - if (tmp_min < min) - { - min = tmp_min; - save_x = (*it).row(); - save_y = (*it).col(); + unsigned nb_nbh = 0; + oln_neighb_type(oln::window2d) q(oln::win_c8p(), *it); + for_all (q) + if ((oln::point2d)(q) != *it and ima.hold(q) and is_element_vec(v, (oln::point2d)(q))) + ++nb_nbh; + if (nb_nbh == 2) + { + beg = *it; + break; } } - if (not i) + if (beg.row() == -1) + beg = *(v.begin() + v.size() / 2); + + dep = beg; + arr = beg; + std::vector<oln::point2d> seen; + + int i = 0; + oln_neighb_type(oln::window2d) q(oln::win_c8p(), beg); + for_all (q) { - ex_1_x = save_x; - ex_1_y = save_y; - } - else + if ((oln::point2d)(q) != beg and ima.hold(q) and is_element_vec(v, (oln::point2d)(q))) { - ex_2_x = save_x; - ex_2_y = save_y; + bool s = false; + int max = 0; + + seen.push_back(beg); + if (not i) + chemin(v, ima, seen, (oln::point2d)(q), dep, tmp2, max, s); + else + chemin(v, ima, seen, (oln::point2d)(q), arr, tmp2, max, s); + + seen.clear(); + i++; } } - - res.push_back(oln::point2d(ex_1_x, ex_1_y)); + res.push_back(dep); std::vector<oln::point2d> tmp; for (it = v.begin(); it != v.end(); it++) - if (((*it).row() != ex_1_x or (*it).col() != ex_1_y) and - ((*it).row() != ex_2_x or (*it).col() != ex_2_y)) + if (*it != dep) + if (type == OUVERT) + { + if (*it != arr) + tmp.push_back(*it); + } + else tmp.push_back(*it); - bool stop = false; - - int tmp_x = ex_1_x; - int tmp_y = ex_1_y; + stop = false; + int tmp_x = dep.row(); + int tmp_y = dep.col(); while (stop == false) { @@ -160,23 +221,83 @@ p_ref = it2; } } + if (min <= 10) res.push_back(p); tmp.erase(p_ref); + if (min <= 10) + { tmp_x = p.row(); tmp_y = p.col(); } - else - { - res.push_back(oln::point2d(tmp.front().row(), tmp.front().col())); + if (tmp.size() == 1) stop = true; } } - res.push_back(oln::point2d(ex_2_x, ex_2_y)); + if (type == OUVERT or is_element_vec(res, arr) == 0) + res.push_back(arr); + return res; +} + + +std::vector<std::vector<oln::point2d> > filter_size(std::vector<std::vector<oln::point2d> >& v) +{ + std::vector<std::vector<oln::point2d> > res; + + for (int i = 0; i < v.size(); i++) + if (v[i].size() > 4) + res.push_back(v[i]); + return res; } +void decoup_set(std::vector<std::vector<oln::point2d> >& v) +{ + std::vector<oln::point2d>::iterator it; + std::vector<oln::point2d>::iterator it2; + bool stop = false; + + for (int i = 0; stop == false and i < v.size(); i++) + for (int j = i + 1; stop == false and j < v.size(); j++) + for (it = v[i].begin(); stop == false and it != v[i].end(); it++) + for (it2 = v[j].begin(); stop == false and it2 != v[j].end(); it2++) + if (nearly_equal((*it).row(), (*it2).row(), (*it).col(), (*it2).col())) + { + std::vector<oln::point2d> n1; + std::vector<oln::point2d> n2; + + std::vector<oln::point2d>::iterator it3; + std::vector<oln::point2d>::iterator it4; + + if (it + 1 != v[i].end() and it + 2 != v[i].end() and it + 3 != v[i].end() and + it != v[i].begin() and it + 1 != v[i].begin() and it + 2 != v[i].begin()) + { + for (it3 = it + 1; it3 != v[i].end(); it3++) + n1.push_back(*it3); + v[i].erase(it + 1, v[i].end() - 1); + } + + if (it2 + 1 != v[j].end() and it2 + 2 != v[j].end() and it2 + 3 != v[j].end() and + it2 != v[j].begin() and it2 + 1 != v[j].begin() and it2 + 2 != v[j].begin()) + { + for (it4 = it2 + 1; it4 != v[j].end(); it4++) + n2.push_back(*it4); + v[j].erase(it2 + 1, v[j].end() - 1); + } + if (n1.size()) + v.push_back(n1); + if (n2.size()) + v.push_back(n2); + if (n2.size() or n1.size()) + decoup_set(v); + stop = true; + } + +} + + + int main(int argc, char **argv) { using namespace oln; @@ -187,18 +308,33 @@ exit(1); } - std::vector<oln::point2d> v; + std::vector<std::vector<oln::point2d> > v; unsigned max_pts = (unsigned)atoi(argv[7]); oln::image2d<ntg::bin> mask = load(argv[8]); oln::image2d<int_u8> input1 = load(argv[9]); v = morpho::watersnakes(input1, mask, win_c8p(), 5); + v = filter_size(v); + // decoup_set(v); - v = tri_vec(input1, v); - - if (max_pts) - v = oln::snakes::impl::redispatch(v, max_pts); + for (int cpt = 0; cpt < v.size(); cpt++) + { + std::vector<oln::point2d> v_new = tri_vec(input1, v[cpt], (snake_type)atoi(argv[6])); + std::vector<oln::point2d> v_verif = verify_snaxels(v[cpt], v_new); + v[cpt] = v_new; + if (v_verif.size() > 0) + v.push_back(v_verif); + if (v[cpt].size() > max_pts) + v[cpt] = oln::snakes::impl::redispatch(v[cpt], max_pts); + } + + std::vector<unsigned> v_max_pts; + for (int cpt = 0; cpt < v.size(); cpt++) + if ((unsigned)((float)(v[cpt].size()) * 0.6) > max_pts) + v_max_pts.push_back(max_pts); + else + v_max_pts.push_back((unsigned)((float)(v[cpt].size()) * 0.6)); for (int i = 9; i < argc; i++) { @@ -209,16 +345,19 @@ oln::image2d<int_u8> out(input.size()); unsigned nb_gen = 0; - if (i == 9) - nb_gen = (unsigned)atoi(argv[3]); - else - nb_gen = 1; - - v = oln::snakes::snakes(input, v, (force_type)(atoi(argv[1])), (unsigned)atoi(argv[2]), nb_gen, max_pts, atof(argv[4]), (unsigned)atoi(argv[5]), (snake_type)atoi(argv[6])); + my_copy(input, out); - aff_droites(input, v, out); - // aff_points(input, v, out); + nb_gen = (unsigned)atoi(argv[3]); + for (int cpt = 0; cpt < v.size(); cpt++) + { + if (v[cpt].size() > v_max_pts[cpt]) + v[cpt] = oln::snakes::impl::redispatch(v[cpt], v_max_pts[cpt]); + else + v[cpt] = oln::snakes::impl::redispatch_normal(v[cpt], v[cpt].size()); + v[cpt] = oln::snakes::snakes(input, v[cpt], (force_type)(atoi(argv[1])), (unsigned)atoi(argv[2]), nb_gen, v_max_pts[cpt], atof(argv[4]), (unsigned)atoi(argv[5]), (snake_type)atoi(argv[6])); + aff_droites(input, v[cpt], out); + } char t[30]; sprintf(t, "snakes_%d.pgm", i - 8); Index: oln/appli/snakes/snakes.hh --- oln/appli/snakes/snakes.hh (revision 484) +++ oln/appli/snakes/snakes.hh (working copy) @@ -40,7 +40,6 @@ typedef enum FORCE_TYPE { GRADIENT = 0, VARIANCE = 1 } force_type; const float PI = 3.14159265; - namespace oln { namespace snakes { @@ -80,22 +79,17 @@ y2 = force.ncols() - 1; } - std::vector<point2d> draw_line_(const point2d& p, const point2d& q) { std::vector<point2d> res; - point2d p_cur = p; + if (q.col() == p.col()) // cas vertical { int sens = q.row() > p.row() ? 1 : -1; while (p_cur != q) { - double pc_p = euclidian_distance(p_cur.row(), p.row(), p_cur.col(), p.col()); - double pc_q = euclidian_distance(p_cur.row(), q.row(), p_cur.col(), q.col()); - double p_q = euclidian_distance(p.row(), q.row(), p.col(), q.col()); - res.push_back(p_cur); p_cur.row() = p_cur.row() + sens; } @@ -107,10 +101,6 @@ int sens = q.col() > p.col() ? 1 : -1; while (p_cur != q) { - double pc_p = euclidian_distance(p_cur.row(), p.row(), p_cur.col(), p.col()); - double pc_q = euclidian_distance(p_cur.row(), q.row(), p_cur.col(), q.col()); - double p_q = euclidian_distance(p.row(), q.row(), p.col(), q.col()); - res.push_back(p_cur); p_cur.col() = p_cur.col() + sens; } @@ -132,10 +122,6 @@ while (p_cur != q) { - double pc_p = euclidian_distance(p_cur.row(), p.row(), p_cur.col(), p.col()); - double pc_q = euclidian_distance(p_cur.row(), q.row(), p_cur.col(), q.col()); - double p_q = euclidian_distance(p.row(), q.row(), p.col(), q.col()); - res.push_back(p_cur); if (abs(decalage) >= abs(denom)) @@ -154,8 +140,6 @@ return res; } - - template <typename T> std::vector<point2d> compute_normal_points_(const image2d<T>& force, const point2d& p1, @@ -163,9 +147,12 @@ const point2d& p3, unsigned int dmax) { + point2d pp1(p1.row(), p1.col()); + point2d pp3(p3.row(), p3.col()); + float x_c = p2.row(); float y_c = p2.col(); - float a_p1_p3 = (p1.col() - p3.col()) != 0 ? (float)(((float)(p1.row() - p3.row())) / (p1.col() - p3.col())) : 0; + float a_p1_p3 = (pp1.col() - pp3.col()) != 0 ? (float)(((float)(pp1.row() - pp3.row())) / (pp1.col() - pp3.col())) : 0; float a = -a_p1_p3; float b = p2.col() - a * p2.row(); // use of - slope of p1 et p3 @@ -203,11 +190,21 @@ } else { + if (pp3.row() == pp1.row()) + { x1 = p2.row() - dmax; y1 = p2.col(); x2 = p2.row() + dmax; y2 = p2.col(); } + else + { + x1 = p2.row(); + y1 = p2.col() - dmax; + x2 = p2.row(); + y2 = p2.col() + dmax; + } + } verify_integrity_(force, x1, x2, y1, y2); @@ -226,6 +223,7 @@ return sqr(180 - angle) / sqr(180); } + template <typename T> double variance(const image2d<T>& input, const point2d& p, @@ -255,6 +253,7 @@ return res / sqr(fen); } + template <typename T> std::vector<point2d> gen_snakes_(const image2d<T>& force, const std::vector<point2d>& v, @@ -267,6 +266,9 @@ std::vector<point2d>::const_iterator it = v.begin(); std::vector<point2d> res; + if (type == OUVERT) + res.push_back(*(v.begin())); + for (; it != v.end(); it++) { point2d p1 = *it; @@ -322,7 +324,6 @@ } else res.push_back(*(v.end() - 1)); - return res; } @@ -376,9 +377,16 @@ int nb_pts = v.size() * 2; int cpt = 0; + if (tmp.size() > nb_pts) + { for (it2 = tmp.begin(); it2 != tmp.end(); it2++, cpt++) if ((cpt % (tmp.size() / nb_pts)) == 0) res.push_back(*it2); + } + else + for (it2 = tmp.begin(); it2 != tmp.end(); it2++, cpt++) + res.push_back(*it2); + if (type == FERME) { @@ -391,7 +399,6 @@ return res; } - std::vector<point2d> redispatch(const std::vector<point2d>& v, int nb_snaxels) { @@ -418,6 +425,33 @@ } + std::vector<point2d> redispatch_normal(const std::vector<point2d>& v, + int nb_snaxels) + { + std::vector<point2d> res; + std::vector<point2d> tmp; + std::vector<point2d>::const_iterator it = v.begin(); + int cpt = 0; + + for (; it + 1 != v.end(); it++) + { + std::vector<point2d> vec = draw_line_(*it, *(it+1)); + std::vector<point2d>::const_iterator it2 = vec.begin(); + + for (; it2 != vec.end(); it2++) + tmp.push_back(*it2); + } + + for (it = tmp.begin(); it != tmp.end(); it++, cpt++) + if ((cpt % (int)(roundf(((float)(tmp.size()) / nb_snaxels)))) == 0) + res.push_back(*it); + + res.push_back(*(v.end() - 1)); + return res; + } + + + template <typename T> void clean_ima(image2d<T>& ima) { @@ -475,6 +509,7 @@ while (i < nb_gen) { res = gen_snakes_(force, res, f, fen, lambda, dmax, type); + if (res.size() > max_pts) res = redispatch(res, max_pts); i++; if (i < nb_gen)