Repository: opencv
Issue: Refactor file I/O for optimization and Unicode support
Labels: feature,category: core,RFC

### Describe the feature and motivation

Hello everyone,

We recently came accross the following two, related issues.
The first one refers to the image I/O currently implemented inside the `imgcodecs` module. With particular focus on reading files and decoding images - for encoding and writing output files the situation is analogous - the current approach is:
* calling `imread(filename)`
* openining the file / creating the respective `FILE*` pointer.
* start reading the file header to resolve the required decoder by `findDecoder(filename);`
* use the right `ImageDecoder` instance to read the file

This current approach involves that the file is always opened twice as the created file pointer is not passed to the decoder. Instead, the decoders use the filename only and have to re-open the file. This is potentially suboptimal as file access is usually much slower than memory access, which is particularly relevant if you open a lot of images, for example if OpenCV is used in combination with deep learning trainings. However, we did not benchmark these speed differences and they are not our main intention for the following proposal.

Alternatively, OpenCV supports decoding the image from a preloaded buffer by:
* reading the file content into a preloaded `std::vector<string> buffer` independent of OpenCV code
* calling `imdecode(buffer)`
* `imdecode()` resolves the decoder type from the buffer by `findDecoder(buf_row)`
* thereafter, the image is decoded from the buffer without opening the file twice (at least according to our code inspection)

If the decoder does not support reading from a buffer, OpenCV writes the buffer to a temporary file. However, all decoders do support it, with the only exception of the gdcm decoder, as given by the respective `m_buf_supported` value. Still, it supports reading from a stream such that a temporary file is still not necessary, however this is not of main interest here.

Consequently, the multiple file system calls by `imread()` can be optimized away in most cases by reading the file buffer first and, thereafter, passing the buffer to `imdecode()`. Our main intention for proposing this change is to extend OpenCV's file handling abilities. Currently, OpenCV uses `fopen()` to access files. This does a fine job on Linux (presumably the same holds for any Unix), however on Windows, `fopen()` has limited Unicode support. It was discussed before to [extend OpenCV's API on Windows](https://github.com/opencv/opencv/issues/4292#issuecomment-601686965), whereas the current proposal is to extend the API to [support streams](https://github.com/opencv/opencv/issues/15675). However, we think by reading the buffers inside OpenCV using the following function, full Unicode support will be available on Windows, too:

```
std::vector<char> readFile(const std::string& filename)
{
    std::ifstream stream(std::filesystem::u8path(filename).c_str(), ios::binary | ios::ate);
    std::vector<char> buffer;
    if (stream.good())
    {
        std::streamsize size = stream.tellg();
        stream.seekg(0);
        buffer.resize(size);
        stream.read(&buffer[0], size);
    }
    else
    {
        CV_LOG_WARNING(NULL, "readFile('" << filename << "'): can't open/read file: check file path/integrity");
    }
    return buffer;
}

// now refactor imread() to read the file first and use imdecode() thereafter
```

We think that using this approach inside `loadsave.cpp` will be not too complicated and significantly improves the usablity because presumably most UTF-8 Windows-only issues would be already solved while not needing any API changes. Or did we miss anything important here?

Even if the stream API will be implemented in advance, it can easily combined with our proposal by creating the stream first and, thereafter, decode the image directly from the stream instead of the buffer. Besides, this function could be exported to be used wherever file system access is required in other modules, too, either based on streams or buffers, respectively.

What do you think about this proposal?

### Additional context

_No response_