Repository: opencv
Issue: cuda::alphaComp is inaccurate with CV_8UC4 Mat type
Labels: priority: low,category: gpu/cuda (contrib)

<!--
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).

Please:

* Read the documentation to test with the latest developer build.
* Check if other person has already created the same issue to avoid duplicates. You can comment on it if there already is an issue.
* Try to be as detailed as possible in your report.
* Report only one problem per created issue.


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 => 3.4.1
- Operating System / Platform => Ubuntu Linux 16.04.9
- Compiler => g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609

##### Detailed description

Using cuda::alphaComp on 8-bit char-type images (CV_8UC4) produces inaccurate results. On first glance and when used once, this is barely visible, as the RGB value of the pixels is only offset by 1 or 2. However, when repeatedly compositing the same image, it gets darker until reaching a balance at 50% opacity.

This does not happen with images of type CV_32FC4.

##### Steps to reproduce

```.cpp
#include <stdio.h>
    #include <iostream>

    #include <opencv2/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/core/opengl.hpp>

    #include <opencv2/core/cuda.hpp>
    #include <opencv2/cudaimgproc.hpp>
    #include <opencv2/cudaarithm.hpp>

    using namespace std;
    using namespace cv;

    // When using these defines, the resulting green square starts dimming.
    // On first iteration of the loop, its RGB color is 0, 253, 0 instead of 0, 255, 0
    // After running this loop for a while, the color dims to a perfect 0, 128, 0
    #define TYPE_4CH CV_8UC4
    #define TYPE_1CH CV_8UC1
    #define MAX_VAL 255

    // When using these defines, the results are as expected: the green square remains green
    // And the pink square slowly fades in.
    //#define TYPE_4CH CV_32FC4
    //#define TYPE_1CH CV_32FC1
    //#define MAX_VAL 1.0

    int main(int argc, char *argv[])
    {

        namedWindow("test", CV_WINDOW_OPENGL);

        // Drawing a green rectangle with 100% opacity
        Mat frame(1080, 1920, TYPE_4CH, Scalar::all(0));
        rectangle(frame, Rect(10, 10, 400, 400), Scalar(0, MAX_VAL, 0, MAX_VAL), CV_FILLED);

        Mat blank(1080, 1920, TYPE_4CH, Scalar::all(0));
        rectangle(blank, Rect(150, 150, 400, 400), Scalar(MAX_VAL, 0, MAX_VAL, MAX_VAL / 2), CV_FILLED);

        cuda::GpuMat gpuFrame(frame);

        while(true){
            cuda::GpuMat gpuBlank(blank);

            // Alpha-compositing them together numerous times should have the following results
            //   - Visible part of green square remains 100% green (RGB = 0, 255, 0)
            //   - Magenta square starts at opacity 50% and gradually fades in until becoming 100% visible
            //     over part of the green square
            cuda::GpuMat gpuFrameResult;
            cuda::alphaComp(gpuBlank, gpuFrame, gpuFrameResult, cuda::ALPHA_OVER);

            // Splitting the image into 4 mats, to remove any resulting opacity from the image
            vector<cuda::GpuMat> frameChannels;
            cuda::GpuMat finalFrame(1080, 1920, TYPE_4CH, Scalar::all(0));
            cuda::split(gpuFrameResult, frameChannels);

            // A GpuMat with 100% opacity just to discard the eventual resulting
            // alpha chanel in the result of alpha-compositing
            cuda::GpuMat fullAlpha(1080, 1920, TYPE_1CH, Scalar(MAX_VAL));

            if (gpuFrame.channels() > 3) {
                frameChannels.pop_back();
            }
            frameChannels.push_back(fullAlpha);
            cuda::merge(frameChannels, finalFrame);

            finalFrame.copyTo(gpuFrame);

            imshow("test", finalFrame);
            waitKey(1);
        }
    }

```