Repository: opencv
Issue: CUDA ORB ROI boundary conditions should be modefied in "void ORB_Impl::detectAndComputeAsync"
Labels: priority: low,category: gpu/cuda (contrib)

##### System information (version)
- OpenCV => 3.3:
- Operating System / Platform => Ubuntu16.04 Linux 4.10.0-42-generic x86_64
- Compiler => codeblocks 13.12

##### Detailed description

In CUDA ORB, if the size of the picture input is too small, detectAndComputeAsync will report 
> OpenCV Error: Assertion failed (0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows) in GpuMat.

While in CPU ORB, the same picture will not cause the same problem when `ORB::create()` choose the same value.

After reading the sources code in /opencv-3.3.1/modules/cudafeatures2d/src/orb.cpp and comparing it with CPU ORB in /opencv-3.3.1/modules/features2d/src/orb.cpp, I find that obtaining method of ROI in CUDA ORB causes the error:
In `void ORB_Impl::buildScalePyramids(InputArray _image, InputArray _mask, Stream& stream)`, it goes like this:
`float scale = 1.0f / getScale(scaleFactor_, firstLevel_, level);
Size sz(cvRound(image.cols * scale), cvRound(image.rows * scale));`
`Rect inner(edgeThreshold_, edgeThreshold_, sz.width - 2 * edgeThreshold_, sz.height - 2 * edgeThreshold_);`
It means that if `nLevels` and `edgeThreshold` in `cv::cuda::ORB::create()` are high enough, it will make `inner` out of the GpuMat and cause the problem. Even default values `nLevels=8` and `edgeThreshold = 31` will crash when I choose a [170*209] image.

However, in CPU ORB method, `void ORB_Impl::detectAndCompute( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints, OutputArray _descriptors, bool useProvidedKeypoints )` gives another ROI choosing method:
```
for( level = 0; level < nLevels; level++ )
    {
        float scale = getScale(level, firstLevel, scaleFactor);
        layerScale[level] = scale;
        Size sz(cvRound(image.cols/scale), cvRound(image.rows/scale));
        Size wholeSize(sz.width + border*2, sz.height + border*2);
        if( level_ofs.x + wholeSize.width > bufSize.width )
        {
            level_ofs = Point(0, level_ofs.y + level_dy);
            level_dy = wholeSize.height;
        }

        Rect linfo(level_ofs.x + border, level_ofs.y + border, sz.width, sz.height);
        layerInfo[level] = linfo;
        layerOfs[level] = linfo.y*bufSize.width + linfo.x;
        level_ofs.x += wholeSize.width;
    }
```

Inside, `Rect linfo(level_ofs.x + border, level_ofs.y + border, sz.width, sz.height);` can avoid the problem properly.
Maybe ORB in CPU is updated frequently while CUDA ORB is ignored, for there are few information about CUDA ORB can be found in Internet and ORB is the solution submitted for CPU opertion. But the problem can be solved soon. Thanks!

##### Steps to reproduce

[orb_gpu_tidyup.txt](https://github.com/opencv/opencv/files/1621838/orb_gpu_tidyup.txt)
![orb_test](https://user-images.githubusercontent.com/31119574/34816344-a1fe6b1a-f6ef-11e7-81b8-99e34659a49a.jpg)
![timg4](https://user-images.githubusercontent.com/31119574/34816345-a2425ff0-f6ef-11e7-910c-1c15eee9643a.jpg)
When `Ptr<cuda::ORB> d_orb = cuda::ORB::create(500, 1.2f, 6, 31, 0, 2, 0, 31, 20,true);` is changed to `Ptr<cuda::ORB> d_orb = cuda::ORB::create(500, 1.2f, 8, 31, 0, 2, 0, 31, 20,true);`, the error will happen.