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 construireOpenCV
en mode debug et d'entrer dans la fonction du corps (encore.cpp
) - Merci de bien vouloir examiner ma réponse. Merci!!!!
Vous devez vous connecter pour publier un commentaire.
Si votre image est en continu dans la mémoire vous pouvez utiliser l'astuce suivante:
Si elle n'est pas continue:
Edit (merci à Antonio pour le commentaire):
Noter que ce code peut être le plus court et il n'est pas de l'attribution de nouveaux de la mémoire, mais elle n'est pas efficace du tout. Il peut être encore plus lente que split/merge approche. OpenCV est vraiment inefficace quand il doit effectuer des opérations sur les non-matrices continues avec 1 pixel dans une rangée. Si le temps le rendement est important, vous devez utiliser la solution proposée par @Antonio.
Juste une légère amélioration de sa solution:
Cela économise de l'opération d'incrémentation de x et un moins de valeur dans le registre. Sur le système à ressources limitées, il peut donner à ~5% de l'accélération. Autrement le temps les performances seront les mêmes.
Mat::create()
sont toujours en continu. Mais si vous extraire une partie de la matrice en utilisant laMat::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é. Et nous pouvons compter surMat::isContinuous()
pour vérifier.Remarque: Cela fonctionne à la fois continue et uncontinuous matrices, en fonction de l'utilisation du terme pour opencv: http://docs.opencv.org/modules/core/doc/basic_structures.html#bool%20Mat::isContinuous%28%29%20const
const
, par la voie), mais c'est pas une raison pour downvote. L'étape est l'étape de byte à sauter d'un alpha octet pour la prochaine. docs.opencv.org/modules/core/doc/basic_structures.html#mat-ptrp_row += step;
*p_row = value;
. Cependant, il existe des erreurs facilement retiré après la compilation.Qu'en direct Mat::accès aux données (je suis tout à fait sûr de setTo() ou oother opencv Mat api utiliser la même solution):
img.data + (y * img.cols + x)
devrait êtreimg.data + (y * img.step1() + x)
Algorithme Simple: