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

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

/*
 * Copyright 2010-2014, Sikuli.org, sikulix.com
 * Released under the MIT License.
 *
 */
#include 
#include 
#include 

#include "finder.h"
#include "pyramid-template-matcher.h"
#include "vision.h"

using namespace cv;
using namespace std;


#ifdef DEBUG_FINDER
#define dout std::cerr
#else
#define dout if(0) std::cerr
#endif

BaseFinder::BaseFinder(Mat _source) : source(_source){
   roi = Rect(0,0,source.cols,source.rows);
}


BaseFinder::BaseFinder(const char* source_image_filename){
   source = imread(source_image_filename,1);
   roi = Rect(0,0,source.cols,source.rows);
}


// somwhow after changing it to false works!!
BaseFinder::BaseFinder(IplImage*  _source) : source(Mat(_source, false)){
   roi = Rect(0,0,source.cols,source.rows);
}

BaseFinder::~BaseFinder(){
}

void 
BaseFinder::setROI(int x, int y, int w, int h){
   roi = Rect(x,y,w,h);
}

void
BaseFinder::find(){
   // create an ROI image to work on
   roiSource.create(roi.size(),source.type());
   Mat(source,roi).copyTo(roiSource);   
}

//=======================================================================================

bool sort_by_score(FindResult m1, FindResult m2){
   return m1.score > m2.score;
}

void TemplateFinder::init(){
   matcher = NULL;
   float min_target_size = sikuli::Vision::getParameter("MinTargetSize");
   PyramidMinTargetDimension = min_target_size>0 ? 
      min_target_size : DEFAULT_PYRAMID_MIM_TARGET_DIMENSION;
}

TemplateFinder::TemplateFinder(Mat _source) : BaseFinder(_source){
   init();
}

TemplateFinder::TemplateFinder(IplImage* _source) : BaseFinder(_source){
   init();
}

TemplateFinder::TemplateFinder(const char* source_image_filename)
: BaseFinder(source_image_filename){
   init();
}

TemplateFinder::~TemplateFinder(){
   if (matcher)
      delete matcher;
}

void 
TemplateFinder::find(const char *target_image_filename, double min_similarity){     
   Mat target = imread(target_image_filename, 1);
   if (target.data == NULL)
      throw cv::Exception();
   find(target, min_similarity);
}   

void 
TemplateFinder::find(IplImage* target, double min_similarity){
   find(Mat(target, false), min_similarity);
}   

void 
TemplateFinder::find_all(const char *target_image_filename, double min_similarity){
   Mat target = imread(target_image_filename, 1);
   if (target.data == NULL)
      throw cv::Exception();

   find_all(target, min_similarity);
}   


void 
TemplateFinder::find_all(IplImage* target, double min_similarity){
   find_all(Mat(target, true), min_similarity);
}   

void
TemplateFinder::find_all(Mat target, double min_similarity){   
   this->min_similarity = min_similarity;
   
   BaseFinder::find();  
   
   if (roiSource.cols < target.cols || roiSource.rows < target.rows){	   
	   current_match.score = -1;
	   return;
   }
   
   float factor = 2.0;      
   int levels=-1;
   int w = target.rows;
   int h = target.cols;
   while (w >= PYRAMID_MIM_TARGET_DIMENSION_ALL && h >= PYRAMID_MIM_TARGET_DIMENSION_ALL){
      w = w / factor;
      h = h / factor;
      levels++;
   }
   
   MatchingData data(roiSource, target);
   
   if (min_similarity < 0.99){
      data.useGray(true);
      create_matcher(data, levels, factor);
      add_matches_to_buffer(5);     
      if (top_score_in_buffer() >= max(min_similarity,REMATCH_THRESHOLD))
         return;
   }
   data.useGray(false);
   dout << "[find_all] matching (original resolution: color) ... " << endl;
   create_matcher(data, 0, 1);
   add_matches_to_buffer(5);
}


float
TemplateFinder::top_score_in_buffer(){
   if (buffered_matches.empty())
      return -1;
   else
      return buffered_matches[0].score;
}

void
TemplateFinder::create_matcher(const MatchingData& data, int level, float ratio){
   if (matcher)
      delete matcher;
   matcher = new PyramidTemplateMatcher(data, level, ratio);
}

void 
TemplateFinder::add_matches_to_buffer(int num_matches_to_add){ 
   buffered_matches.clear();
   for (int i=0;inext();
      buffered_matches.push_back(next_match);
   }
   sort(buffered_matches,sort_by_score);
} 

void
TemplateFinder::find(Mat target, double min_similarity){
   this->min_similarity = min_similarity;   
   BaseFinder::find();  
   
   if (roiSource.cols < target.cols || roiSource.rows < target.rows){	   
      current_match.score = -1;
      return;
   }
   
   float ratio;
   ratio = min(target.rows / PyramidMinTargetDimension, 
               target.cols / PyramidMinTargetDimension);
   if(ratio < 1.f)
      ratio = 1.f;
   
   MatchingData data(roiSource, target);

   if (min_similarity < 0.99)
      data.useGray(true);
   
   const int N_RESIZE_RATIO = 4;
   const float resize_ratio[N_RESIZE_RATIO] = {1.f, 0.75f, 0.5f, 0.25f};
   for(int i=0;i= 1.f){
         dout << "matching (" << new_ratio << ") ... " << endl;
         create_matcher(data, 1, new_ratio);
         add_matches_to_buffer(5);
         if (top_score_in_buffer() >= max(min_similarity,REMATCH_THRESHOLD)){
            return;
         }  
      }
   }
   
   if(data.useGray()){
      dout << "matching (original resolution: gray) ... " << endl;
      create_matcher(data, 0, 1);
      add_matches_to_buffer(5);
      if (top_score_in_buffer() >= max(min_similarity,REMATCH_THRESHOLD))
         return;
   }

   dout << "matching (original resolution: color) ... " << endl;
   create_matcher(data, 0, 1);
   add_matches_to_buffer(5);
}

bool
TemplateFinder::hasNext(){  
   return top_score_in_buffer() >= (min_similarity-0.0000001);
}

FindResult
TemplateFinder::next(){
   
   if (!hasNext())
      return FindResult(0,0,0,0,-1);
   
   FindResult top_match = buffered_matches.front();
   top_match.x += roi.x;
   top_match.y += roi.y;
   
   FindResult next_match = matcher->next();
   buffered_matches[0] = next_match;
   sort(buffered_matches,sort_by_score);
   return top_match;
}

//=========================================================================================
//TODO
//static const char* cascade_name = "haarcascade_frontalface_alt.xml";
//
//CvHaarClassifierCascade* FaceFinder::cascade = 0;
//
//FaceFinder::FaceFinder(const char* screen_image_name)
//: BaseFinder(screen_image_name){
//   
//   //  cascade = 0;
//   storage = 0;
//   if (!cascade){
//      cascade = (CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0);
//   }
//   if (!cascade)
//   {
//      cerr << "can't load the face cascade";
//      return;
//   }
//}
//
//FaceFinder::~FaceFinder(){
//   //cvReleaseImage(&img);
//   if (cascade)
//      cvReleaseHaarClassifierCascade(&cascade);
//   if (storage)
//      cvReleaseMemStorage(&storage);
//}
//
//void 
//FaceFinder::find(){
//   
//   BaseFinder::find();
//   
//   storage = cvCreateMemStorage(0);
//   //faces = cvHaarDetectObjects(roi_img, cascade, storage, 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(40,40));
//   face_i = 0;  
//   
//   // [DEBUG] reset the debug image to the content of the input image
//}
//
//
//bool
//FaceFinder::hasNext(){
//   return faces && face_i < faces->total;
//}
//
//FindResult
//FaceFinder::next(){
//   
//   
//   
//   CvRect* r = (CvRect*)cvGetSeqElem(faces ,face_i);  
//   face_i++;
//   
//   FindResult match;
//   match.x = r->x + roi.x;
//   match.y = r->y + roi.y;
//   match.w = r->width;
//   match.h = r->height;
//   
//   
//   return match;
//}
//
//=====================================================================================
#define PIXEL_DIFF_THRESHOLD 5
#define IMAGE_DIFF_THRESHOLD 5

ChangeFinder::ChangeFinder(const char* screen_image_filename)
: BaseFinder(screen_image_filename){
   is_identical = false;
   storage = 0;
}

ChangeFinder::ChangeFinder(const IplImage* screen_image)
: BaseFinder(screen_image){
   is_identical = false;
   storage = 0;
}


ChangeFinder::ChangeFinder(const Mat screen_image)
: BaseFinder(screen_image){
   is_identical = false;
   storage = 0;
}

ChangeFinder::~ChangeFinder(){
   if (storage)
      cvReleaseMemStorage(&storage);
}


void
ChangeFinder::find(const char* new_screen_image_filename){
   find(imread(new_screen_image_filename,1));
}

void
ChangeFinder::find(IplImage* new_screen_image){
   find(Mat(new_screen_image, false));
}

#include "opencv2/imgproc/imgproc_c.h"
void
ChangeFinder::find(Mat new_screen_image){

   BaseFinder::find(); // set ROI
   
   Mat im1 = roiSource;
   Mat im2 = Mat(new_screen_image,roi);
   
   Mat gray1;
   Mat gray2;

   // convert image from RGB to grayscale
   cvtColor(im1, gray1, CV_RGB2GRAY);
   cvtColor(im2, gray2, CV_RGB2GRAY);
   
   Mat diff1;
   absdiff(gray1,gray2,diff1);
   
   
   Size size = diff1.size();
   int ch = diff1.channels();
   typedef unsigned char T;

   int diff_cnt = 0;
   for( int i = 0; i < size.height; i++ )
    {
        const T* ptr1 = diff1.ptr(i);
        for( int j = 0; j < size.width; j += ch )
        {         
         if (ptr1[j] > PIXEL_DIFF_THRESHOLD)
            diff_cnt++;
        }
    }
   
   // quickly check if two images are nearly identical
   if (diff_cnt < IMAGE_DIFF_THRESHOLD){
      is_identical = true;
      return;
   }   
   
   
   threshold(diff1,diff1,PIXEL_DIFF_THRESHOLD,255,CV_THRESH_BINARY);
   dilate(diff1,diff1,Mat());

   // close operation
   Mat se = getStructuringElement(MORPH_ELLIPSE, Size(5,5));
   morphologyEx(diff1, diff1, MORPH_CLOSE, se);
   
/*   
   namedWindow("matches", CV_WINDOW_AUTOSIZE);
    imshow("matches", diff1);
   waitKey();   
*/
   
   vector< vector > contours; 
   vector< Vec4i> hierarchy;
   //findContours(diff1, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point());
   
   storage = cvCreateMemStorage();
   CvSeq* first_contour = NULL;
   
   CvMat mat = (CvMat) diff1;
   
   cvFindContours(
                     &mat,
                     storage,
                     &first_contour,
                     sizeof(CvContour),
                     CV_RETR_EXTERNAL);
   
   c = first_contour;
}

bool      
ChangeFinder::hasNext(){
   return !is_identical  && c !=NULL;
}

FindResult
ChangeFinder::next(){ 
   
   // find bounding boxes
    int x1=source.cols;
    int x2=0;
    int y1=source.rows;
    int y2=0;
   
    for( int i=0; i < c->total; ++i ){
      CvPoint* p = CV_GET_SEQ_ELEM( CvPoint, c, i );
      if (p->x > x2)
         x2 = p->x;
      if (p->x < x1)
         x1 = p->x;
      if (p->y > y2)
         y2 = p->y;
      if (p->y < y1)
         y1 = p->y;         
    }
   
    FindResult m;
    m.x = x1 + roi.x;
    m.y = y1 + roi.y;
    m.w = x2 - x1 + 1;
    m.h = y2 - y1 + 1;
   
    c = c->h_next;
   return m;
}



//=====================================================================================
#include "tessocr.h"

TextFinder::TextFinder(Mat inputImage)
: BaseFinder(inputImage){
};

void
TextFinder::train(Mat& trainingImage){	
//	train_by_image(trainingImage);
}


// Code copied from 
// http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
static void Tokenize(const string& str,
              vector& tokens,
              const string& delimiters = " ")
{
   // Skip delimiters at beginning.
   string::size_type lastPos = str.find_first_not_of(delimiters, 0);
   // Find first "non-delimiter".
   string::size_type pos     = str.find_first_of(delimiters, lastPos);
   
   while (string::npos != pos || string::npos != lastPos)
   {
      // Found a token, add it to the vector.
      tokens.push_back(str.substr(lastPos, pos - lastPos));
      // Skip delimiters.  Note the "not_of"
      lastPos = str.find_first_not_of(delimiters, pos);
      // Find next "non-delimiter"
      pos = str.find_first_of(delimiters, lastPos);
    }
}


void
TextFinder::find(const char* text, double _min_similarity){
   vector words;
   Tokenize(text, words, " ");
   return find(words, _min_similarity);
}

void
TextFinder::find_all(const char* text, double _min_similarity){
   vector words;
   Tokenize(text, words, " ");
   return find_all(words, _min_similarity);
}


void
TextFinder::find(vector words, double _min_similarity){
   this->min_similarity = _min_similarity;
   BaseFinder::find();
	matches = OCR::find_phrase(roiSource, words);
   matches_iterator = matches.begin();   
}

void
TextFinder::find_all(vector words, double _min_similarity){
   this->min_similarity = _min_similarity;
   BaseFinder::find();
	matches = OCR::find_phrase(roiSource, words, false);
   matches_iterator = matches.begin();   
}


bool      
TextFinder::hasNext(){
   
//   dout << "[TextFinder] " << matches_iterator->score  << endl;
   return (matches_iterator != matches.end()) &&
   (matches_iterator->score >= min_similarity);
}

FindResult
TextFinder::next(){ 
   
   FindResult ret;
   if (hasNext()){
      ret = *matches_iterator;
      ++matches_iterator;
      return ret;
   }else {
      return FindResult(0,0,0,0,-1);
   }

}
   

vector
TextFinder::recognize(const Mat& inputImage){	
	return vector();//recognize_words(inputImage);
}


//=====================================================================================
Finder::Finder(Mat source)
: _source(source){
   _finder = NULL;
   _roi = Rect(-1,-1,-1,-1);
}

Finder::Finder(IplImage* source)
: _source(Mat(source)){
   _finder = NULL;
   _roi = Rect(-1,-1,-1,-1);
}

Finder::Finder(const char* source){
   _source = imread(source,1);
   _finder = NULL;
   _roi = Rect(-1,-1,-1,-1);
}

Finder::~Finder(){
   if (_finder)
      delete _finder;
}

void 
Finder::find(IplImage* target, double min_similarity){
   dout << "[Finder::find]" << endl;
   
   
   if (abs(min_similarity - 100)< 0.00001){
      dout << "training.." << endl;
      Mat im(target);
      TextFinder::train(im);
      
   }else{
   
      TemplateFinder* tf = new TemplateFinder(_source);
      if(_roi.width>0) tf->setROI(_roi.x, _roi.y, _roi.width, _roi.height);
      tf->find(target, min_similarity);
      if(_finder) delete _finder;
      _finder = tf;
      
   }
}

void 
Finder::find(const char *target, double min_similarity){
   dout << "[Finder::find]" << endl;

   const char* p = target;
   const char* ext = p + strlen(p) - 3;
   
   if (abs(min_similarity - 100)< 0.00001){
      
      Mat im = imread(target,1);
      TextFinder::train(im);
      
   }else if (strncmp(ext,"png",3) != 0){
      TextFinder* wf = new TextFinder(_source);
      if(_roi.width>0) wf->setROI(_roi.x, _roi.y, _roi.width, _roi.height);
      
         // get name after bundle path, which is
         // assumed to be the query word
      int j;
      for (j = (strlen(p)-1); j >=0; j--){      
         if (p[j]=='/')
         break;
      }
     
      const char* q = p + j + 1;
         
      wf->find(q,0.6);
      if(_finder) delete _finder;
      _finder = wf;
      
   }else {
      
      TemplateFinder* tf = new TemplateFinder(_source);
      if(_roi.width>0) tf->setROI(_roi.x, _roi.y, _roi.width, _roi.height);
      tf->find(target, min_similarity);
      if(_finder) delete _finder;
      _finder = tf;
   }                    
}

void 
Finder::find_all(IplImage*  target, double min_similarity){
   TemplateFinder* tf  = new TemplateFinder(_source);
   if(_roi.width>0) tf->setROI(_roi.x, _roi.y, _roi.width, _roi.height);
   tf->find_all(target, min_similarity);
   if(_finder) delete _finder;
   _finder = tf;
}

void 
Finder::find_all(const char *target, double min_similarity){
   
   const char* p = target;
   const char* ext = p + strlen(p) - 3;
   
   if (strncmp(ext,"png",3) != 0){
      TextFinder* wf = new TextFinder(_source);
      if(_roi.width>0) wf->setROI(_roi.x, _roi.y, _roi.width, _roi.height);
      
      // get name after bundle path, which is
      // assumed to be the query word
      int j;
      for (j = (strlen(p)-1); j >=0; j--){      
         if (p[j]=='/')
            break;
      }
      
      const char* q = p + j + 1;
      
      wf->find(q,0.6);
      if(_finder) delete _finder;
      _finder = wf;
   }else {
      
      TemplateFinder* tf = new TemplateFinder(_source);
      if(_roi.width>0) tf->setROI(_roi.x, _roi.y, _roi.width, _roi.height);
      tf->find_all(target, min_similarity);
      if(_finder) delete _finder;
      _finder = tf;
   }     
}

bool 
Finder::hasNext(){
   return _finder->hasNext();
}

FindResult 
Finder::next(){
   return _finder->next();
}


void Finder::setROI(int x, int y, int w, int h){
   _roi = Rect(x, y, w, h);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy