// -*- C++ -*- // Copyright 2006-2007 Deutsches Forschungszentrum fuer Kuenstliche Intelligenz // or its licensors, as applicable. // // You may not use this file except under the terms of the accompanying license. // // Licensed under the Apache License, Version 2.0 (the "License"); you // may not use this file except in compliance with the License. You may // obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Project: // File: // Purpose: // Responsible: tmb // Reviewer: // Primary Repository: // Web Sites: www.iupr.org, www.dfki.de, www.ocropus.org #include #include "grouper.h" #include "imglib.h" #include "imgio.h" #include "ocr-utils.h" #include "ocr-segmentations.h" namespace ocropus { using namespace iulib; using namespace colib; namespace { template int find(T &object,narray &list) { for(int i=0;i100000) throw "labels out of range"; narray rboxes; bounding_boxes(rboxes,labels); #if 0 // FIXME disabling check until the overseg issue is fixed for(int i=1;i0) centers(i) /= counts(i); else centers(i) = 999999; } intarray permutation; quicksort(permutation,centers); intarray rpermutation(permutation.length()); for(int i=0;i boxes; objlist segments; narray rboxes; floatarray classifications; floatarray spaces; bool fullheight; SimpleGrouper() { maxrange = 4; maxdist = 2; fullheight = false; } void set(const char *s,double v) { if(!strcmp(s,"maxrange")) maxrange = int(v); else if(!strcmp(s,"maxdist")) maxdist = int(v); else if(!strcmp(s,"fullheight")) fullheight = int(v); else throw "unknown parameter"; } const char *description() { return "SimpleGrouper"; } // Set a segmentation. void setSegmentation(intarray &segmentation) { copy(labels,segmentation); make_line_segmentation_black(labels); check_approximately_sorted(labels); boxes.dealloc(); segments.dealloc(); classifications.dealloc(); spaces.dealloc(); computeGroups(); } // Set a character segmentation. void setCSegmentation(intarray &segmentation) { maxrange = 1; maxdist = 2; copy(labels,segmentation); make_line_segmentation_black(labels); check_approximately_sorted(labels); boxes.dealloc(); segments.dealloc(); classifications.dealloc(); spaces.dealloc(); computeGroups(); } // Compute the groups for a segmentation (internal method). void computeGroups() { rboxes.clear(); bounding_boxes(rboxes,labels); int n = rboxes.length(); // NB: we start with i=1 because i=0 is the background for(int i=1;in) continue; rectangle box = rboxes[i]; intarray seg; bool bad = 0; for(int j=i;ji && rboxes[j].x0-rboxes[j-1].x1>maxdist) { bad = 1; break; } box.include(rboxes[j]); seg.push(j); } if(bad) continue; boxes.push(box); move(segments.push(),seg); } } } // Return the number of character candidates found. int length() { return boxes.length(); } // Return the bounding box for a character. rectangle boundingBox(int index) { return boxes[index]; } // Return the segmentation-derived mask for the character. // This may optionally be grown by some pixels. void getMask(rectangle &r,bytearray &mask,int index,int grow) { r = boxes[index].grow(grow); r.intersect(rectangle(0,0,labels.dim(0),labels.dim(1))); if(fullheight) { r.y0 = 0; r.y1 = labels.dim(1); } int x = r.x0, y = r.y0, w = r.width(), h = r.height(); intarray &segs = segments[index]; mask.resize(w,h); fill(mask,0); for(int i=0;i=0) { mask(i,j) = 255; } } if(grow>0) binary_dilate_circle(mask,grow); } // Extract the masked character from the source image/source // feature map. template void extractMasked(narray &out,bytearray &mask,narray &source,int index,int grow=0) { ASSERT(samedims(labels,source)); rectangle r; getMask(r,mask,index,grow); int x = r.x0, y = r.y0, w = r.width(), h = r.height(); out.resize(w,h); fill(out,0); for(int i=0;i void extractWithBackground(narray &out,narray &source,T dflt,int index,int grow=0) { ASSERT(samedims(labels,source)); bytearray mask; rectangle r; getMask(r,mask,index,grow); int x = r.x0, y = r.y0, w = r.width(), h = r.height(); out.resize(w,h); fill(out,dflt); for(int i=0;i=rboxes.length()-1) return -1; int x0 = rboxes[end].x1; int x1 = rboxes[end+1].x0; return x1-x0; } // Set the cost for inserting a space after the given // character. void setSpaceCost(int index,float yes,float no) { maybeInit(); spaces(index,0) = yes; spaces(index,1) = no; } // Output the segmentation into a segmentation graph. // Construct a state for each of the segments, then // add transitions between states (segments) // from min(segments[i]) to max(segments[i])+1. void getLattice(IGenericFst &fst) { fst.clear(); int final = max(labels)+1; intarray states(final+1); states.fill(-1); for(int i=1;i %d\n",i,j,start,end); } } } }; IGrouper *make_SimpleGrouper() { return new SimpleGrouper(); } IGrouper *make_StandardGrouper() { return new SimpleGrouper(); } }