/** * @name attempt_blob_chop * * Try to split the this blob after this one. Check to make sure that * it was successful. */ SEAM *Wordrec::attempt_blob_chop(TWERD *word, TBLOB *blob, int32_t blob_number, bool italic_blob, const GenericVector<SEAM*>& seams) { if (repair_unchopped_blobs) preserve_outline_tree (blob->outlines); TBLOB *other_blob = TBLOB::ShallowCopy(*blob); /* Make new blob */ // Insert it into the word. word->blobs.insert(other_blob, blob_number + 1); SEAM *seam = nullptr; if (prioritize_division) { TPOINT location; if (divisible_blob(blob, italic_blob, &location)) { seam = new SEAM(0.0f, location); } } if (seam == nullptr) seam = pick_good_seam(blob); if (chop_debug) { if (seam != nullptr) seam->Print("Good seam picked="); else tprintf("\n** no seam picked *** \n"); } if (seam) { seam->ApplySeam(italic_blob, blob, other_blob); } seam = CheckSeam(chop_debug, blob_number, word, blob, other_blob, seams, seam); if (seam == nullptr) { if (repair_unchopped_blobs) restore_outline_tree(blob->outlines); if (allow_blob_division && !prioritize_division) { // If the blob can simply be divided into outlines, then do that. TPOINT location; if (divisible_blob(blob, italic_blob, &location)) { other_blob = TBLOB::ShallowCopy(*blob); /* Make new blob */ word->blobs.insert(other_blob, blob_number + 1); seam = new SEAM(0.0f, location); seam->ApplySeam(italic_blob, blob, other_blob); seam = CheckSeam(chop_debug, blob_number, word, blob, other_blob, seams, seam); } } } if (seam != nullptr) { // Make sure this seam doesn't get chopped again. seam->Finalize(); } return seam; }
/********************************************************************** * choose_best_seam * * Choose the best seam that can be created by assembling this a * collection of splits. A queue of all the possible seams is * maintained. Each new split received is placed in that queue with * its partial priority value. These values in the seam queue are * evaluated and combined until a good enough seam is found. If no * further good seams are being found then this function returns to the * caller, who will send more splits. If this function is called with * a split of NULL, then no further splits can be supplied by the * caller. **********************************************************************/ void Wordrec::choose_best_seam(SeamQueue *seam_queue, const SPLIT *split, PRIORITY priority, SEAM **seam_result, TBLOB *blob, SeamPile *seam_pile) { SEAM *seam; char str[80]; float my_priority; /* Add seam of split */ my_priority = priority; if (split != NULL) { TPOINT split_point = split->point1->pos; split_point += split->point2->pos; split_point /= 2; seam = new SEAM(my_priority, split_point, *split); if (chop_debug > 1) seam->Print("Partial priority "); add_seam_to_queue(my_priority, seam, seam_queue); if (my_priority > chop_good_split) return; } TBOX bbox = blob->bounding_box(); /* Queue loop */ while (!seam_queue->empty()) { SeamPair seam_pair; seam_queue->Pop(&seam_pair); seam = seam_pair.extract_data(); /* Set full priority */ my_priority = seam->FullPriority(bbox.left(), bbox.right(), chop_overlap_knob, chop_centered_maxwidth, chop_center_knob, chop_width_change_knob); if (chop_debug) { sprintf (str, "Full my_priority %0.0f, ", my_priority); seam->Print(str); } if ((*seam_result == NULL || (*seam_result)->priority() > my_priority) && my_priority < chop_ok_split) { /* No crossing */ if (seam->IsHealthy(*blob, chop_min_outline_points, chop_min_outline_area)) { delete *seam_result; *seam_result = new SEAM(*seam); (*seam_result)->set_priority(my_priority); } else { delete seam; seam = NULL; my_priority = BAD_PRIORITY; } } if (my_priority < chop_good_split) { if (seam) delete seam; return; /* Made good answer */ } if (seam) { /* Combine with others */ if (seam_pile->size() < chop_seam_pile_size) { combine_seam(*seam_pile, seam, seam_queue); SeamDecPair pair(seam_pair.key(), seam); seam_pile->Push(&pair); } else if (chop_new_seam_pile && seam_pile->size() == chop_seam_pile_size && seam_pile->PeekTop().key() > seam_pair.key()) { combine_seam(*seam_pile, seam, seam_queue); SeamDecPair pair; seam_pile->Pop(&pair); // pop the worst. // Replace the seam in pair (deleting the old one) with // the new seam and score, then push back into the heap. pair.set_key(seam_pair.key()); pair.set_data(seam); seam_pile->Push(&pair); } else { delete seam; } } my_priority = seam_queue->empty() ? NO_FULL_PRIORITY : seam_queue->PeekTop().key(); if ((my_priority > chop_ok_split) || (my_priority > chop_good_split && split)) return; } }