Repository: opencv
Issue: Add [minimal] type information to the images created using the Python wrapper of opencv
Labels: category: python bindings,RFC


##### System information (version)
<!-- Example
- OpenCV => 3.1
- Operating System / Platform => Windows 64 Bit
- Compiler => Visual Studio 2015
-->

- OpenCV => 4.1.2
- Operating System / Platform => Windows 10 / Python wrapper
- Compiler => not used, but have available VS2017/ VS2019

##### Detailed description

This issue is actually about the Python wrapper, and I couldnt find the pythons specific repo, so I'm here. the issue is non-existant on languages such as C/C++ and is only relevant in Python. 
In Python wrapper, when you create an image, e.g. with imread, there is no way, you can distiguish it between other image types, such as the one, created using Matplotlibs `imread`. They all represent the resulting image, simply as a numpy ndarray.   
We can distinguish between these two methods, by quering the `base` and `flags` attributes. However, when the objects are deepcopied this distinction goes away and there would be no way of knowing which object comes from opencv backend and which comes from other sources. 
```python

In [48]: img_cv.flags
Out[48]:
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False

In [49]: img_mtplotlib.flags
Out[49]:
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : False
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False

In [50]: img_skimage.flags
Out[50]:
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False
```
After deepcopy : 
```python
cv2:  
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False 
matplotlib after deepcopy:  
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False 
skimage after deefpcopy:    
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False 

```
This is specially the case, since opencv works with BGR instead of RGB and there is no way to know if channels are swapped without any metadata. 
Exposing the resulting image as a well structured data-structure that can provide other meta-data concerning it would be very helpful on python like the way `skimage` does it, it has a meta attribute which can be used among others, to distinguish it between other types.   

Solution : 
--
One simple solution could be to implement the opencv image as a specific type that inherits from numpy.ndarray. sth like :
Minimal Solution : 
 
```python 
class OpenCVImage(np.ndarray):
    pass
# instead of returning the ndarray wrap it using the OpenCVImage. 
return np.array(img).view(OpenCVImage)
```
This will behave like before and this time it can be easily identified. you may also add other meta-data if needed. 

### Steps to reproduce
- operating system Win10
- architecture x86
- opencv-python  4.1.2


```python
import cv2
from skimage import io
from PIL import Image 
import matplotlib.pyplot as plt 
import copy

img_path = 'test.jpg'

c = cv2.imread(img_path)
s = io.imread(img_path)
m = plt.imread(img_path)

print(f'opencv obj: {type(c)} {type(c).__name__}')
print(f'skimage obj: {type(s)} {type(s).__name__}')
print(f'matplotlibs obj: {type(m)} {type(m).__name__}')

print(f'CV2:  \n{c.flags} ')
print(f'\nMatplotlib:\n{m.flags} ')
print(f'\nSkimage:    \n{s.flags} ')

c_2 = copy.deepcopy(c)
s_2 = copy.deepcopy(s)
m_2 = copy.deepcopy(m)

print('\nAfter DeepCopy\n')

print(f'CV2:  \n{c_2.flags} ')
print(f'\nMatplotlib:  \n{m_2.flags} ')
print(f'\nSkimage:    \n{s_2.flags} ')
```