4

I am trying to implement openCV method warpPerspective() from scratch, I made the code below, it can handle shifts in y and x but, when I pass homography matrix from findHomography() to the function I made it always gives blank image compared to warpPerspective() output.

I followed this definition to find the new locations of the pixels:

s*x' h1 h2 h3 x s*y' = h4 h5 h6 * y s h7 h8 1 1

my mapping works on simple shift like { 1, 0.5,-51,0,1,50,0,0,1} enter image description here

but when matrix is like: [1.0340946, 0.032195676, -6.419126; 0.00302419, 1.0487343, -96.520393; 3.7013847e-06, 0.00010837225, 1] the output is like this: enter image description here

my implementation: -Given H, and image A, -Find new locations of pixels in A and save them in TransArry.where the index of the array is the linearized index of A. -Remap pixels of A into tranImg.

    Mat transform(Mat A, Mat H)
{
// allocate array of all locations
int Numrows = A.rows;
int Numcols = A.cols;
int channels   = A.channels();
cout << "rows " << Numrows << "col " << Numcols << "channels " << channels <<endl;
int size = Numrows*Numcols;
int MaxX,MaxY = -1000;
int MinX,MinY =  1000;
int *TransArry = (int *)malloc(sizeof(int)*size);
int Idx;

 int homeX=Idx % Numcols;
 int homeY=Idx / Numcols;
 cout << H << endl;

 waitKey();         
for (Idx=0; Idx < size; ++Idx ){

        homeX=Idx % Numcols;
        homeY=Idx / Numcols;

        float x  = (H.at<float>(0,0) * (homeX)) +( H.at<float>(0,1) * (homeY)) + ( H.at<float>(0,2) * 1) ;
        float y  = (H.at<float>(1,0) * (homeX)) +( H.at<float>(1,1) * (homeY)) + ( H.at<float>(1,2) * 1) ;
        float s  = (H.at<float>(2,0) * (homeX)) +( H.at<float>(2,1) * (homeY)) + ( H.at<float>(2,2) * 1) ;

        cout << " x = " << x << " y= " << y << " s= " << s;
        x = (x/s);

        y = y/s;

        // for the first col in TransMatrix
        if (homeX ==0){
            if (x > MaxX) MaxX = x;
            if (x < MinX) MinX = x; 
        }

        //for thee first row in TransMatrix
        if (homeY ==0){
            if (y > MaxY) MaxY = y;
            if (y < MinY) MinY = y;
        }
        if((y)>=A.rows || (y)<0 || (x)>=A.cols || (x)<0){
            TransArry[Idx]  = -1;
            cout << "x= " << x << "y= "<< y << endl;
        }else{
            TransArry[Idx] = (y * Numcols + x); 
        }           

        //cout << Numcols << endl;
        cout <<     "New index of " << Idx << "is " << TransArry[Idx] << endl;
        }

         Mat   tranImg ;

         A.copyTo(tranImg);
         tranImg = tranImg - tranImg;
        cout <<     "Rows" << tranImg.rows << "cols" << tranImg.cols << "cha" <<  A.channels() << endl;


        waitKey();
        // Remap Image
        for (Idx=0; Idx < size; Idx ++ ){

            homeX=Idx % Numcols;
            homeY=Idx / Numcols;                
            //tranImg.at<uchar>(homeY, homeX) =0;
            if(TransArry[Idx] != -1){   
                //cout << "Index " << Idx << "Passed " << endl;
                int newhomeX=TransArry[Idx] % Numcols; // Col ID
                int newhomeY=TransArry[Idx] / Numcols;  // Row ID


                 cout << "Index is " << Idx << endl;
                 cout << "HomeX is " << homeX << " and HomeY is " << homeY << endl;
                 cout << "New Index is " << TransArry[Idx] << endl;
                 cout << "New HomeX is " << newhomeX << " and New HomeY is " << newhomeY << endl;   
                 cout << "*****************************************"<< endl; 
                // if (!(Idx%100)) sleep(20);  

                tranImg.at<uchar>(newhomeY, (newhomeX*channels)) = A.at<uchar>(homeY, homeX*channels);
                if(channels>1)
                    tranImg.at<uchar>(newhomeY, newhomeX*channels+1) = A.at<uchar>(homeY, homeX*channels+1);
                if(channels>2)
                    tranImg.at<uchar>(newhomeY, newhomeX*channels+2) = A.at<uchar>(homeY, homeX*channels+2);
                // if (!(Idx%100)){
                    // imshow("inside", tranImg);
                    // waitKey(1);
                    // }
                }
        }
        //cout << tranImg << endl;  

return tranImg;

}

H is calaculated and verified.

So, is there a problem in the way I access the matrices H and A?

Karam Abo Ghalieh
  • 428
  • 1
  • 5
  • 19

2 Answers2

3

See my answer here and it should answer both of your questions. This answer still uses warpPerspective() but it gives the full insight into how to calculate how far out of the image bounds your homography warps the image, so you can pad appropriately on each side of the image.

As for doing warpPerspective() manually, all you need to do is put all your image coordinates into a linearized homogeneous array and multiply by your homography, and then divide by the last coordinate to get back to Cartesian coordinates. Then, you can use remap() to do the interpolation. The syntax for remap() can be confusing, so you can reference my answer here to get an idea of how to use it. This answer shows a manual transformation and interpolation, it should give you (at least nearly) identical results to warpPerspective().

alkasm
  • 22,094
  • 5
  • 78
  • 94
  • thanks for your detailed answer, I tried a solution but I am not getting the rotated image. should I post my code to another question? since I have problems dealing with matrices elements and trying to convert them to c array. – Karam Abo Ghalieh Nov 30 '17 at 20:42
  • 1
    @KaramAboGhalieh I think it still fits in the scope of this question well, you should just edit your original post and include the code and current problems (but I would suggest not to remove any of your current post). Editing your post will bump it in the questions queue as well, so you may get more responses too. Also do check out my GitHub repo for [padded warps in C++](https://github.com/alkasm/padded-transformations-cpp) which might be helpful. – alkasm Nov 30 '17 at 21:18
  • my implementation works fine for x or y shifting but it cant handle full H matrix – Karam Abo Ghalieh Dec 02 '17 at 20:34
  • @KaramAboGhalieh the indenting is very messed up on the above and the code is very hard to read. If you organize it a bit better it would be easier to spot any issues. Can you give example inputs and your current outputs? What do you mean it "can't handle full H matrix"? – alkasm Dec 03 '17 at 06:44
  • sorry for that, what about now? what I mean by full matrix something like this { 0.97744, -0.014668,1.75,-0.00308,0.96445,91.30,-4.80865,-7.4539,1} ; I am able to handle this { 1, 0.5,-51,0,1,50,0,0,1} matrix for example but not the one before. – Karam Abo Ghalieh Dec 03 '17 at 08:01
0

I found the problem. The co-ordinates you are using are floating point values instead of integers. Typecast x and y to integers and floor the values x = floor(x/s) and y =floor(y/s).