PhonoDots
PhonoDots

Reputation: 149

OpenCV/C - Improve the speed of a time consuming loop?

I've recently implemented an image warping method using OpenCV 2.31(C++). However, this method is quite time consuming... After some investigations and improvement I succeed to reduce the processing time from 400ms to about 120ms which is quite nice. I achieve this result by unrolling the loop (It reduces the time from 400ms to 330ms) then I enabled optimization flags on my VC++ compiler 2008 express edition (Enabled O2 flag) - this last fix improved the processing to around 120ms.

However, since I have some other processing to implement around this warp, I'd like to reduce down this processing time even more to 20ms - lower than this value will be better of course, but I don't know if it's possible!!!...

One more thing, I'd like to do this using freely available libraries. All suggestions are more than welcomed.

Bellow, you'll find the method I'm speaking about.

thanks for your help

Ariel B.

cv::Mat Warp::pieceWiseWarp(const cv::Mat &Isource, const cv::Mat &s, TYPE_CONVERSION type)
{       
cv::Mat Idest(roi.height,roi.width,Isource.type(),cv::Scalar::all(0));
float xi, xj, xk, yi, yj, yk, x, y;
float X2X1,Y2Y1,X2X,Y2Y,XX1,YY1,X2X1_Y2Y1,a1, a2, a3, a4,b1,b2,c1,c2;
int x1, y1, x2, y2;
char k;     
int nc = roi.width;
int nr = roi.height;
int channels = Isource.channels();
int N = nr * nc;


float *alphaPtr = alpha.ptr<float>(0);
float *betaPtr = beta.ptr<float>(0);
char *triMaskPtr = triMask.ptr<char>(0);
uchar *IdestPtr = Idest.data;


for(int i = 0; i < N;  i++, IdestPtr += channels - 1)       
        if((k = triMaskPtr[i]) != -1)// the pixel do belong to delaunay
        {

            cv::Vec3b t = trianglesMap.row(k);

            xi = s.col(1).at<float>(t[0]); yi = s.col(0).at<float>(t[0]); 
            xj = s.col(1).at<float>(t[1]); yj = s.col(0).at<float>(t[1]); 
            xk = s.col(1).at<float>(t[2]); yk = s.col(0).at<float>(t[2]);                       

            x = xi + alphaPtr[i]*(xj - xi) + betaPtr[i]*(xk - xi);
            y = yi + alphaPtr[i]*(yj - yi) + betaPtr[i]*(yk - yi);


            //...some bounds checking here...

            x2 = ceil(x); x1 = floor(x);
            y2 = ceil(y); y1 = floor(y);                

            //2. use bilinear interpolation on the pixel location - see wiki for formula...
            //...3. copy the resulting intensity (GL) to the destination (i,j)

            X2X1 = (x2 - x1);
            Y2Y1 = (y2 - y1);
            X2X  = (x2 - x);
            Y2Y  = (y2 - y);
            XX1  = (x - x1);                
            YY1  = (y - y1);

            X2X1_Y2Y1 = X2X1*Y2Y1;
            a1 = (X2X*Y2Y)/(X2X1_Y2Y1);
            a2 = (XX1*Y2Y)/(X2X1_Y2Y1);
            a3 = (X2X*YY1)/(X2X1_Y2Y1);
            a4 = (XX1*YY1)/(X2X1_Y2Y1);

            b1 = (X2X/X2X1);
            b2 = (XX1/X2X1);

            c1 = (Y2Y/Y2Y1);
            c2 = (YY1/Y2Y1);

            for(int c = 0; c < channels; c++)// Consider implementing this bilinear interpolation elsewhere in another function 
            {
                if(x1 != x2 && y1 != y2)
                    IdestPtr[i + c] = Isource.at<cv::Vec3b>(y1,x1)[c]*a1
                                                + Isource.at<cv::Vec3b>(y2,x1)[c]*a2
                                                + Isource.at<cv::Vec3b>(y1,x2)[c]*a3
                                                + Isource.at<cv::Vec3b>(y2,x2)[c]*a4;                       
                if(x1 == x2 && y1 == y2)
                    IdestPtr[i + c] = Isource.at<cv::Vec3b>(y1,x1)[c];

                if(x1 != x2 && y1 == y2)
                    IdestPtr[i + c] = Isource.at<cv::Vec3b>(y1,x1)[c]*b1 + Isource.at<cv::Vec3b>(y1,x2)[c]*b2;

                if(x1 == x2 && y1 != y2)
                    IdestPtr[i + c] = Isource.at<cv::Vec3b>(y1,x1)[c]*c1 + Isource.at<cv::Vec3b>(y2,x1)[c]*c2;                      
            }                       
        }

if(type == CONVERT_TO_CV_32FC3)
    Idest.convertTo(Idest,CV_32FC3);
if(type == NORMALIZE_TO_1)
    Idest.convertTo(Idest,CV_32FC3,1/255.);
return Idest;
}

Upvotes: 2

Views: 1338

Answers (1)

luhb
luhb

Reputation: 666

I would suggest:

1.Change division by a common factor to multiplication. i.e. from a = a1/d; b = b1/d to d_1 = 1/d; a = a1*d_1; b = b1*d_1

2.Eliminate the four if test to a single bilinear interpolation.

I'm not sure whether that would help you. You could have a try.

Upvotes: 1

Related Questions