How to reduce the execution time for the following code?

580 views Asked by At

I tried to give some sketch effects to an image for that i used Gaussian modeling technique in opencv, but i face an issue that it takes more time for execution. Time is reduced when the size of the picture is small if the size is large it takes more time. Please any one tell how to reduce the time for execution without changing the actual size of an image for the following code

#include "opencv2/opencv.hpp"
#include <iostream>
#include <vector>
#include "opencv2/ml/ml.hpp"
#include <list>
#include <iostream>
using namespace cv;
using namespace std;

void clustrize_colors(Mat& src,Mat& dst)
{
 // Number of clusters
 int NrGMMComponents = 96;

 cv::GaussianBlur(src,src,Size(3,3),1);

 int srcHeight = src.rows;
 int srcWidth  = src.cols;

 // Get datapoints
 vector<Vec3d> ListSamplePoints;

 for (int y=0; y<srcHeight; y++)
 {
  for (int x=0; x<srcWidth; x++)
  {
   // Collecting points from image
   Vec3b bgrPixel = src.at<Vec3b>(y, x);

   uchar b = bgrPixel.val[0];
   uchar g = bgrPixel.val[1];
   uchar r = bgrPixel.val[2];
   if(rand()%25==0) // peek every 25-th
   {
    ListSamplePoints.push_back(Vec3d(b,g,r));
   }
  } // for (x)
 } // for (y)


 // Form training matrix
 int NrSamples = ListSamplePoints.size();    
 Mat samples( NrSamples, 3, CV_64FC1 );

 for (int s=0; s<NrSamples; s++)
 {
  Vec3d v = ListSamplePoints.at(s);
  samples.at<double>(s,0) = (float) v[0];
  samples.at<double>(s,1) = (float) v[1];
  samples.at<double>(s,2) = (float) v[2];
 }    
 // 
 cout << "Learning to represent the sample distributions with " << NrGMMComponents << " gaussians." << endl;
 cout << "Started GMM training" << endl;

 Ptr<cv::ml::EM> em_model;
 cv::ml::EM::Params params(NrGMMComponents,cv::ml::EM::COV_MAT_GENERIC);

 Mat labels(NrSamples,1,CV_32SC1);
 Mat logLikelihoods( NrSamples, 1, CV_64FC1 );

 // Train classifier
 em_model=cv::ml::EM::train(samples,logLikelihoods,labels,noArray(),params);
 cout << "Finished GMM training" << endl;

 // result image
 Mat img  = Mat::zeros( Size( srcWidth, srcHeight ), CV_8UC3 );

 // predict cluster
 Mat sample( 1, 3, CV_64FC1 );

 Mat means=em_model->getMeans();

 for(int i = 0; i < img.rows; i++ )
 {
  for(int j = 0; j < img.cols; j++ )
  {
   Vec3b v=src.at<Vec3b>(i,j);
   sample.at<double>(0,0) = (float) v[0];
   sample.at<double>(0,1) = (float) v[1];
   sample.at<double>(0,2) = (float) v[2];
   int response = cvRound(em_model->predict( sample ));
   img.at<Vec3b>(i,j)[0]=means.at<double>(response,0);
   img.at<Vec3b>(i,j)[1]=means.at<double>(response,1);
   img.at<Vec3b>(i,j)[2]=means.at<double>(response,2);
  }
 }

 img.convertTo(img,CV_8UC3);
        namedWindow("result",WINDOW_AUTOSIZE);
 imshow("result",img);
        imwrite("D:\\nfr.jpg",img);
 waitKey();
 dst=img;
}

void processLayer(Mat& src,Mat& dst)
{
 Mat tmp=src.clone();
 Mat gx,gy,mag,blurred;
 Sobel( src, gx, -1, 1, 0, 3);
 Sobel( src, gy, -1, 0, 1, 3);
 magnitude(gx,gy,mag);
 //GaussianBlur(mag,blurred,Size(3,3),2);
 //mag+=blurred;
 normalize(mag,mag,0,1,cv::NORM_MINMAX);
 //sqrt(mag,dst);
 dst=mag.clone();
 normalize(dst,dst,0,1,cv::NORM_MINMAX);
}

int main(int ac, char** av)
{
 Mat clusterized;
 Mat frame=imread("image path"); ////load an image//////
        //resize(frame,frame,Size(256,256),0,0,INTER_LINEAR);
 clustrize_colors(frame,clusterized);
 clusterized.convertTo(clusterized,CV_32FC3,1.0/255.0);
 frame.convertTo(frame,CV_32FC3,1.0/255.0);
 Mat result1;
 vector<Mat> ch;
 split(frame, ch);

 processLayer(ch[0],ch[0]);
 processLayer(ch[1],ch[1]);
 processLayer(ch[2],ch[2]);

 merge(ch,result1);

 result1=(0.5*frame-0.9*result1+0.3*clusterized)*2.0;
        namedWindow("result1",WINDOW_AUTOSIZE);
 imshow("result1",result1);
        //cout<<result1;
        imwrite("D:\\finalresult.jpg",result1);
 waitKey(0);
 //destroyAllWindows();
 return 0;
}

1

There are 1 answers

0
Boyko Perfanov On

In all likelihood the bottleneck is opencv's cv::ml::EM::train method. Training a classifier is not an easy or simple task. The classification problem has not been solved conclusively. That's why there are large tradeoffs and differences in between algorithms, let alone across different problem spaces.

As for performance, if you insist on using EM, check the EM class documentation and possibly its parent classes to modify:

  • Max number of iterations for training and/or
  • Term criteria to stop training.

Due to using a third-party library, there is not much you can do that will increase speed but not sacrifice accuracy. On the other hand, the library is open-source, and it is likely reasonably well optimized. I don't recommend trying to optimize the actual library code.