ho_bitmap * ho_bitmap_filter_fill (const ho_bitmap * m) { ho_objmap *m_obj; ho_bitmap *m_out; ho_bitmap *m_temp1; ho_bitmap *m_temp2; int index; int width, height; /* allocate memory */ m_obj = ho_objmap_new_from_bitmap (m); if (!m_obj) return NULL; m_out = ho_bitmap_new (m->width, m->height); if (!m_out) { ho_objmap_free (m_obj); return NULL; } m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* loop over all the objects and box them */ for (index = 0; index < m_obj->obj_list->size; index++) { /* get a dimention factor */ width = (((m_obj->obj_list)->objects)[index]).width; height = (((m_obj->obj_list)->objects)[index]).height; /* copy only the current object to a new bitmap */ m_temp1 = ho_objmap_to_bitmap_by_index (m_obj, index); /* fill the current object */ m_temp2 = ho_bitmap_hlink (m_temp1, width / 4); ho_bitmap_free (m_temp1); m_temp1 = ho_bitmap_vlink (m_temp2, height / 4); ho_bitmap_free (m_temp2); /* add to matrix out */ ho_bitmap_or (m_out, m_temp1); ho_bitmap_free (m_temp1); } return m_out; }
ho_bitmap * ho_bitmap_filter_set_height_from_bottom (const ho_bitmap * m, const int height, const int top, const int bottom) { ho_objmap *m_obj; ho_bitmap *m_out; ho_bitmap *m_temp1; ho_bitmap *m_temp2; int index; /* allocate memory */ m_obj = ho_objmap_new_from_bitmap (m); if (!m_obj) return NULL; m_out = ho_bitmap_new (m->width, m->height); if (!m_out) { ho_objmap_free (m_obj); return NULL; } m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* loop over all the objects and box them */ for (index = 0; index < m_obj->obj_list->size; index++) { /* copy only the current object to a new bitmap */ m_temp1 = ho_objmap_to_bitmap_by_index (m_obj, index); if (!m_temp1) continue; /* take height pixels from this object */ m_temp2 = ho_bitmap_set_height_from_bottom (m_temp1, height, top, bottom); ho_bitmap_free (m_temp1); if (!m_temp2) continue; /* add to matrix out */ ho_bitmap_or (m_out, m_temp2); ho_bitmap_free (m_temp2); } return m_out; }
ho_bitmap * ho_bitmap_filter_boxes (const ho_bitmap * m, const int leeway_down, const int leeway_up) { ho_objmap *m_obj; ho_bitmap *m_out; int index; int x, y, width, height; /* allocate memory */ m_obj = ho_objmap_new_from_bitmap (m); if (!m_obj) return NULL; m_out = ho_bitmap_new (m->width, m->height); m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; if (!m_out) { ho_objmap_free (m_obj); return NULL; } /* loop over all the objects and box them */ for (index = 0; index < m_obj->obj_list->size; index++) { x = (((m_obj->obj_list)->objects)[index]).x; y = (((m_obj->obj_list)->objects)[index]).y; width = (((m_obj->obj_list)->objects)[index]).width; height = (((m_obj->obj_list)->objects)[index]).height; y -= leeway_up; height += leeway_up + leeway_down; if (y < 0) y = 0; if (y + height >= m->height) height = m->height - y - 1; ho_bitmap_draw_box (m_out, x, y, width, height); } return m_out; }
int ho_bitmap_filter_count_objects (const ho_bitmap * m) { ho_objmap *o_obj; int count; o_obj = ho_objmap_new_from_bitmap (m); if (!o_obj) return -1; count = ho_objmap_get_size (o_obj); ho_objmap_free (o_obj); return count; }
ho_bitmap * ho_bitmap_filter_by_size (const ho_bitmap * m, int min_height, int max_height, int min_width, int max_width) { ho_objmap *m_obj; ho_bitmap *m_out; /* create a new objmap */ m_obj = ho_objmap_new_from_bitmap (m); if (!m_obj) return NULL; m_out = ho_objmap_to_bitmap_by_size (m_obj, min_height, max_height, min_width, max_width); /* free objmap */ ho_objmap_free (m_obj); return m_out; }
int main (int argc, char * argv[]) { ho_pixbuf * pix = NULL; ho_pixbuf * pix_temp = NULL; ho_objmap * obj = NULL; ho_pixsum * sums = NULL; int i; /* read image and convert to bw */ /* ---------------------------- */ /* try to read pnm files */ pix = ho_pixbuf_pnm_load_path("./images/p6.pnm"); ho_pixbuf_pnm_save_path(pix, "t-p6.pnm"); /* convert image to gray and then to b/w */ ho_pixbuf_filter_gray(pix); ho_pixbuf_filter_polarize(pix, 150); ho_pixbuf_pnm_save_path(pix, "t-bw-p6.pnm"); /* run layout filters */ /* ------------------ */ /* filter by size */ ho_pixbuf_layout_filter (pix, 0, 10, 100, 10, 100); /* smear image */ //ho_pixbuf_filter_hsmear (pix, 0, 0, 10, 0); //ho_pixbuf_filter_vsmear (pix, 0, 0, 10, 0); //ho_pixbuf_op_mov (pix, 0, 1); /* create a sums transforamtion of pix */ sums = ho_pixsum_new(pix->width, pix->height); ho_pixsum_from_pixbuf(sums, pix, 0); /* segment the image verticaly using the sums map */ ho_pixbuf_layout_segment_vertical (pix, sums, 0, 0, 0, pix->width, pix->height, 0.05); /* connect small gaps between vertical segments, using smear */ /* ho_pixbuf_filter_hsmear */ /* (pix = pix, chanel = 0, value = 255, gap = 5, moment = 0) */ ho_pixbuf_filter_hsmear (pix, 0, 0, 5, 0); /* create objmap */ obj = ho_objmap_new(pix->width, pix->height); ho_objmap_from_pixbuf (obj, pix, 0); /* loop on all the objects and dump to disk */ for (i = 1; i <= ho_objmap_get_size(obj); i++) { printf("o%d %d %d %d %d 0\n", i, ho_objmap_get_object(obj,i).x, pix->height - ho_objmap_get_object(obj,i).y - ho_objmap_get_object(obj,i).height, ho_objmap_get_object(obj,i).x + ho_objmap_get_object(obj,i).width, pix->height - ho_objmap_get_object(obj,i).y); ho_pixbuf_layout_segment_horizontal (pix, sums, 0, ho_objmap_get_object(obj,i).x, ho_objmap_get_object(obj,i).y, ho_objmap_get_object(obj,i).width, ho_objmap_get_object(obj,i).height, 0.12); } //ho_pixbuf_filter_vsmear (pix, 1, 255, 5, 0); //ho_pixbuf_layout_filter_by_height (pix, 1, 10, 120); //ho_pixbuf_layout_smear(pix, 1, 10, 120); /* draw a grid with: step_size=100, channel=1, value=0 */ ho_pixbuf_draw_grid (pix, 100, 2, 0); /* save layout image */ ho_pixbuf_pnm_save_path(pix, "t-p6-layout.pnm"); ho_objmap_free(obj); ho_pixbuf_free(pix_temp); ho_pixbuf_free(pix); return 0; }
ho_bitmap * ho_bitmap_filter_obj_extend_lateraly (const ho_bitmap * m, const int ext_width) { ho_objmap *m_obj; ho_bitmap *m_temp; ho_bitmap *m_out; int x, y; int index; int width, height; m_temp = ho_bitmap_clone (m); if (!m_temp) return NULL; /* loop over all objects and extend them lateraly */ /* allocate memory */ m_obj = ho_objmap_new_from_bitmap (m_temp); if (!m_obj) { ho_bitmap_free (m_temp); return NULL; } /* draw stopers */ for (index = 0; index < m_obj->obj_list->size; index++) { x = (((m_obj->obj_list)->objects)[index]).x; y = (((m_obj->obj_list)->objects)[index]).y; width = (((m_obj->obj_list)->objects)[index]).width; height = (((m_obj->obj_list)->objects)[index]).height; if (x - ext_width < 0) x = ext_width; if (x + width + ext_width >= m->width) width = m->width - x - ext_width - 1; ho_bitmap_draw_vline (m_temp, x - ext_width, y, height); ho_bitmap_draw_vline (m_temp, x + width + ext_width, y, height); } /* extend */ m_out = ho_bitmap_hlink (m_temp, 7 * ext_width / 4); ho_bitmap_free (m_temp); if (!m_out) return NULL; /* delete stopers */ for (index = 0; index < m_obj->obj_list->size; index++) { x = (((m_obj->obj_list)->objects)[index]).x; y = (((m_obj->obj_list)->objects)[index]).y; width = (((m_obj->obj_list)->objects)[index]).width; height = (((m_obj->obj_list)->objects)[index]).height; if (x - ext_width < 0) x = ext_width; if (x + width + ext_width >= m->width) width = m->width - x - ext_width - 1; ho_bitmap_delete_vline (m_out, x - ext_width, y, height); ho_bitmap_delete_vline (m_out, x + width + ext_width, y, height); } /* set origin */ m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; ho_objmap_free (m_obj); return m_out; }
ho_bitmap * ho_bitmap_filter_remove_dots (const ho_bitmap * m, const unsigned char erosion_n, const unsigned char dilation_n) { int x, y; unsigned char sum; ho_bitmap *m_temp; ho_bitmap *m_out; ho_objmap *m_obj; int index; int width, height; /* allocate memory */ m_out = ho_bitmap_new (m->width, m->height); if (!m_out) return NULL; m_out->x = m->x; m_out->y = m->y; m_out->type = m->type; m_out->font_height = m->font_height; m_out->font_width = m->font_width; m_out->font_spacing = m->font_spacing; m_out->line_spacing = m->line_spacing; m_out->avg_line_fill = m->avg_line_fill; m_out->com_line_fill = m->com_line_fill; m_out->nikud = m->nikud; /* connect all the small dots */ m_temp = ho_bitmap_dilation (m); /* check the size of objects */ m_obj = ho_objmap_new_from_bitmap (m_temp); ho_bitmap_free (m_temp); for (x = 1; x < (m->width - 1); x++) for (y = 1; y < (m->height - 1); y++) { /* check the size of this pixel's object */ index = ho_objmap_get (m_obj, x, y); if (index) { width = (((m_obj->obj_list)->objects)[index - 1]).width; height = (((m_obj->obj_list)->objects)[index - 1]).height; } else { width = 0; height = 0; } /* in a big object do erosion */ if (width > m->width / 4 || height > m->height / 4) { if (ho_bitmap_get (m, x, y)) /* black pixel */ { sum = ho_bitmap_get (m, x - 1, y - 1) + ho_bitmap_get (m, x - 1, y) + ho_bitmap_get (m, x - 1, y + 1) + ho_bitmap_get (m, x, y - 1) + ho_bitmap_get (m, x, y + 1) + ho_bitmap_get (m, x + 1, y - 1) + ho_bitmap_get (m, x + 1, y) + ho_bitmap_get (m, x + 1, y + 1); /* n number of white pixels or more */ if ((8 - sum) < erosion_n) ho_bitmap_set (m_out, x, y); } } else /* if in a small object do dilation */ { if (!ho_bitmap_get (m, x, y)) /* white pixel */ { sum = ho_bitmap_get (m, x - 1, y - 1) + ho_bitmap_get (m, x - 1, y) + ho_bitmap_get (m, x - 1, y + 1) + ho_bitmap_get (m, x, y - 1) + ho_bitmap_get (m, x, y + 1) + ho_bitmap_get (m, x + 1, y - 1) + ho_bitmap_get (m, x + 1, y) + ho_bitmap_get (m, x + 1, y + 1); /* n number of black neighbors or more */ if (sum >= dilation_n) ho_bitmap_set (m_out, x, y); } else ho_bitmap_set (m_out, x, y); } } ho_objmap_free (m_obj); return m_out; }
int ho_recognize_nikud_dimentions (const ho_bitmap * m_text, const ho_bitmap * m_mask, double *height, double *width, double *top, double *bottom, double *top_left, double *top_mid, double *top_right, double *mid_left, double *mid_right, double *bottom_left, double *bottom_mid, double *bottom_right, double *dots_above, double *dots_below, double *dots_inside, double *objs_above, double *objs_below, double *objs_inside, double *main_obj_height, double *main_obj_width, double *top_dot_x, double *inside_dot_x, double *font_width_by_height) { int i, x, y; int obj_width, obj_height; int obj_x, obj_y; int obj_w, obj_h; int line_start, line_end, line_height; int sum, font_start_x, font_end_x, font_height, font_width; int font_start_y, font_end_y; ho_objmap *o_obj = NULL; unsigned char is_dot, is_obj; /* init values to zero */ *height = 0.0; *width = 0.0; *top = 0.0; *bottom = 0.0; *top_left = 0.0; *top_mid = 0.0; *top_right = 0.0; *mid_left = 0.0; *mid_right = 0.0; *bottom_left = 0.0; *bottom_mid = 0.0; *bottom_right = 0.0; *dots_above = 0.0; *dots_below = 0.0; *dots_inside = 0.0; *objs_above = 0.0; *objs_below = 0.0; *objs_inside = 0.0; *top_dot_x = 0.0; *inside_dot_x = 0.0; *font_width_by_height = 0.0; /* get line start and end */ x = m_mask->width / 2; for (y = 0; y < m_mask->height && !ho_bitmap_get (m_mask, x, y); y++) ; line_start = y - 1; for (; y < m_mask->height && ho_bitmap_get (m_mask, x, y); y++) ; line_end = y; line_height = line_end - line_start; if (line_height < 4 || m_text->width < 4) return TRUE; *font_width_by_height = (double) m_mask->width / (double) line_height; /* get all the objects of nikud */ o_obj = ho_objmap_new_from_bitmap (m_text); if (!o_obj) return TRUE; /* if no nikud just return */ if (ho_objmap_get_size (o_obj) == 0) { ho_objmap_free (o_obj); return FALSE; } /* count points and objects above/in/below font */ obj_x = 0; obj_y = 0; obj_w = 0; obj_h = 0; for (i = 0; i < ho_objmap_get_size (o_obj); i++) { /* is this object inside line ? */ y = ho_objmap_get_object (o_obj, i).y; x = ho_objmap_get_object (o_obj, i).x; obj_width = ho_objmap_get_object (o_obj, i).width; obj_height = ho_objmap_get_object (o_obj, i).height; is_dot = (obj_height < line_height / 4 && obj_height > line_height / 16 && obj_width < line_height / 4 && obj_width > line_height / 16); is_obj = (obj_height > line_height / 4 || obj_width > line_height / 4); if (is_dot) { /* count */ if ((y + obj_height / 2) < line_start) { (*dots_above) += 0.1; *top_dot_x = (double) x / (double) (m_text->width); } else if ((y + obj_height / 2) > line_end) { (*dots_below) += 0.1; } else { (*dots_inside) += 0.1; *inside_dot_x = (double) x / (double) (m_text->width); } } else if (is_obj) { /* count */ if ((y + obj_height / 2) < line_start) { (*objs_above) += 0.1; } else if ((y + obj_height / 2) > line_end) { (*objs_below) += 0.1; /* get metrics of bigest obj under font */ if (obj_width > *width) { obj_x = x; obj_y = y; obj_w = obj_width; obj_h = obj_height; } } else { (*objs_inside) += 0.1; } } } /* free obj map */ ho_objmap_free (o_obj); /* if nothing below font we are finished */ if (!(*objs_below) && !(*dots_below)) return FALSE; /* get nikud metrics */ *main_obj_height = 2.0 * (double) obj_h / (double) line_height; *main_obj_width = 2.0 * (double) obj_w / (double) line_height; if (obj_y && obj_h) { *top = 2.0 * (double) (obj_y - line_end) / (double) line_height; *bottom = 2.0 * (double) ((obj_y + obj_h) - line_end) / (double) line_height; } /* get nikud start and end */ sum = 0; for (y = line_end + 1; y < m_text->height && sum == 0; y++) for (sum = 0, x = 1; x < (m_text->width - 1); x++) sum += ho_bitmap_get (m_text, x, y); font_start_y = y - 1; sum = 0; for (y = m_text->height - 1; y > font_start_y && sum == 0; y--) for (sum = 0, x = 1; x < (m_text->width - 1); x++) sum += ho_bitmap_get (m_text, x, y); font_end_y = y + 1; font_height = font_end_y - font_start_y; if (!font_height) return TRUE; *height = 2.0 * (double) font_height / (double) line_height; sum = 0; for (x = 2; x < m_text->width && sum == 0; x++) for (sum = 0, y = line_end; y < (m_text->height - 1); y++) sum += ho_bitmap_get (m_text, x, y); font_start_x = x - 1; sum = 0; for (sum = 0, x = m_text->width - 2; x > (font_start_x + 1) && sum == 0; x--) for (sum = 0, y = line_end; y < (m_text->height - 1); y++) sum += ho_bitmap_get (m_text, x, y); font_end_x = x + 1; font_width = font_end_x - font_start_x; if (!font_width) return TRUE; *width = 2.0 * (double) font_width / (double) line_height; /* get nikud egdes */ for (y = font_start_y, x = font_start_x; x < font_end_x && y < (font_end_y) && !ho_bitmap_get (m_text, x, y); x++, y++) ; *top_left = (double) (x - font_start_x) / (double) (line_height / 4); if (*top_left > 1.0) *top_left = 1.0; for (y = font_end_y, x = font_start_x; x < font_end_x && y > (font_start_y) && !ho_bitmap_get (m_text, x, y); x++, y--) ; *bottom_left = (double) (x - font_start_x) / (double) (line_height / 4); if (*bottom_left > 1.0) *bottom_left = 1.0; for (y = font_start_y, x = font_end_x - 1; x > font_start_x && y < (font_end_y) && !ho_bitmap_get (m_text, x, y); x--, y++) ; *top_right = (double) (font_end_x - x) / (double) (line_height / 4); if (*top_right > 1.0) *top_right = 1.0; for (y = font_end_y, x = font_end_x - 1; x > font_start_x && y > font_start_y && !ho_bitmap_get (m_text, x, y); x--, y--) ; *bottom_right = (double) (font_end_x - x) / (double) (line_height / 4); if (*bottom_right > 1.0) *bottom_right = 1.0; for (y = font_start_y, x = font_start_x + font_width / 2; y < (font_start_y + font_height) && !ho_bitmap_get (m_text, x, y); y++) ; *top_mid = (double) (y - font_start_y) / (double) (line_height / 4); if (*top_mid > 1.0) *top_mid = 1.0; for (y = font_end_y, x = font_start_x + font_width / 2; y > (font_start_y + font_height) && !ho_bitmap_get (m_text, x, y); y--) ; *bottom_mid = (double) (font_end_y - y) / (double) (line_height / 4); if (*bottom_mid > 1.0) *bottom_mid = 1.0; for (y = font_start_y + font_height / 2, x = font_start_x; x < (font_end_x) && !ho_bitmap_get (m_text, x, y); x++) ; *mid_left = (double) (x - font_start_x) / (double) (line_height / 4); if (*mid_left > 1.0) *mid_left = 1.0; for (y = font_start_y + font_height / 2, x = font_end_x - 1; x > (font_start_x) && !ho_bitmap_get (m_text, x, y); x--) ; *mid_right = (double) (font_end_x - x) / (double) (line_height / 4); if (*mid_right > 1.0) *mid_right = 1.0; return FALSE; }