Comment définir canal donné d'un cv::Mat pour une valeur donnée de manière efficace, sans modifier les autres canaux?

Comment définir canal donné d'un cv::Mat à une valeur donnée de manière efficace, sans modifier les autres canaux? Par exemple, je veux mettre sa quatrième canal (canal alpha) sur la valeur 120 (c'est à dire la moitié transparent), quelque chose comme:

cv::Mat mat; //with type CV_BGRA
...
mat.getChannel(3) = Scalar(120); //<- this is what I want to do

P. S.: Ma solution actuelle est d'abord divisé la mat en de multiples canaux et de définir le canal alpha, puis de les fusionner en arrière.

P. S. 2: je sais que je peux le faire rapidement si je veux aussi changer d'autres canaux par:

mat.setTo(Scalar(54, 154, 65, 120)); 

Mise à jour avec une solution:

Les deux méthodes de travail pour l'établissement de tous les tapis de valeurs au canal donné à la valeur donnée. Et ils vont travailler pour toutes les matrices qu'elles soient continues ou non.

Méthode-1 - plus efficace

-> basé sur @Antonio réponse et encore améliorée par @MichaelBurdinov

//set all mat values at given channel to given value
void setChannel(Mat &mat, unsigned int channel, unsigned char value)
{
    //make sure have enough channels
    if (mat.channels() < channel + 1)
        return;

    const int cols = mat.cols;
    const int step = mat.channels();
    const int rows = mat.rows;
    for (int y = 0; y < rows; y++) {
        //get pointer to the first byte to be changed in this row
        unsigned char *p_row = mat.ptr(y) + channel; 
        unsigned char *row_end = p_row + cols*step;
        for (; p_row != row_end; p_row += step)
            *p_row = value;
    }
}

Méthode-2 - plus élégant

-> basé sur @MichaelBurdinov la réponse de

//set all mat values at given channel to given value
void setChannel(Mat &mat, unsigned int channel, unsigned char value)
{
    //make sure have enough channels
    if (mat.channels() < channel+1)
        return;

    //check mat is continuous or not
    if (mat.isContinuous())
        mat.reshape(1, mat.rows*mat.cols).col(channel).setTo(Scalar(value));
    else{
        for (int i = 0; i < mat.rows; i++)
            mat.row(i).reshape(1, mat.cols).col(channel).setTo(Scalar(value));
    }
}

P. S.: Il est digne de noter que, selon la la documentation, matrices créé avec Mat::create() sont toujours en continu. Mais si vous extraire une partie de la matrice en utilisant la Mat::col(), Mat::diag(), et ainsi de suite, ou de la construction d'une matrice d'en-tête pour l'extérieur les données allouées, ces matrices peuvent ne plus avoir cette propriété.

  • Pour voir comment setTo est mis en œuvre, de construire OpenCV en mode debug et d'entrer dans la fonction du corps (en core.cpp)
  • Merci de bien vouloir examiner ma réponse. Merci!!!!