26 #ifndef SCRIBO_PREPROCESSING_DESKEW_HH
27 # define SCRIBO_PREPROCESSING_DESKEW_HH
38 # include <mln/core/image/image2d.hh>
39 # include <mln/math/pi.hh>
40 # include <mln/geom/rotate.hh>
41 # include <mln/value/int_u8.hh>
46 namespace preprocessing
67 double mtheta()
const;
73 double get_cos(
int index)
const;
74 double get_sin(
int index)
const;
111 # ifndef MLN_INCLUDE_ONLY
118 QCompare::operator()(
const s_angle& s1,
const s_angle& s2)
120 return (s1.max > s2.max);
125 Hough::Hough(
int width,
int height)
128 max_rho_(
sqrt((width * width) + (height * height))),
129 max_theta_(math::
pi),
130 max_rho_index_(
int(this->max_rho_) + 1),
131 max_theta_index_(500),
132 acc_(this->max_rho_index_, this->max_theta_index_)
147 void Hough::look_up_table()
149 this->cos_ =
new double[this->max_theta_index_];
150 this->sin_ =
new double[this->max_theta_index_];
152 for (
int i = 0; i < this->max_theta_index_; ++i)
154 double i_val = (i + 650) * this->max_theta_ / 1800.0f;
156 this->cos_[i] =
cos(i_val);
157 this->sin_[i] =
sin(i_val);
162 int Hough::width()
const
168 int Hough::height()
const
170 return this->height_;
174 double Hough::mtheta()
const
176 return this->max_theta_;
180 double Hough::mrho()
const
182 return this->max_rho_;
186 int Hough::mrhoi()
const
188 return this->max_rho_index_;
192 int Hough::mthetai()
const
194 return this->max_theta_index_;
198 double Hough::get_cos(
int index)
const
200 return this->cos_[index];
204 double Hough::get_sin(
int index)
const
206 return this->sin_[index];
218 vote(
int x,
int y, Hough&
hough,
int theta)
220 int theta_min =
std::max(theta - 25, 0);
221 int theta_max =
std::min(theta + 25, hough.mthetai());
226 for (
int i = theta_min; i < theta_max; ++i)
228 double rho = x * hough.get_cos(i) + y * hough.get_sin(i);
229 double rho_index = (0.5 + (rho / hough.mrho() + 0.5)
232 ++(opt::at(hough.acc(),
241 init_hist(Hough& hough,
int hist[500],
242 std::priority_queue<s_angle, std::vector<s_angle>, QCompare>& q,
245 int max_rho = hough.mrhoi();
246 int max_theta = hough.mthetai();
247 unsigned max_elm = (nb_elm > max_rho) ? (nb_elm / max_rho) << 5 : 1;
249 for (
int j = 0; j < max_theta; ++j)
253 if (q.size() < max_elm)
255 if (opt::at(hough.acc(), 0, j) > 0)
259 s.max = opt::at(hough.acc(), 0, j);
265 else if (opt::at(hough.acc(), 0, j) > q.top().max)
269 s.max = opt::at(hough.acc(), 0, j);
282 get_max(Hough& hough,
int hist[500],
283 std::priority_queue<s_angle, std::vector<s_angle>, QCompare>& q,
288 int max_rho = hough.mrhoi();
289 int max_theta = hough.mthetai();
291 unsigned max_elm = (nb_elm > max_rho) ? (nb_elm / max_rho) << 5 : 1;
294 for (
int i = 1; i < max_rho; ++i)
296 for (
int j = 0; j < max_theta; ++j)
298 if (q.size() < max_elm)
300 if (opt::at(hough.acc(), i, j) > 0)
304 s.max = opt::at(hough.acc(), i, j);
310 else if (opt::at(hough.acc(), i, j) > q.top().max)
314 s.max = opt::at(hough.acc(), i, j);
325 hist[q.top().pos] += q.top().max;
326 h_value = hist[q.top().pos];
346 std::priority_queue<s_angle, std::vector<s_angle>, QCompare> q;
350 for (
unsigned i = 0; i < gray.
nrows() - 1; ++i)
352 for (
unsigned j = 1; j < gray.
ncols() - 1; ++j)
356 unsigned mean = ((opt::at(gray, i, j) * opt::at(gray, i + 1, j))) >> 8;
358 for (
unsigned k = j - 1; k <= j + 1; ++k)
360 up *= opt::at(gray, i, k);
361 down *= opt::at(gray, i + 1, k);
364 up = 255 - (up >> 16);
367 if (up > down && down > mean && down > 130)
371 double gy = opt::at(gray, i - 1, j - 1) + 2 * opt::at(gray, i - 1, j) +
372 opt::at(gray, i - 1, j + 1);
373 gy += -opt::at(gray, i + 1, j - 1) - 2 * opt::at(gray, i + 1, j) -
374 opt::at(gray, i + 1, j + 1);
376 double gx = opt::at(gray, i - 1, j - 1) + 2 * opt::at(gray, i, j - 1) +
377 opt::at(gray, i + 1, j - 1);
378 gx += -opt::at(gray, i - 1, j + 1) - 2 * opt::at(gray, i, j + 1) -
379 opt::at(gray, i + 1, j + 1);
383 if (tanv <= 25.0 || tanv >= 155.0)
386 vote(j, i, hough,
int((tanv <= 25.0 ? 250.0 - tanv * 10.0 :
387 (180.0 - tanv) * 10.0 + 250.0)));
393 init_hist(hough, hist, q, nb_elm);
395 return 90 - (get_max(hough, hist, q, nb_elm) + 650) / 10;
404 template <
typename I>
408 const I& input_gl =
exact(input_gl_);
410 mln_trace(
"scribo::preprocessing::deskew");
411 mln_assertion(input_gl.is_valid());
412 mlc_is(mln_domain(I),
box2d)::check();
413 mlc_is_not(mln_value(I),
bool)::check();
414 mlc_is_not_a(mln_value(I), value::Vectorial)::check();
416 double angle = internal::perform_deskew(input_gl);
422 if (angle > 0.5 || angle < -0.5)
423 output = geom::
rotate(input_gl, - angle,
425 extend(input_gl, mln_min(mln_value(I))),
433 # endif // ! MLN_INCLUDE_ONLY
441 # endif // SCRIBO_PREPROCESSING_DESKEW_HH