Repository: opencv
Issue: Inconsistency in Mat::release behavior can lead to different outcomes under Debug and Release modes elsewhere.
Labels: category: core,RFC

##### System information (version)
- OpenCV => 4.1.2
- Operating System / Platform => Windows 10
- Compiler => Visual Studio 2019

##### Detailed description
Inconsistency in `Mat::release` behavior can lead to different outcomes under Debug and Release modes elsewhere.

I believe there might be more configurations where this can manifest, but in my code, I was calling the pair of `findNonZero` followed by `boundingRect` few times, reusing the index matrix, and I observed different behavior in Debug and Release modes - Debug passed while Release threw an exception.

The reason turned out to be that [`boundingRect`](https://github.com/opencv/opencv/blob/master/modules/imgproc/src/shapedescr.cpp#L1142) code paths differ based on the type of the input matrix, and only the second one asserts that the input must not be empty.

A call to `findNonZero` that doesn't find any non-zero locations releases the `idx` matrix. In case of a Debug mode, this not only deallocates the memory and clears the size info, but also changes the data type:
```cpp
inline
void Mat::release()
{
    if( u && CV_XADD(&u->refcount, -1) == 1 )
        deallocate();
    u = NULL;
    datastart = dataend = datalimit = data = 0;
    for(int i = 0; i < dims; i++)
        size.p[i] = 0;
#ifdef _DEBUG
    flags = MAGIC_VAL; // This effectively changes the type to CV_8UC1.
    dims = rows = cols = 0;
    if(step.p != step.buf)
    {
        fastFree(step.p);
        step.p = step.buf;
        size.p = &rows;
    }
#endif
}
```

Then, in [`pointSetBoundingRect`](https://github.com/opencv/opencv/blob/master/modules/imgproc/src/shapedescr.cpp#L872) `int npoints = points.checkVector(2);` evaluates as `-1`, because the `data` member is `NULL`.

I guess the easiest way to fix this would be to just make `boundingRect` return an empty rectangle, if the input matrix is empty.

Or at least if its of the correct type, but empty (since there's the `if( npoints == 0 )` condition which I believe can never be hit):
```cpp
// This code always throws, regardless the build mode.
cv::Mat empty(0, 0, CV_32SC2);
cv::boundingRect(empty);
```

Or, if this is intended behavior, it should probably be mentioned in the documentation.

##### Steps to reproduce
```cpp
const cv::Mat ones  = cv::Mat::ones (2, 3, CV_32F); // Any type or non-empty size, really.
const cv::Mat zeros = cv::Mat::zeros(2, 3, CV_32F); // ...

cv::Mat idx;

// After this call, the type of `idx` will be `CV_32SC2`.
cv::findNonZero(ones, idx);
const int first = idx.type();

// After this call, the type of `idx` will either be:
// - `CV_8UC1` if `_DEBUG` is defined.
// - `CV_32SC2` otherwise.
cv::findNonZero(zeros, idx);
const int second = idx.type();

// Result will differ whether `_DEBUG` is defined or not.
printf("idx types match: %s\n", first == second ? "YES\n" : "NO\n");

const cv::Rect throwsInReleaseMode = cv::boundingRect(idx);
```

##### Issue submission checklist
 - [x] I report the issue, it's not a question.
 - [x] I checked the problem with documentation, FAQ, open issues, forum.opencv.org, Stack Overflow, etc and have not found solution.
 - [ ] I updated to latest OpenCV version and the issue is still there.
 - [x] There is reproducer code.