Repository: opencv
Issue: stereoRectify returns too narrow FoV
Labels: bug,category: calib3d,affected: 2.4,affected: 3.4

<!--
If you have a question rather than reporting a bug please go to http://answers.opencv.org where you get much faster responses.
If you need further assistance please read [How To Contribute](https://github.com/opencv/opencv/wiki/How_to_contribute).

This is a template helping you to create an issue which can be processed as quickly as possible. This is the bug reporting section for the OpenCV library.
-->
##### System information (version)
- OpenCV => 2.4.8 or 3.1
- Operating System / Platform =>  Ubuntu14.04
- Compiler => gcc 4.8.4
##### Detailed description

Using cv::stereoRectify, we can compute rectification transforms. Setting argument alpha = 0 (or -1), We obtain projection matrix which create rectified image so that only valid pixels are visible.
However, there are too much loss of angle of view.
##### Steps to reproduce

``` .cpp
#include "opencv2/opencv.hpp"

using namespace cv;

int main(int argc, char** argv)
{
    // read images
    Mat img1 = imread("left000000.png, 1");
    Mat img2 = imread("right000000.png, 1");

    // get parameters.
    Mat cameraMatrix1 = (Mat_<double>(3,3) << 297.4089814269344, 0, 320.5522625552759,
                        0, 297.4237628565247, 216.5714813003074,
                        0, 0, 1);
    Mat distCoeffs1 = (Mat_<double>(8,1) << 0.2748830280780161,
                        -0.01621485704756092,
                        -0.0001422338901898611,
                        -5.464830883313612e-05,
                        0.0007905921035454578,
                        0.6293739571366611,
                        0,
                        0);
    Mat cameraMatrix2 = (Mat_<double>(3,3) << 299.9196394373507, 0, 317.3610118656668,
                        0, 299.8188459158802, 218.7071016329061,
                        0, 0, 1);
    Mat distCoeffs2 = (Mat_<double>(8,1) << 0.2764273821263449,
                        -0.01606351441652921,
                        -0.0001328981789739428,
                        3.984181363726657e-05,
                        0.0007352344185123152,
                        0.6319438272394248,
                        0,
                        0);
    Mat R = (Mat_<double>(3,3) << 0.999986734411586, -0.001027538742322914, -0.005047292837277665,
                            0.001012708281235076, 0.9999951654653096, -0.002939977541586314,
                            0.005050289376790885, 0.002934827105800179, 0.9999829405380223);
    Mat T = (Mat_<double>(3,1) << -0.08175826598351721,
                            -0.001466183753848256,
                            0.001439342993774405);
    Size imageSize = Size(640, 480);
    Mat R1, R2, P1, P2, Q;
    Rect validRoi1, validRoi2;

    // rectify
    double alpha = 0;
    stereoRectify(cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, imageSize,
                      R, T, R1, R2, P1, P2, Q,
                      CALIB_ZERO_DISPARITY, alpha, imageSize, &validRoi1, &validRoi2);

    // remap
    Mat rmap[2][2];
    initUndistortRectifyMap(cameraMatrix1, distCoeffs1, R1, P1, imageSize, CV_16SC2, rmap[0][0], rmap[0][1]);
    initUndistortRectifyMap(cameraMatrix2, distCoeffs2, R2, P2, imageSize, CV_16SC2, rmap[1][0], rmap[1][1]);
    Mat out1, out2;
    remap(img1, out1, rmap[0][0], rmap[0][1], CV_INTER_LINEAR);
    remap(img2, out2, rmap[1][0], rmap[1][1], CV_INTER_LINEAR);
    Mat result;
    hconcat(out1, out2, result);

    // draw horizontal line
    for(int j = 0; j < result.rows; j += 16 ) {
        line(result, Point(0, j), Point(result.cols, j), Scalar(0, 255, 0), 1, 8);
    }

    // show
    imshow("result", result);
    waitKey();

    return 0;
}

```

input image1
![left000000](https://cloud.githubusercontent.com/assets/21995016/18240473/0585f6d2-7387-11e6-8850-6c46bdc7bbe5.png)

input image2
![right000000](https://cloud.githubusercontent.com/assets/21995016/18240478/0d95f76e-7387-11e6-99fd-0e26cad2b3de.png)

result image
![alpha0_000000](https://cloud.githubusercontent.com/assets/21995016/18240485/18ff1a54-7387-11e6-9bcc-fd6980aa94f9.png)
##### Workaround

If you replace rectify part with following code, you can decrease loss of angle of view with stereo rectification.
Setting argument alpha = 1, we get projection matrix and rectangles inside the rectified images where all the pixels are valid. We recompute projection matrix so that rectified image have only valid pixels.

``` .cpp
    // rectify
    double alpha = 1;
    stereoRectify(cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, imageSize,
                      R, T, R1, R2, P1, P2, Q,
                      CALIB_ZERO_DISPARITY, alpha, imageSize, &validRoi1, &validRoi2);
    Rect commonRoi = validRoi1 & validRoi2;
    // to retain aspect ratio
    Rect_<double> aspectRoi;
    if(commonRoi.width > commonRoi.height*4.0/3.0){
        aspectRoi.x = commonRoi.x + (commonRoi.width-commonRoi.height*4.0/3.0)/2.0;
        aspectRoi.y = commonRoi.y;
        aspectRoi.width = commonRoi.height*4.0/3.0;
        aspectRoi.height = commonRoi.height;
    }
    else{
        aspectRoi.x = commonRoi.x;
        aspectRoi.y = commonRoi.y + (commonRoi.height-commonRoi.width*3.0/4.0)/2.0;
        aspectRoi.width = commonRoi.width;
        aspectRoi.height = commonRoi.width*3.0/4.0;
    }
    // create cropping matrix
    double u = double(imageSize.width)/double(aspectRoi.width); 
    double v = double(imageSize.height)/double(aspectRoi.height);
    Mat M = (Mat_<double>(3,3) << u, 0, -double(aspectRoi.x)*u,
                                0, v, -double(aspectRoi.y)*v,
                                0, 0, 1); 
    P1 = M * P1;
    P2 = M * P2;
```

modified result image
![result000000](https://cloud.githubusercontent.com/assets/21995016/18240491/22da33e2-7387-11e6-84d2-2eee58c477c0.png)