All Downloads are FREE. Search and download functionalities are using the official Maven repository.

srcnativelibs.Vision.cvgui.cpp Maven / Gradle / Ivy

/*
 * Copyright 2010-2014, Sikuli.org, sikulix.com
 * Released under the MIT License.
 *
 */
#include "cvgui.h"
#include "sikuli-debug.h"
#include 
using namespace std;
using namespace sikuli;


Scalar Color::RED(0,0,255);
Scalar Color::WHITE(255,255,255);

Scalar Color::RANDOM() { 
   return Scalar(rand()&255, rand()&255, rand()&255);
};

static bool sort_by_x (Rect a, Rect b){ 
	return (a.x < b.x); 
}

static bool sort_blob_by_x(Blob a, Blob b){ 
	return (a.x < b.x); 
}

static bool sort_blob_by_y(Blob a, Blob b){ 
	return (a.y < b.y); 
}

#define SHOW(x) namedWindow(#x,1); imshow(#x,x);
#define SHOW0(x) namedWindow(#x,1); imshow(#x,x); waitKey(0);

//class VisualLogger{
//   
//   
//   int image_i;
//   int step_i;
//   char* prefix;
//   
//public:
//   
//   VisualLogger(){
//   }
//   
//   static void newImage(){
//      image_i++;
//      step_i = 0;
//   }
//   
//   static void log(const char* name, const Mat& image){
//      char buf[200];
//      
//      if (prefix){
//         
//         sprintf(buf, "%s-%02d-%s.vlog.png", prefix, step_i, name);
//         
//      }else{
//         sprintf(buf, "%03d-%02d-%s.vlog.png",image_i,step_i,name);           
//      }
//      
//      imwrite(buf, image);
//      
//      step_i++;  
//   }
//};
//
//static VisualLogger vlog;

int VisualLogger::image_i = 0;
int VisualLogger::step_i = 0;
//bool VisualLogger::enabled = false;
char* VisualLogger::prefix = 0;

//#define VLOG(x,y) 

void
Util::rgb2grayC3(const Mat& input, Mat& output){
   Mat g;
   cvtColor(input, g, CV_RGB2GRAY);   
   Mat ss[3] = {g,g,g};
   merge(ss,3,output);   
}

void 
Util::growRect(Rect& rect, int xd, int yd, Rect bounds){
   
   
   Rect in = rect;
   in.x -= xd;
   in.width += 2*xd;
   in.y -= yd;
   in.height += 2*yd;
   
   int x1 = max(bounds.x, in.x);
   int y1 = max(bounds.y, in.y);
   int x2 = min(in.x + in.width, bounds.width);
   int y2 = min(in.y + in.height, bounds.height);
	
   if (x2 < x1 || y2 < y1)
      rect = Rect(0,0,0,0);
   else
      rect = Rect(x1,y1,x2-x1+1,y2-y1+1);
   
}

void 
Util::growRect(Rect& rect, int xd, int yd, cv::Mat image){
   growRect(rect, xd, yd, Rect(0,0, image.cols-1, image.rows-1));
}



void 
Painter::drawRect(Mat& image, Rect r, Scalar color){
   rectangle(image, 
             Point(r.x, r.y),
             Point(r.x + r.width, r.y + r.height),
             color);   
}

void 
Painter::drawRect(Mat& image, OCRRect r, Scalar color){
   rectangle(image, 
             Point(r.x, r.y),
             Point(r.x + r.width, r.y + r.height),
             color);   
}

void 
Painter::drawRects(Mat& image, vector& rects, Scalar color){
   for (vector::iterator r = rects.begin();
        r != rects.end(); ++r){
      
      rectangle(image, 
                Point(r->x, r->y),
                Point(r->x + r->width, r->y + r->height),
                color);
   }
}



void 
Painter::drawBlobsRandomShading(Mat& image, vector& blobs){

   
   Mat blank = image.clone();
   blank = 0.0;
   
   Mat shading = blank;
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){   
      Blob& box = *it;      
      rectangle(shading, Point(box.x,box.y), Point(box.x+box.width,box.y+box.height), Color::RANDOM(), CV_FILLED);
   }
   
   image = image * 0.5 + shading * 0.7;
   
   Painter::drawBlobs(image, blobs, Color::WHITE);
}

void 
Painter::drawRects(Mat& image, vector& rects){
   drawRects(image, rects, Scalar(0,0,255));
}

void 
Painter::drawBlobs(Mat& image, vector& blobs){
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& blob = *it;
      
      Scalar color(blob.mr,blob.mg,blob.mb);
      vector rs;
      rs.push_back(blob);
      drawRects(image, rs, color);
   }
}

void 
Painter::drawBlobs(Mat& image, vector& blobs, Scalar color){
   vector rs;

   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& blob = *it;
      rs.push_back(blob);
   }
   drawRects(image, rs, color);
}

void 
Painter::drawLineBlobs(Mat& image, vector& lineblobs, Scalar color){
   for (vector::iterator it1 = lineblobs.begin();
        it1 != lineblobs.end(); ++it1){
      
      LineBlob& lineblob = *it1;
      
      
      if (lineblob.blobs.size()>=2){
         
         for (vector::iterator r = lineblob.blobs.begin() + 1;
              r != lineblob.blobs.end(); ++r){
            
            Rect previous = *(r-1);
            Rect current = *r;
            
            Point from(previous.x+previous.width,previous.y);
            Point to(current.x,current.y);            
            cv::line(image, from, to, Scalar(255,255,255));
         }
      }
      
      drawRect(image, lineblob, color);
   }
}

void 
Painter::drawParagraphBlobs(Mat& image, vector blobs, Scalar color){
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      ParagraphBlob& parablob = *it;      
      for (vector::iterator it1 = parablob.lineblobs.begin();
           it1 != parablob.lineblobs.end(); ++it1){
         
         LineBlob& lineblob = *it1;
         drawRect(image, lineblob, Scalar(255,255,0));
      }
      
      drawRect(image, parablob, Scalar(0,0,255));
      
   }
}

void 
Painter::drawOCRWord(Mat& ocr_result_image, OCRWord ocrword){
   
   cout << ocrword.x << " " << ocrword.y <<  " " << ocrword.width <<  " " << ocrword.height << ": ";
   cout << ocrword.getString() << endl;
  
   drawRect(ocr_result_image, ocrword, Scalar(255,255,0));
   Point pt(ocrword.x, ocrword.y + ocrword.height - 10);      
   putText(ocr_result_image, ocrword.getString(), pt,  
     FONT_HERSHEY_SIMPLEX, 0.4, Color::RED);

}

void 
Painter::drawOCRLine(Mat& ocr_result_image, OCRLine ocrline){
   vector ocrwords = ocrline.getWords();
   for (vector::iterator it = ocrwords.begin(); it != ocrwords.end(); ++it){
      OCRWord& ocrword = *it;
      drawOCRWord(ocr_result_image, ocrword);
   }
}

void 
Painter::drawOCRParagraph(Mat& ocr_result_image, OCRParagraph ocrpara){
   vector ocrlines = ocrpara.getLines();
   for (vector::iterator it = ocrlines.begin(); it != ocrlines.end(); ++it){
      OCRLine& ocrline = *it;
      drawOCRLine(ocr_result_image, ocrline);
   }
}

void 
Painter::drawOCRText(Mat& ocr_result_image, OCRText ocrtext){
   vector ocrparas = ocrtext.getParagraphs();
   for (vector::iterator it = ocrparas.begin(); it != ocrparas.end(); ++it){
      OCRParagraph& ocrpara = *it;
      drawOCRParagraph(ocr_result_image, ocrpara);
   }
}




void
LineBlob::merge(LineBlob& blob){
   
   for (vector::iterator it = blob.blobs.begin();
        it != blob.blobs.end(); ++it){
      add(*it);
   }
   
}

void
LineBlob::updateBoundingRect(Blob& blob){
   if (blobs.size() == 0){
      x = blob.x;
      y = blob.y;
      height = blob.height;
      width = blob.width;
      
   }else{
      
      int x1,y1,x2,y2;
      x1 = min(x, blob.x);
      y1 = min(y, blob.y);
      x2 = max(x+width, blob.x + blob.width);
      y2 = max(y+height, blob.y + blob.height);
      
      x = x1;
      y = y1;
      height = y2 - y1;
      width = x2 - x1;
   }
}

void
LineBlob::add(Blob& blob){
   updateBoundingRect(blob);
   blobs.push_back(blob);
}

void
LineBlob::calculateBoundingRectangle(){
   int x1,y1,x2,y2;
   Blob& first_blob = blobs.front();
   x1 = first_blob.x;
   x2 = first_blob.x + first_blob.width;
   y1 = first_blob.y;
   y2 = first_blob.y + first_blob.height;
   
   for (vector::iterator it_line = blobs.begin()+1; 
        it_line != blobs.end(); ++it_line){
      Blob& b = *it_line;
      x1 = min(x1, b.x);
      y1 = min(y1, b.y);
      x2 = max(x2, b.x + b.width);
      y2 = max(y2, b.y + b.height);
   }
   
   x = x1;
   y = y1;
   height = y2 - y1;
   width = x2 - x1;
}

void
ParagraphBlob::add(LineBlob& blob){
   
   if (lineblobs.size() == 0){
      x = blob.x;
      y = blob.y;
      height = blob.height;
      width = blob.width;
      
   }else{
      
      int x1,y1,x2,y2;
      x1 = min(x, blob.x);
      y1 = min(y, blob.y);
      x2 = max(x+width, blob.x + blob.width);
      y2 = max(y+height, blob.y + blob.height);
      
      x = x1;
      y = y1;
      height = y2 - y1;
      width = x2 - x1;
   }
   lineblobs.push_back(blob);
}



void denoise(Mat& src){
   
   //src = src * 0.1;
   
   Mat kernel = Mat::ones(3,3,CV_32FC1);
   kernel.at(2,2) = 0;
   
   Mat srcF, destF;
   src.convertTo(srcF, CV_32FC1, 0.1);
   
   filter2D(srcF, destF, -1, kernel);
   
   Mat destU;
   destF.convertTo(destU, CV_8UC1);
   
   threshold(destU, destU, 60, 255, THRESH_BINARY);
   
   bitwise_and(src, destU, src);
}




void
cvgui::linkLineBlobsIntoPagagraphBlobs(vector& blobs, vector& parablobs){
   
   sort(blobs, sort_blob_by_y);
   
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      LineBlob& blob = *it;
      
      vector::iterator it1;
      for (it1 = parablobs.begin(); 
           it1 != parablobs.end(); ++it1){
         
         ParagraphBlob& parablob = *it1;
         
         bool left_aligned = abs(parablob.x - blob.x) < 10;
         bool small_vertical_spacing = abs(blob.y - (parablob.y + parablob.height)) < 15;
         
         bool same_paragraph = left_aligned & small_vertical_spacing; 
         
         if (same_paragraph){
            parablob.add(blob);
            break;
         }
      }
      
      if (it1 ==  parablobs.end()){
         ParagraphBlob new_parablob;
         new_parablob.add(blob);
         parablobs.push_back(new_parablob);
      }
   }
}

void
cvgui::mergeLineBlobs(vector& blobs, vector& merged_blobs){
   
   sort(blobs, sort_blob_by_x);
   
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      LineBlob& blob = *it;
      
      vector::iterator l;
      for (l = merged_blobs.begin(); l != merged_blobs.end(); ++l){
         
         LineBlob& merged_blob = *l;
         
         bool similar_baseline = abs((merged_blob.y + merged_blob.height) - (blob.y + blob.height)) < 5;
         bool small_spacing = (blob.x - (merged_blob.x + merged_blob.width)) < 10;
         
         bool cond1 = merged_blob.isContainedBy(blob) || blob.isContainedBy(merged_blob);
         
         bool same_line = cond1 || (similar_baseline && small_spacing);
         
         if (same_line){
            merged_blob.merge(blob);
            break;
         }
      }
      
      if (l == merged_blobs.end()){
         merged_blobs.push_back(blob);
      }
      
   }
}

void
cvgui::linkBlobsIntoLineBlobs(vector& blobs, vector& lines, int max_spacing){
   
   
   sort(blobs, sort_blob_by_x);
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& blob = *it;
      
      vector::iterator l;
      for (l = lines.begin(); l != lines.end(); ++l){
         
         LineBlob& line = *l;
         Blob& last = line.blobs.back();
         
         bool similar_baseline = abs((last.y + last.height) - (blob.y + blob.height)) < 5;
         bool similar_centerline = abs((last.y + last.height/2) - (blob.y + blob.height/2)) < 5;
         bool similar_height = 1.0*min(last.height,blob.height)/max(last.height,blob.height) > 0.5;
         bool similar_width = 1.0*min(last.width,blob.width)/max(last.width,blob.width) > 0.5;
         
         bool small_overlap = blob.x > ((last.x + last.width)-2);
         
         
         bool small_spacing = (blob.x - (last.x + last.width)) < max_spacing;
         
         bool is_dot = blob.height < 3 && blob.width < 3 && similar_baseline && small_spacing;
         
         int th = 40;
         bool similar_foreground_color = 
         abs(last.mr - blob.mr) < th && abs(last.mg - blob.mg) < th && abs(last.mb - blob.mb) < th;
         
         
         //bool is_probably_i = blob.width < 2 || last.width < 2;
         
         
         bool same_line = (similar_centerline || similar_baseline)
         && similar_height
         && small_overlap
         //&& similar_width
         && small_spacing
         && similar_foreground_color; //|| is_probably_i);
         
         
         bool very_close = (blob.x - (last.x + last.width)) < 3;
         
         //         bool vertically_overlap = similar_baseline;
         
         if (same_line || (very_close && similar_height && similar_baseline)){
            line.add(blob);
            break;
         }
      }
      
      if (l == lines.end()){
         
         LineBlob newline;
         newline.add(blob);
         lines.push_back(newline);
      }
      
   }
}


void 
cvgui::run_ocr_on_lineblobs(vector& ocr_input_lineblobs,
                            Mat& input_image,
                            vector& ocrlines){
   
   
   for (vector::iterator it = ocr_input_lineblobs.begin(); 
        it != ocr_input_lineblobs.end(); ++it){
      
      LineBlob& lineblob = *it;
      OCRLine ocrline;
      OCRWord ocrword;
      
      // if (lineblob.blobs.size()<10)
      //         continue;
      //      
      
      
      Mat wordImage(input_image,lineblob);
      
      Mat ocrImage;  // the image passed to tesseract      
      bool upsampled = false;
      if (wordImage.rows < 20){
         upsampled = true;
         resize(wordImage, ocrImage, Size(wordImage.cols*2,wordImage.rows*2));
      }else {
         ocrImage = wordImage.clone(); 
      }  
      
      vector ocr_chars;
      ocr_chars = OCR::recognize((unsigned char*)ocrImage.data,
                                            ocrImage.cols,
                                            ocrImage.rows,
                                            8); 
      
      for (vector::iterator iter = ocr_chars.begin(); 
           iter != ocr_chars.end(); iter++){
         
         
         OCRChar& ocrchar = *iter;
         
         
         if (upsampled){
            // scale back the coordinates in the OCR result
            
            ocrchar.x = ocrchar.x/2;
            ocrchar.y = ocrchar.y/2;
            ocrchar.width = ocrchar.width/2;
            ocrchar.height = ocrchar.height/2;
         }
         
         
         ocrchar.x += lineblob.x;
         ocrchar.y += lineblob.y;
         
         
         
         if (iter > ocr_chars.begin()){
            OCRChar& previous_ocrchar = *(iter-1);
            
            int spacing = ocrchar.x - (previous_ocrchar.x + previous_ocrchar.width);
            //dout() << '[' << ocrchar.height << ':' << spacing << ']';
            //dout() << '[' << spacing << ']';
            
            
            if (lineblob.height > 6 && spacing >= 4){// || spacing >= 2){
               ocrline.addWord(ocrword);
               ocrword.clear();               
               //dout() << ' ';
            }
         } 
         
         //dout() << ocrchar.ch;
         
         ocrword.add(ocrchar);
         ocrword.y = lineblob.y;
         ocrword.height = lineblob.height;
         
         
         
         
         
      }
      
      
      ocrline.addWord(ocrword);
      
      //dout() << endl;
      
      
      ocrlines.push_back(ocrline);
      
   }
}

void getLeafBlobs(vector& blobs, vector& leaf_blobs){
   
   leaf_blobs.clear();
   
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& a = *it;
      
      // check if blob 'a' contains any other blob
      vector::iterator it1;
      for (it1 = blobs.begin(); 
           it1 != blobs.end(); ++it1){
         
         Blob& b = *it1;
         
         if (it != it1 && b.isContainedBy(a))
            break;
      }
      
      // if not, it is a leave blob
      if (it1 == blobs.end())
         leaf_blobs.push_back(a);
         
   }
}


Mat
cvgui::findBoxesByVoting(const Mat& screen, 
                         int bw, int bh,
                         vector& output_blobs){

   Mat dark;
   Util::rgb2grayC3(screen,dark);
   dark = dark * 0.5;
   
   
   VLOG("Input", screen);
   
   Mat gray;
   cvtColor(screen,gray,CV_RGB2GRAY);
   
   
   // Code for experimenting differenty parameters for Canny
   //   for (int c=10;c<=100;c=c+10){
   //      char buf[50];
   //      Mat test;
   //      sprintf(buf,"Canny%d",c);
   //      Canny(gray,test,0.66*c,1.33*c,3,true);  
   //      VLOG(buf, test);       
   //   }

   Mat canny;
   int s = 200;
   Canny(gray,canny,0.66*s,1.33*s,3,true);  
   VLOG("Canny", canny); 
   
   Mat edges;
   Mat v = Mat::ones(2,2,CV_8UC1);
   
   dilate(canny, edges, v);
   erode(edges, edges, v);   
   
   dilate(edges, edges, Mat::ones(3,3,CV_8UC1));
   VLOG("Dilated", edges); 
   
   double k = 0.85;
   double tol = 0.10;
   Mat q = Mat::ones(5,5,CV_8UC1);
   
   Mat h1,h2,hvotes;
   voteCenter_Horizontal(edges, h1, bw*k, bw*tol, bh/2);
   dilate(h1, h1, q);
   voteCenter_Horizontal(edges, h2, bw*k, bw*tol, -bh/2);
   dilate(h2, h2, q);
   
   bitwise_and(h1,h2,hvotes);
   VLOG("H-votes", hvotes); 
   
   
   Mat v1,v2,vvotes;
   voteCenter_Vertical(edges, v1, bh*k, bh*tol, bw/2);
   dilate(v1, v1, q);
   
   voteCenter_Vertical(edges, v2, bh*k, bh*tol, -bw/2);
   dilate(v2, v2, q);
   
   bitwise_and(v1,v2,vvotes);
   VLOG("V-votes", vvotes); 
   
   Mat hvvotes;
   bitwise_and(vvotes,hvotes,hvvotes);
   VLOG("HV-votes", hvvotes); 
   
   

   
   Mat copy = hvvotes.clone();
   
   
   vector > contours;
   vector hierarchy;
   
   findContours( copy, contours, hierarchy,
                CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
   
   vector blobs;
   
   Mat blank = dark.clone();
   blank = 0.0;
   
   Mat contour_shading = blank;

   
   // define a perfect box for back-proj verification
   Mat pbox = Mat::zeros(bh,bw,CV_8UC1); 
   pbox.row(0).setTo(255);
   pbox.row(bh-1).setTo(255);
   pbox.col(0).setTo(255);
   pbox.col(bw-1).setTo(255);
   int pscore = countNonZero(pbox);
   
   for (vector >::iterator it = contours.begin();
        it != contours.end(); ++it){
      
      vector& contour = *it;
      
      Rect r = boundingRect(Mat(contour));
      
      double a1 = contourArea(Mat(contour));
      double a2 = r.height * r.width;
      
      int cx = r.x + r.width/2;
      int cy = r.y + r.height/2;
      
      
      Rect box(cx-bw/2,cy-bh/2,bw,bh);
      
      Mat e(edges, box);
      // calculate the score by comparing each hypothesized box to the ideal box
      Mat sc;
      bitwise_and(e,pbox,sc);
      int score = countNonZero(sc);
      
      // ignore those boxes with fewer than this percentage 
      // of edge pixels
      if ((1.0 * score) / (1.0 * pscore) < 0.90)
         continue;
      
     // rectangle(contour_shading, Point(box.x,box.y), Point(box.x+box.width,box.y+box.height), Color::RANDOM(), CV_FILLED);
      

      Blob blob(box);
      blob.score = score;
      blobs.push_back(blob);
      
   }
   
   
   Mat blobs_image = dark.clone();
   
   Painter::drawBlobsRandomShading(blobs_image, blobs);
   VLOG("BlobHypotheses", blobs_image); 
   
   
   // remove overlapping blobs
   // and do non-maximal suppression
   vector nonoverlapping_blobs;
   
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& b = *it;
      
      bool not_overlap = true;
      int tolerance = 3;
      vector::iterator ito;
      for (ito = nonoverlapping_blobs.begin();
           ito != nonoverlapping_blobs.end(); ++ito){
         
         Blob& bo = *ito;
         
         not_overlap = b.x >= bo.x + bo.width - tolerance || b.y >= bo.y + bo.height - tolerance||
            b.x + b.width <= bo.x + tolerance|| b.y + b.height <= bo.y + tolerance;
         
         if (!not_overlap)
            break;
         
      }
      
      if (not_overlap){
         
         nonoverlapping_blobs.push_back(b);
         
      }else{
         // replace it if the score is better
      
         if (it->score > ito->score){
          
            (*ito) = (*it);
         }
         
      }
      
   }
   
   
   vector& result_blobs = nonoverlapping_blobs;
   
   
   Mat result_blobs_image = dark.clone();
   Painter::drawBlobsRandomShading(result_blobs_image, result_blobs);
   VLOG("OutputBlobs", result_blobs_image);
   
   // print output to stdout
   for (vector::iterator it = result_blobs.begin();
        it != result_blobs.end(); ++it){
      Blob& b = *it;
      dout() << b.x << " " << b.y << " " << b.width << " " << b.height << " " << b.score << endl;
   }
   
   
   return result_blobs_image;
}

Mat
cvgui::findPokerBoxes(const Mat& screen, vector& output_blobs){
   
   
   //return findBoxesByVoting(screen, 70, 90, output_blobs);
   return findBoxesByVoting(screen, 40, 50, output_blobs);
   
   
// old algorithm
#if 0   
   Mat dark;
   Util::rgb2grayC3(screen,dark);
   dark = dark * 0.5;
   
   
   VLOG("Input", screen);
   
   Mat gray;
   cvtColor(screen,gray,CV_RGB2GRAY);
   
   //medianBlur(gray, gray, 3);
   //VLOG("Blurred", gray); 
   
   Mat edges;
   
   // Code for experimenting differenty parameters for Canny
   //   for (int c=10;c<=100;c=c+10){
   //      char buf[50];
   //      Mat test;
   //      sprintf(buf,"Canny%d",c);
   //      Canny(gray,test,0.66*c,1.33*c,3,true);  
   //      VLOG(buf, test);       
   //   }
   
   int s = 100;
   Canny(gray,edges,0.66*s,1.33*s,3,true);  
   VLOG("Canny", edges); 
   
   
   Mat v = Mat::ones(2,2,CV_8UC1);

   dilate(edges, edges, v);
   erode(edges, edges, v);

   VLOG("Dilated", edges); 
   
   // experimental
   Mat hlines,vlines;
   dilate(edges, edges, Mat::ones(3,2,CV_8UC1));
   
   
   findLongLines_Vertical(edges,vlines, 50, 2);
   VLOG("V-lines", vlines); 
   
   findLongLines_Horizontal(edges,hlines, 50, 2);
   VLOG("H-lines", hlines);

   
   int bw = 70;
   int bh = 20;
   double k = 0.90;
   
   Mat q = Mat::ones(5,5,CV_8UC1);
   
   Mat h1,h2,hvotes;
   voteCenter_Horizontal(edges, h1, bw*k, 2, bh/2);
   dilate(h1, h1, q);
   voteCenter_Horizontal(edges, h2, bw*k, 2, -bh/2);
   dilate(h2, h2, q);

   bitwise_and(h1,h2,hvotes);
   VLOG("H-votes", hvotes); 

   
   Mat v1,v2,vvotes;
   voteCenter_Vertical(edges, v1, bh*k, 2, bw/2);
   dilate(v1, v1, q);

   voteCenter_Vertical(edges, v2, bh*k, 2, -bw/2);
   dilate(v2, v2, q);

   bitwise_and(v1,v2,vvotes);
   VLOG("V-votes", vvotes); 

   Mat hvvotes;
   bitwise_and(vvotes,hvotes,hvvotes);
   VLOG("HV-votes", hvvotes); 
   
   
//   Mat hvlines;
//   bitwise_or(hlines, vlines, hvlines);
//   VLOG("HV-lines", hvlines);
   
   // 

   Mat lines;
   findLongLines(edges, lines, 15);
   
   Mat w = Mat::ones(5,5,CV_8UC1);
   dilate(lines, lines, w);
   erode(lines, lines, w);
   
   VLOG("Lines", lines); 

   
   Mat lines2;
   Mat z = Mat::ones(2,2,CV_8UC1);   

   dilate(lines, lines, z);
   
   findLongLines(lines, lines2, 30, 15);

   //dilate(lines2, lines2, z);
   //erode(lines2, lines2, z);
   
   VLOG("Lines2", lines2); 


   
   Mat result = dark.clone();
   //Mat copy = edges.clone();
   //Mat copy = lines.clone();
   
   Mat copy = lines2.clone();
   
   
   vector > contours;
   vector hierarchy;
   
   findContours( copy, contours, hierarchy,
                CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
  
   vector blobs;
   
   Mat blank = dark.clone();
   blank = 0.0;
   
   Mat contour_shading = blank;//dark.clone();
   
   for (vector >::iterator it = contours.begin();
        it != contours.end(); ++it){
      
      vector& contour = *it;
      
      Rect r = boundingRect(Mat(contour));
      
      double a1 = contourArea(Mat(contour));
      double a2 = r.height * r.width;
      
      
      if (a2 < 100)
         continue;
         
      
      if (abs(r.width - 65) > 5)
         continue;
      
      //if ( min(a1,a2)/max(a1,a2) > 0.80){
         
         vector > cs;
         cs.push_back(contour);
         drawContours(contour_shading, cs, -1, Color::RANDOM(), CV_FILLED);
         
         
         Blob blob(r);
         blobs.push_back(blob);
      //}
      
   }
   
   Mat contours_image = contour_shading*0.7 + dark*0.5;

   Painter::drawBlobs(contours_image, blobs, Color::WHITE);

   VLOG("ColoredSelectedContours", contours_image); 
   
   

   
   vector nonoverlapping_blobs;

   // print output to stdout
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& b = *it;
      bool not_overlap = true;
      for (vector::iterator ito = nonoverlapping_blobs.begin();
           ito != nonoverlapping_blobs.end(); ++ito){
            
         Blob& bo = *ito;
         
         not_overlap = b.x >= bo.x + bo.width || b.y >= bo.y + bo.height ||
         b.x + b.width <= bo.x || b.y + b.height <= bo.y;
            
         if (!not_overlap)
            break;
         
      }
      
      if (not_overlap){
         nonoverlapping_blobs.push_back(b);
      }
      
   }
   
   
   vector& result_blobs = nonoverlapping_blobs
   
   
   Mat blobs_result = dark.clone();
   Painter::drawBlobs(blobs_result, result_blobs, Color::RED);
   
   VLOG("OutputBlobs", blobs_result);
   
   // print output to stdout
   for (vector::iterator it = result_blobs.begin();
        it != result_blobs.end(); ++it){
   
      dout() << b.x << " " << b.y << " " << b.width << " " << b.height << endl;
   }

      
   return contours_image;
#endif     
}

void
cvgui::findBoxes(const Mat& screen, vector& output_blobs){

   Mat dark;
   Util::rgb2grayC3(screen,dark);
   dark = dark * 0.5;
   
   
   VLOG("Input", screen);
   
   Mat gray;
   cvtColor(screen,gray,CV_RGB2GRAY);
   
   //medianBlur(gray, gray, 3);
   //VLOG("Blurred", gray); 
   
   Mat edges;

// Code for experimenting differenty parameters for Canny
//   for (int c=10;c<=100;c=c+10){
//      char buf[50];
//      Mat test;
//      sprintf(buf,"Canny%d",c);
//      Canny(gray,test,0.66*c,1.33*c,3,true);  
//      VLOG(buf, test);       
//   }

   int s = 100;
   Canny(gray,edges,0.66*s,1.33*s,3,true);  
   VLOG("Canny", edges); 


   dilate(edges, edges, Mat::ones(2,2,CV_8UC1));
   VLOG("Dilated", edges); 


   
   
   Mat result = dark.clone();
   Mat copy = edges.clone();
   
   
   vector > contours;
   vector hierarchy;
   
   findContours( copy, contours, hierarchy,
                CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

//   findContours(edges, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);

   //findContours( copy, contours, hierarchy,
    //            CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
   
//   cout << contours.size() << " " << hierarchy.size() << endl;
   // iterate through all the top-level contours,
   // draw each connected component with its own random color
//   int idx = 0;
//   for( ; idx >= 0; idx = hierarchy[idx][0]){
//      
//      vector& contour = contours[idx];
//      
//      
//      //Scalar color( rand()&255, rand()&255, rand()&255 );
//      Scalar cyan(255,255,0);
//      vector > cs;
//      cs.push_back(contour);
//      drawContours( result, cs, -1, cyan, 2);//, CV_FILLED);
//      
// //     drawContours( result, contours, idx, color, CV_FILLED, 8, hierarchy );
//
//   }
   
   vector blobs;
   
   
   Mat box_contour_image = dark.clone();
   
   for (vector >::iterator it = contours.begin();
        it != contours.end(); ++it){
      
      vector& contour = *it;
    
      Rect r = boundingRect(Mat(contour));
      
      double a1 = contourArea(Mat(contour));
      double a2 = r.height * r.width;
      
      
      
      
      if ( min(a1,a2)/max(a1,a2) > 0.80){

         vector > cs;
         cs.push_back(contour);
         drawContours(box_contour_image, cs, -1, Color::RANDOM(), 2);//, CV_FILLED);
         
         
         Blob blob(r);
         blobs.push_back(blob);
      }
      
   }
   
        
   VLOG("Box-shaped contours", box_contour_image); 
   
   
   Mat blobs_result = dark.clone();
   Painter::drawBlobs(blobs_result, blobs, Color::RED);
   
   VLOG("Blobs", blobs_result);
   
   
   vector unique_blobs;
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& a = *it;

      
      vector::iterator it1;
      for (it1 = unique_blobs.begin(); 
           it1 != unique_blobs.end(); ++it1){
         
         Blob& b = *it1;
         
         int d = 5;
         bool similar_bounding_box = 
            abs(a.x-b.x) < d && abs(a.y-b.y) < d &&
         abs(a.height-b.height) < 2*d &&
         abs(a.width-b.width) < 2*d;
         
         
         if (similar_bounding_box)
            break;
            
      }
      
      // if no blob whose bounding box is similar
      if (it1 == unique_blobs.end()){
       
         // add this blob to the list of unique blobs
         unique_blobs.push_back(a);
      }
   }
   
   Mat unique_blobs_result = dark.clone();
   Painter::drawBlobs(unique_blobs_result, unique_blobs, Color::RED);
   
   VLOG("UniqueBlobs", unique_blobs_result);
   
   
   vector leaf_blobs;
   getLeafBlobs(unique_blobs, leaf_blobs);
   
      
   Mat leaf_blobs_result = dark.clone();
   Painter::drawBlobs(leaf_blobs_result, leaf_blobs, Color::RED);
   VLOG("LeafBlobs", leaf_blobs_result);
   
   output_blobs = leaf_blobs;
}




void
cvgui::computeUnitBlobs(const Mat& screen, Mat& output){
   
   VLOG("Input", screen);
   
   Mat gray;
   cvtColor(screen,gray,CV_RGB2GRAY);
   
   
   Mat edges;
   Canny(gray,edges,0.66*50,1.33*50,3,true);  
   VLOG("Canny", edges); 
   
//   Mat corners;
//   cornerHarris(gray,corners,10,5,1.0);

//   Mat corners_result = screen.clone();
//   vector corners;
//   goodFeaturesToTrack(gray, corners, 50, 0.5, 10);
//   for (vector::iterator it = corners.begin(); it != corners.end(); ++it){
//      Point2f& p = *it;
//      circle(corners_result, p, 3, Scalar(0,0,255));
//   }
//   VLOG("Corners", corners_result); 
   
   
   adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 5, 1);
   VLOG("AdaptiveThresholded", gray);
   
   Mat lines;
   cvgui::findLongLines(gray, lines);
   
   Mat lines_viz = lines.clone();
   dilate(lines_viz, lines_viz, Mat::ones(4,4,CV_8UC1));
   VLOG("LongLinesFound", lines_viz);
   
   Mat not_lines;
   bitwise_not(lines, not_lines);
   
   Mat foreground;
   bitwise_and(gray, not_lines, foreground);
   
   gray.setTo(0, lines);
   VLOG("LongLinesRemoved",gray);
   
   
   dilate(edges, edges, Mat::ones(3,3,CV_8UC1));
   bitwise_and(gray, edges, gray);
   
   VLOG("NonEdgeRemoved", gray);
   
   //GaussianBlur(gray, gray, Size(3, 3), 3);
   //VLOG("Blurred", gray); 

   output = gray;
}



void 
cvgui::getParagraphBlobs(const Mat& screen, vector& output_parablobs){
      
   VisualLogger::newImage();
   Mat screen_gray;
   cvtColor(screen,screen_gray,CV_RGB2GRAY);
   
   Mat blobs_mask;
   cvgui::computeUnitBlobs(screen, blobs_mask);
   
   Mat dark;
   Util::rgb2grayC3(screen,dark);
   dark = dark * 0.5;
   
   vector blobs;
   cvgui::extractBlobs(blobs_mask, blobs);
   
   cvgui::calculateColor(blobs, screen, blobs_mask);
   
   // draw blobs
   Mat result_blobs = dark.clone();
   Painter::drawBlobs(result_blobs, blobs, Scalar(255,255,0));   
   VLOG("blobs-extracted",result_blobs);
   
   
   vector filtered_blobs;
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& blob = *it;
      
      //  if (blob.height < 3 && blob.width < 3)
      //         continue;
      //      
      //      if (blob.height < 4)
      //         continue;
      
      filtered_blobs.push_back(blob);
   }
   
   Mat result_filtered_blobs = dark.clone();
   Painter::drawBlobs(result_filtered_blobs, filtered_blobs, Scalar(255,255,0));
   
   VLOG("blobs-filtered",result_filtered_blobs);
   
   
   Mat result_lineblobs = dark.clone();
   
   vector lineblobs;
   cvgui::linkBlobsIntoLineBlobs(filtered_blobs, lineblobs, 20);
   
   Painter::drawLineBlobs(result_lineblobs, lineblobs, Scalar(255,255,0));
   VLOG("lineblobs", result_lineblobs);
   
   
   Mat result_lineblobs_filtered = dark.clone();
   vector filtered_lineblobs;
   
   // Calculate the bounding rectangle of each line of linked blobs
   for (vector::iterator it_lines = lineblobs.begin();
        it_lines != lineblobs.end(); ++ it_lines){
      
      LineBlob& line = *it_lines;
      
      // Ignore lines with fewer than X elements
      if (line.blobs.size()<2)
         continue;

      
      if (line.height < 3)
         continue;
      
      filtered_lineblobs.push_back(line);
   }
   
   
   
   Painter::drawLineBlobs(result_lineblobs_filtered, filtered_lineblobs, Scalar(255,255,0));   
   VLOG("lineblobs-filtered", result_lineblobs_filtered);
   
   
   Mat result_merged_blobs = dark.clone();
   
   vector merged_lineblobs;
   cvgui::mergeLineBlobs(filtered_lineblobs, merged_lineblobs);
   Painter::drawLineBlobs(result_merged_blobs, merged_lineblobs, Scalar(255,255,0));
   VLOG("lineblobs-merged", result_merged_blobs);


   vector parablobs;
   cvgui::linkLineBlobsIntoPagagraphBlobs(merged_lineblobs, parablobs);
   
   Mat result_linked_parablobs = dark.clone();
   
   Painter::drawParagraphBlobs(result_linked_parablobs, parablobs, Scalar(255,0,0));
   
   VLOG("paragblobs", result_linked_parablobs);
   
   
   output_parablobs = parablobs;
   
   
//  Mat screen_dark = screen * 0.2;
//   Mat ocr_result_image = screen_dark;
//   
//   
//   for (vector::iterator it = parablobs.begin(); 
//        it != parablobs.end(); ++it){
//      
//      
//      ParagraphBlob& parablob = *it;      
//      
//      vector ocrlines;
//      
//      cvgui::run_ocr_on_lineblobs(parablob.lineblobs, screen_gray, ocrlines);
//      
//      Painter::drawOCRLines(ocr_result_image, ocrlines);
//      
//   }
//   
//   VLOG("OCR-Result", ocr_result_image);
   
   
}


void
cvgui::getLineBlobsAsIndividualWords(const Mat& screen, vector& output_lineblobs){

   Mat screen_gray;
   cvtColor(screen,screen_gray,CV_RGB2GRAY);
   
   Mat blobs_mask;
   cvgui::computeUnitBlobs(screen, blobs_mask);
   
   Mat dark;
   Util::rgb2grayC3(screen,dark);
   dark = dark * 0.5;
   
   vector blobs;
   cvgui::extractBlobs(blobs_mask, blobs);
   
   cvgui::calculateColor(blobs, screen, blobs_mask);
   
   // draw blobs
   Mat result_blobs = dark.clone();
   Painter::drawBlobs(result_blobs, blobs, Scalar(255,255,0));   
   VLOG("blobs-extracted",result_blobs);
   
   
   vector filtered_blobs;
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& blob = *it;
      
      //  if (blob.height < 3 && blob.width < 3)
      //         continue;
      //      
      //      if (blob.height < 4)
      //         continue;
      
      filtered_blobs.push_back(blob);
   }
   
   Mat result_filtered_blobs = dark.clone();
   Painter::drawBlobs(result_filtered_blobs, filtered_blobs, Scalar(255,255,0));
   
   VLOG("blobs-filtered",result_filtered_blobs);
   
   
   Mat result_lineblobs = dark.clone();
   
   vector lineblobs;
   cvgui::linkBlobsIntoLineBlobs(filtered_blobs, lineblobs, 3);
   
   Painter::drawLineBlobs(result_lineblobs, lineblobs, Scalar(255,255,0));
   VLOG("lineblobs", result_lineblobs);
   
   
   Mat result_lineblobs_filtered = dark.clone();
   vector filtered_lineblobs;
   
   // Calculate the bounding rectangle of each line of linked blobs
   for (vector::iterator it_lines = lineblobs.begin();
        it_lines != lineblobs.end(); ++ it_lines){
      
      LineBlob& line = *it_lines;
      
      // Ignore lines with fewer than X elements
//      if (line.blobs.size()<2)
//         continue;
      
      if (line.height < 3)
         continue;
      
      filtered_lineblobs.push_back(line);
   }
   
   
   
   Painter::drawLineBlobs(result_lineblobs_filtered, filtered_lineblobs, Scalar(255,255,0));   
   VLOG("lineblobs-filtered", result_lineblobs_filtered);
   
   
   
   output_lineblobs = filtered_lineblobs;
   
  // Mat result_merged_blobs = dark.clone();
//   
//   vector merged_lineblobs;
//   cvgui::mergeLineBlobs(filtered_lineblobs, merged_lineblobs);
//   Painter::drawLineBlobs(result_merged_blobs, merged_lineblobs, Scalar(255,255,0));
//   VLOG("lineblobs-merged", result_merged_blobs);
//   
//   
//   vector parablobs;
//   cvgui::linkLineBlobsIntoPagagraphBlobs(merged_lineblobs, parablobs);
//   
//   Mat result_linked_parablobs = dark.clone();
//   
//   Painter::drawParagraphBlobs(result_linked_parablobs, parablobs, Scalar(255,0,0));
//   
//   VLOG("paragraph-linked", result_linked_parablobs);
//   
//   
//   Mat screen_dark = screen * 0.2;
//   Mat ocr_result_image = screen_dark;
//   
//   
//   for (vector::iterator it = parablobs.begin(); 
//        it != parablobs.end(); ++it){
//      
//      
//      ParagraphBlob& parablob = *it;      
//      
//      vector ocrlines;
//      
//      cvgui::run_ocr_on_lineblobs(parablob.lineblobs, screen_gray, ocrlines);
//      
//      Painter::drawOCRLines(ocr_result_image, ocrlines);
//      
//   }
//   
//   VLOG("OCR-Result", ocr_result_image);
}

/* not used currently
void 
cvgui::segmentScreenshot(const Mat& screen, vector& text_blobs, vector& image_blobs){
   
   VLOG("Input", screen);
   
   Mat gray, screen_gray;
   if(screen.channels() > 1){
      cvtColor(screen,gray,CV_RGB2GRAY);
   }
   else
      gray = screen;

   screen_gray = gray.clone();
   
   adaptiveThreshold(gray, gray, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 5, 1);
   VLOG("AdaptiveThresholded", gray);
   
   
   Mat lines;
   cvgui::findLongLines(gray, lines);
   
   Mat lines_viz = lines.clone();
   dilate(lines_viz, lines_viz, Mat::ones(4,4,CV_8UC1));
   VLOG("LongLinesFound", lines_viz);
   
   Mat not_lines;
   bitwise_not(lines, not_lines);
   
   Mat foreground;
   bitwise_and(gray, not_lines, foreground);
   
   gray.setTo(0, lines);
   VLOG("LongLinesRemoved",gray);
   
   
   denoise(gray);   
   VLOG("NoiseRemoved", gray);  
   
   dilate(gray,gray,Mat::ones(1,3,CV_8UC1));
   VLOG("Dilated",gray);
   
   vector rects;
   //cvgui::extractRects(gray, rects);
   
   vector blobs;
   cvgui::extractBlobs(gray, blobs);
   
   
   Mat dilated = gray.clone();
   
   
   // visualization
   Mat result;
   Mat g;
   cvtColor(screen, g, CV_RGB2GRAY);
   
   Mat ss[3] = {g,g,g};
   merge(ss,3,result);   
   result = result * 0.5;
   
   Mat bg = result.clone();
   Mat screen_darken = bg.clone();
   
   
   text_blobs.clear();
   
   for (vector::iterator b = blobs.begin(); b != blobs.end(); ++b){
      
      Blob& blob = *b;
      Rect& bound = blob;
      Mat part(screen, bound);
      //paste(part, result, r->x, r->y);
      
      Mat p = part.clone();
      Mat g;
      cvtColor(p, g, CV_RGB2GRAY);
      adaptiveThreshold(g, g, 255, 
                        ADAPTIVE_THRESH_MEAN_C, 
                        THRESH_BINARY_INV, 3, 1);
      vector rs;
      cvgui::extractSmallRects(g, rs);
      for (vector::iterator r = rs.begin();r != rs.end(); ++r){
         r->x += bound.x;
         r->y += bound.y;
      }
      
      vector rs0;
      for (vector::iterator q = rs.begin();
           q != rs.end(); ++q){
         
         // exclude overly short element (e.g., dot of i)
         if (q->height < 5)
            continue;         
         
         rs0.push_back(*q);
      }
      
      rs = rs0;
      
      // re-calculate the bounds
      int x1,y1,x2,y2;
      x1 = bound.x + bound.width;
      y1 = bound.y + bound.height;
      x2 = bound.x;
      y2 = bound.y;
      
      for (vector::iterator r = rs.begin();
           r != rs.end(); ++r){
         x1 = min(x1, r->x);
         y1 = min(y1, r->y);
         x2 = max(x2, r->x + r->width);
         y2 = max(y2, r->y + r->height);
      }
      
      //blob.bound = Rect(x1-2,y1-2,x2-x1+4,y2-y1+4);     
      //blob.bound = Rect(x1,y1,x2-x1,y2-y1); 
      
      // make the bound bigger to be consistent with the dilated blobs
      blob = Blob(Rect(x1-2,y1-1,x2-x1+4,y2-y1+2)); 
      
      
      int MINIMUM_NUM_CHARBLOBS = 2;
      
      if (cvgui::areHorizontallyAligned(rs) && rs.size()>=MINIMUM_NUM_CHARBLOBS)
         Painter::drawRects(result, rs, Scalar(0,255,0));
      else
         Painter::drawRects(result, rs, Scalar(0,0,255));
      
      if (cvgui::areHorizontallyAligned(rs) && rs.size()>=MINIMUM_NUM_CHARBLOBS){
         text_blobs.push_back(blob);
      }
      
   }
   
   //drawRects(result, rects, Scalar(255,0,0));
   Painter::drawBlobs(result, blobs, Scalar(255,0,0));
   
   VLOG("TextBlocksExtracted",result);
   
   
   
   Mat text_mask = Mat::zeros(screen.size(), CV_8UC1);
   
   
   for (vector::iterator b = text_blobs.begin();
        b != text_blobs.end(); ++b){
      
      Rect& r = *b;
      Mat m(text_mask, 
            Range(r.y,r.y+r.height),
            Range(r.x,r.x+r.width));
      
      m = 255;
      
   }
   
   VLOG("TextBinaryMaskComputed", text_mask);
   
   
   
   
   gray.setTo(0, text_mask);
   VLOG("AfterTextRemoved",gray);
   
   dilate(gray,gray,Mat());
   VLOG("DilatedAgain",gray);
   
   Mat dilated_again = gray.clone();
   
   vector temp;
   //cvgui::extractRects(gray, temp);
   cvgui::extractBlobs(gray, temp);
   
   // only keep image rects larger than n pixels
   
   const int MIN_IMAGE_RECT_AREA = 150;
   
   image_blobs.clear();
   for (vector::iterator b = temp.begin();
        b != temp.end(); ++b){
      
      if (b->width * b->height < MIN_IMAGE_RECT_AREA)
         continue;
      
      //      // blob is too big, something is wrong
      //      if (b->bound.width > 0.8 * screen.width)
      //         continue;
      //      if (b->bound.height > 0.8 * screen.height)
      //         continue;
      
      image_blobs.push_back(*b);
      
   }
   
   Mat image_result = bg.clone();
   
   Painter::drawBlobs(image_result, image_blobs, Scalar(0,0,255));
   VLOG("ImageRecordsExtracted", image_result);

   return;
   
   Mat ui_mask = Mat::zeros(screen.size(), CV_8UC1);
   Mat photo_mask = Mat::zeros(screen.size(), CV_8UC1);
   for (vector::iterator b = image_blobs.begin();
        b != image_blobs.end(); ++b){
      
      Rect& r = *b;
      Mat mask;
      if (r.height < 100)
         mask = ui_mask;
      else 
         mask = photo_mask;
      
      Mat m(mask, 
            Range(r.y,r.y+r.height),
            Range(r.x,r.x+r.width));
      
      m = 255;
   }
   
   VLOG("UIMask", ui_mask);
   VLOG("PhotoMask", photo_mask);
   
   Mat segmap;
   Mat segmapr;
   Mat segmapg;
   Mat segmapb;
   
   bitwise_and(dilated,text_mask,segmapr);
   bitwise_and(dilated,ui_mask,segmapg);
   bitwise_and(dilated_again,photo_mask,segmapb);
   //segmapb = photo_mask;
   
   
   Mat cs[3] = {segmapb, segmapg,segmapr};
   merge(cs,3,segmap);   
   VLOG("SegMap", segmap);
   
   
   //Mat wordmap = screen_darken.clone();//segmap.clone();
   Mat wordmap = Mat::zeros(screen.size(), CV_8UC3);
   
   
   screen.copyTo(wordmap, segmapg);
   screen.copyTo(wordmap, photo_mask);
   screen.copyTo(wordmap, text_mask);
   
   
   
   Mat random_ids = Mat::ones(1,100,CV_8UC1);
   randu(random_ids, 22, 80);
   
   Scalar white(255,255,255);
   Scalar black(0,0,0);
   Scalar yellow(255,255,0);
   
   
   int i = 0;
   
   for (vector::iterator b = image_blobs.begin();
        b != image_blobs.end(); ++b){
      
      Rect& r = *b;
      
      
      char vwstr[100];
      
      
      if (r.height < 100){
         
         int xc = r.x + r.width/2;
         int yc = r.y + r.height/2;
         
         
         //         putTextWithBackgroundCentered(black, wordmap, "u12", Point(xc,yc), 
         //                               FONT_HERSHEY_SIMPLEX, 0.5, white);
         
         int id = random_ids.at(0,i++);
         sprintf(vwstr,"u%d",id);   
         
//         putTextWithBackgroundCentered(white, wordmap, vwstr, Point(xc,yc), 
//                                       FONT_HERSHEY_DUPLEX, 0.5, black);
         
         
      }else{ 
         
         
//TODO         SURF surf_extractor(6.0e3);
         vector keypoints;
         
         // printf("Extracting keypoints\n");
//TODO         surf_extractor(screen_gray, photo_mask, keypoints);
         //printf("Extracted %d keypoints from the image\n", (int)keypoints.size());
         
         for (vector::iterator it = keypoints.begin(); it != keypoints.end(); ++it){
            KeyPoint& p = *it;
            
            circle(wordmap, p.pt, p.size*1.5, yellow);
            
            //            putTextWithBackgroundCentered(black, wordmap, "v12", p.pt,  
            //                                  FONT_HERSHEY_SIMPLEX, 0.5, white);
            
            int id = random_ids.at(0,i++);
            sprintf(vwstr,"s%d",id);
            
//            putTextWithBackgroundCentered(white, wordmap, vwstr, p.pt,  
//                                          FONT_HERSHEY_DUPLEX, 0.5, black);
            
         }
      }
      
      
   }
   
   VLOG("WordMap", wordmap);
}
*/



static int L1dist(Vec3b p1, Vec3b p2){
	return max(p1[0],p2[0])-min(p1[0],p2[0])+	
   max(p1[1],p2[1])-min(p1[1],p2[1])+
   max(p1[2],p2[2])-min(p1[2],p2[2]);	
}



bool 
cvgui::areHorizontallyAligned(const vector& rects){
   
   if (rects.size() <= 1)
      return true;
   
   vector sorted_rects = rects;
   sort(sorted_rects, sort_by_x);
   
   int ymin = 10000;
   int ymax = 0;
   
   bool no_overlap = true;
   for (vector::const_iterator r = sorted_rects.begin() + 1;
        r != sorted_rects.end(); ++r){
      
      no_overlap = no_overlap && (r->x >= (r-1)->x + (r-1)->width - 2);
      
      int baseline = r->y + r->height;
      ymin = min(baseline, ymin);
      ymax = max(baseline, ymax);
   }
   
   bool baseline_aligned = (ymax - ymin < 10);
   
   int minv = 10000;
   int maxv = 0;   
   for (vector::const_iterator r = sorted_rects.begin();
        r != sorted_rects.end(); ++r){
      
      int v = r->height;
      minv = min(v, minv);
      maxv = max(v, maxv);
   }
   
   bool height_similar = (maxv - minv < 10);
   
   // if the difference between the highest and lowest baseline
   // is too large, it means the rects are not alginged horizontally
   
   return baseline_aligned && height_similar && no_overlap;
}


bool
cvgui::hasMoreThanNUniqueColors(const Mat& src, int n){
   
   
   Mat_::const_iterator it = src.begin(),
   itEnd = src.end();
   
   
   vector< pair > colors; 
   //vector counts;
   colors.push_back( pair(*it,1) );
   ++it;
   
   for(; it != itEnd; ++it){
      
      bool matched;
      matched = false;
      for (vector< pair >::iterator c = colors.begin();
           c != colors.end();
           ++c){
         
         Vec3b& color = (*c).first;
         int& count = (*c).second;
         
         int d = L1dist((*it), (color));
         //cout << d << endl;
         if (d < 150){
            matched = true;
            count++;
            break;
         }
      }
      
      if (!matched){
         
         //    if (colors.size() == 4)
         //     return true;
         // else
         colors.push_back(pair(*it,1));
         
      }
      
   }
   
   dout() << endl << endl;
   for (vector< pair >::iterator c = colors.begin();
        c != colors.end();
        ++c){
      
      Vec3b& color = (*c).first;
      int& count = (*c).second;
      //cout << count << endl;
   }
   
   return (colors.size() > 5);
}


void 
cvgui::extractSmallRects(const Mat& src, 
                         vector& rects){
   
   Mat copy = src.clone();
   
   vector > contours;
   findContours(copy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
   
   for (vector >::iterator contour = contours.begin();
        contour != contours.end(); ++contour){
      
      Rect bound = boundingRect(Mat(*contour));
      rects.push_back(bound);
   }
   
}

void
cvgui::calculateColor(vector& blobs, 
                      const Mat& color_image,
                      const Mat& foreground_mask){
   
   
   for (vector::iterator it = blobs.begin();
        it != blobs.end(); ++it){
      
      Blob& blob = *it;
      
      
      Mat part(color_image, blob);
      Mat mask(foreground_mask, blob);
      Scalar mean, stddev;
      meanStdDev(part, mean, stddev, mask);
      
      blob.mr = mean[0];
      blob.mg = mean[1];
      blob.mb = mean[2];
      
   }
   
}


void 
cvgui::extractBlobs(const Mat& src, vector& blobs){
   
   Mat copy = src.clone();
   blobs.clear();
   
   vector > contours;
   findContours(copy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
   
   
   for (vector >::iterator contour = contours.begin();
        contour != contours.end(); ++contour){
      
      
      double area = contourArea(Mat(*contour));
      
      Rect bound = boundingRect(Mat(*contour));
      
      
      
      
      Blob blob(bound);
      blob.area = area;
      blobs.push_back(blob);
      
   }
   
   
   
   
   
}


void 
cvgui::extractRects(const Mat& src, 
                    vector& rects){
   
   Mat copy = src.clone();
   rects.clear();
   
   
   vector > contours;
   findContours(copy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
   
   
   for (vector >::iterator contour = contours.begin();
        contour != contours.end(); ++contour){
      
      
      double area = contourArea(Mat(*contour));
      
      Rect bound = boundingRect(Mat(*contour));
      
      
      // too small
      if (bound.width < 6 || bound.height < 6)
         continue;
      
      // too empty
      if (bound.height > 100 && bound.width * bound.height * 0.50 > area)
         continue;
      
      rects.push_back(bound);
      
   }
   
}

void
cvgui::findLongLines_Vertical(const Mat& src, Mat& dest, int min_length, int extension){
   dest = src.clone();

   Mat maskT, destT;
   transpose(dest,destT);
   cvgui::findLongLines_Horizontal(destT,maskT,min_length, extension);
   
   Mat maskTT;
   transpose(maskT,maskTT);   
   dest = maskTT;
}


void
cvgui::findLongLines(const Mat& src, Mat& dest, int min_length, int extension){
   
   Mat copy = src.clone();
   Mat v,h;
  
   cvgui::findLongLines_Horizontal(copy, h, min_length, extension);

   
   cvgui::findLongLines_Vertical(copy, v, min_length, extension);

//   Mat maskT, destT;
//   transpose(dest,destT);
//   cvgui::findLongLines_Horizontal(destT,maskT,min_length, extension);
//   
//   Mat maskTT;
//   transpose(maskT,maskTT);
   
   
   bitwise_or(v,h,dest);
   
}


//void
//cvgui::filterLineSegments(const Mat& src, Mat& dest,
//                          int min_length, int max_length){
//   
//   typedef uchar T;
//   
//   int extension = 5;
//   
//  	dest = Mat::zeros(src.rows,src.cols,CV_8UC1);
//   
//	Size size = src.size();
//	for( int i = 0; i < size.height; i +=1 ){
//      
//		const T* ptr1 = src.ptr(i);
//		T* ptr2 = dest.ptr(i);	
//		
//		bool has_previous_baseline = false;
//		int previous_baseline_endpoint = 0;
//		int current_baseline_startpoint = 0;
//      
//      
//      for( int j = 1; j < size.width; j += 1 ){			
//			
//         
//         if (ptr1[j] > 0 && ptr1[j-1] == 0){
//            current_baseline_startpoint = j;
//         }
//         
//         if (ptr1[j-1] > 0 &&  (ptr1[j] == 0 || j == size.width - 1)){
//            
//            
//				// check for the condition of a baseline hypothesis
//				// the length of the baseline must be > 15
//				if ((j - current_baseline_startpoint) > min_length){// || j == size.width - 1){
//					
//               //					int closeness_threshold = 1; 					
//               //					if (has_previous_baseline && 
//               //                   (current_baseline_startpoint - previous_baseline_endpoint) 
//               //						 <= closeness_threshold){
//               //						
//               //						
//               //						// merge the current baseline with the previously baseline
//               //						for (int k=previous_baseline_endpoint; 
//               //                       k < current_baseline_startpoint; k += 1){
//               //	                     ptr2[k] = ptr1[j];
//               //						}
//               //					}
//					
//               //	has_previous_baseline = true;
//					//previous_baseline_endpoint = j;
//					
//               
//					for (int k=current_baseline_startpoint; k < j; ++k){
//                  ptr2[k] = 255;
//					}	
//               
//               for (int k=j; k < min(j+extension,size.width-1); ++k){
//                  ptr2[k] = 255;
//					}	
//               
//					
//				}
//				
//				// forming a new baseline hypothesis
//				//current_baseline_startpoint = j+1;
//			}
//      }
//   }	 
//   
//}


void
cvgui::voteCenter_Vertical(const Mat& binary, Mat& dest,
                             int min_length, int tolerance, int distance){

   dest = binary.clone();
   
   Mat maskT, destT;
   transpose(dest,destT);
   cvgui::voteCenter_Horizontal(destT,maskT,min_length,tolerance,distance);
   
   Mat maskTT;
   transpose(maskT,maskTT);   
   dest = maskTT;
}

void
cvgui::voteCenter_Horizontal(const Mat& binary, Mat& dest,
                             int min_length, int tolerance, int distance){
   
   typedef uchar T;
   
  	dest = Mat::zeros(binary.rows,binary.cols,CV_8UC1);
   
	Size size = binary.size();
	for( int i = 0; i < size.height; i +=1 ){
      
		const T* ptr1 = binary.ptr(i);
		T* ptr2 = 0;
      //dest.ptr(i);
//      
//      
//      T* ptru = 0;
//      T* ptrb = 0;
//      
      int grid = 5;
      
      
      int gi = grid*(i+distance)/grid;
      
      if (gi >= 0 && gi < size.height){
         ptr2 = dest.ptr(i+distance);
      }
      
//      if (grid*(i+distance)/grid(i+distance);
//      }
		
		bool has_previous_baseline = false;
		int previous_baseline_endpoint = 0;
		int current_baseline_startpoint = 0;
      
      
      for( int j = 1; j < size.width; j += 1 ){			
			
         
         if (ptr1[j] > 0 && ptr1[j-1] == 0){
            current_baseline_startpoint = j;
         }
         
         if (ptr1[j-1] > 0 &&  (ptr1[j] == 0 || j == size.width - 1)){
            
            
				// check for the condition of a baseline hypothesis
				// the length of the baseline must be > 15
				if ((j - current_baseline_startpoint) > min_length){// || j == size.width - 1){
		
					
               
					for (int k=current_baseline_startpoint+min_length/2; k < j-min_length/2; ++k){
                  
                  if (ptr2)
                     ptr2[k] = 255;                  
					}	

               for (int k=j-min_length/2; k < min(j-min_length/2+tolerance,size.width-1); ++k){
                 
                  if (ptr2)
                     ptr2[k] = 255;
                  
					}	
               
					
				}
				
				// forming a new baseline hypothesis
				//current_baseline_startpoint = j+1;
			}
      }
   }	 
   
}  

void
cvgui::findLongLines_Horizontal(const Mat& binary, Mat& dest,
                                int min_length, int extension){
   
   typedef uchar T;
   
  	dest = Mat::zeros(binary.rows,binary.cols,CV_8UC1);
   
	Size size = binary.size();
	for( int i = 0; i < size.height; i +=1 ){
      
		const T* ptr1 = binary.ptr(i);
		T* ptr2 = dest.ptr(i);	
		
		bool has_previous_baseline = false;
		int previous_baseline_endpoint = 0;
		int current_baseline_startpoint = 0;
      
      
      
      
      for( int j = 1; j < size.width; j += 1 ){			
			
         
         if (ptr1[j] > 0 && ptr1[j-1] == 0){
            current_baseline_startpoint = j;
         }
         
         if (ptr1[j-1] > 0 &&  (ptr1[j] == 0 || j == size.width - 1)){
            
            
				// check for the condition of a baseline hypothesis
				// the length of the baseline must be > 15
				if ((j - current_baseline_startpoint) > min_length){// || j == size.width - 1){
					
               //					int closeness_threshold = 1; 					
               //					if (has_previous_baseline && 
               //                   (current_baseline_startpoint - previous_baseline_endpoint) 
               //						 <= closeness_threshold){
               //						
               //						
               //						// merge the current baseline with the previously baseline
               //						for (int k=previous_baseline_endpoint; 
               //                       k < current_baseline_startpoint; k += 1){
               //	                     ptr2[k] = ptr1[j];
               //						}
               //					}
					
               //	has_previous_baseline = true;
					//previous_baseline_endpoint = j;
					
               
					for (int k=current_baseline_startpoint; k < j; ++k){
                  ptr2[k] = 255;
					}	

               for (int k=j; k < min(j+extension,size.width-1); ++k){
                  ptr2[k] = 255;
					}	
               
					
				}
				
				// forming a new baseline hypothesis
				//current_baseline_startpoint = j+1;
			}
      }
   }	 
} 


Mat
cvgui::obtainGrayBackgroundMask(const Mat& input){
   
   Mat copy = input.clone();
   
   Mat_::iterator it = copy.begin(),
   itEnd = copy.end();
   for(; it != itEnd; ++it){
      
      uchar& b = (*it)[0];
      uchar& g = (*it)[1];
      uchar& r = (*it)[2];
      
      if (r == 0 && b == 0 && g == 0){
         r = 1; b = 1; g = 1;
      }
      
      if (b > 50 &&
          abs(b-g) < 10 && abs(g-b) < 10 && abs(b-r) < 10){
         r = 0;
         g = 0;
         b = 0;
      } 
      
      
      
   }
   
   
   Mat ms[3];
   split(copy, ms);
   
   Mat mask;
   threshold(ms[0],mask,0,255,THRESH_BINARY);
   
   dilate(mask,mask,Mat());	
   
   return mask;
}


Mat
cvgui::removeGrayBackground(const Mat& input){
   
//   Mat copy = input.clone();
//   Mat mask;
//   //  (Size(copy.rows,copy.cols), CV_8UC1);
//   
//   Mat_::iterator it = copy.begin(),
//   itEnd = copy.end();
//   for(; it != itEnd; ++it){
//      
//      uchar& b = (*it)[0];
//      uchar& g = (*it)[1];
//      uchar& r = (*it)[2];
//      
//      if (r == 0 && b == 0 && g == 0){
//         r = 1; b = 1; g = 1;
//      }
//      
//      if (b > 50 &&
//          abs(b-g) < 10 && abs(g-b) < 10 && abs(b-r) < 10){
//         r = 0;
//         g = 0;
//         b = 0;
//      } 
//      
//      
//      
//   }
//   
//   
//   Mat ms[3];
//   split(copy, ms);
//   
//   //threshold(ms[0],mask,0,255,THRESH_BINARY_INV);
//   threshold(ms[0],mask,0,255,THRESH_BINARY);
//   
//   dilate(mask,mask,Mat());	
//   
//   
//   vector > contours;
//   findContours(ms[0], contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
//   
//   Scalar red(0,0,255);
//   //drawContours(copy, contours, -1, red);
//   
//   
//   vector boundingRects;
//   
//   for (vector >::iterator contour = contours.begin();
//        contour != contours.end(); ++contour){
//      
//      
//      double area = contourArea(Mat(*contour));
//      
//      Rect bound = boundingRect(Mat(*contour));
//      
//      
//      if (bound.width * bound.height * 0.5 > area)
//         continue;
//      
//      boundingRects.push_back(bound);
//      
//      rectangle(copy, 
//                Point(bound.x, bound.y),
//                Point(bound.x + bound.width, bound.y + bound.height),
//                red);
//      
//      cout << bound.x << "," <<  bound.y << endl;
//      
//   }
//   
//   
//   
//   Mat result(Size(input.cols,input.rows), CV_8UC3);   
//   for (vector::iterator bound = boundingRects.begin();
//        bound != boundingRects.end(); ++bound){
//      
//      if (bound->width < 10 || bound->height < 8)
//         continue;
//      
//      Mat r(input, *bound);
//      paste(r, result, bound->x, bound->y);
//      
//      
//   }
//   
//   
//   namedWindow("result",1);
//   imshow("result",result);
//   
//   
//   namedWindow("copy",1);
//   imshow("copy",copy);
//   
//   namedWindow("mask",1);
//   imshow("mask",mask);
//   waitKey(0);
   return Mat();
   
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy