J'ai une matrice img (480 * 640 pixels, float 64 bits) sur laquelle j'applique un masque complexe. Après cela, j'ai besoin de multiplier ma matrice par une valeur mais pour gagner du temps je veux faire cette multiplication uniquement sur les éléments non nuls car pour l'instant la multiplication est trop longue car je dois itérer l'opération 2000 fois sur 2000 matrice différente mais avec le même masque. J'ai donc trouvé l'indice (sur les axes x / y) des pixels non nuls que je garde dans un vecteur de Point. Mais je ne parviens pas à utiliser ce vecteur pour faire la multiplication uniquement sur les pixels indexés dans ce même vecteur.

Voici un exemple (avec un simple masque) pour comprendre mon problème:

Mat img_temp(480, 640, CV_64FC1);
Mat img = img_temp.clone();
Mat mask = Mat::ones(img.size(), CV_8UC1);
double value = 3.56;

// Apply mask
img_temp.copyTo(img, mask);

// Finding non zero elements
vector<Point> nonZero;
findNonZero(img, nonZero);

// Previous multiplication (long because on all pixels)
Mat result = img.clone()*value;

// What I wish to do : multiplication only on non-zero pixels (not functional)
Mat result = Mat::zeros(img.size(), CV_64FC1);
result.at<int>(nonZero) = img.at(nonZero).clone() * value

Ce qui est délicat, c'est que mes pixels ne sont pas sur une plage (par exemple les pixels 3, 4 et 50, 51 sur une ligne).

Merci d'avance.

0
Mathieu Gauquelin 23 mai 2018 à 16:06

3 réponses

Meilleure réponse

Je vous suggère d'utiliser Mat.convertTo. Fondamentalement, pour le paramètre alpha, qui est le facteur d'échelle, utilisez la valeur du masque (3,56 dans votre cas). Assurez-vous que le tapis est de type CV_32 ou CV_64.

Ce sera plus rapide que de trouver tous les pixels non nuls, d'enregistrer leurs coordonnées dans un vecteur et d'itérer (c'était plus rapide pour moi en Java).

J'espère que cela aide!

1
Rick M. 23 mai 2018 à 13:31

Si tu fais

Mat result = img*value;

Au lieu de

Mat result = img.clone()*value;

La vitesse sera presque 10 fois plus rapide

J'ai également testé votre suggestion avec vector mais c'est encore plus lent que votre première solution. Ci-dessous le code que j'ai utilisé pour tester votre première suggestion

cv::Mat multMask(cv::Mat &img, std::vector<cv::Point> mask, double fact)
{
    if (img.type() != CV_64FC1) throw "invalid format";
    cv::Mat res = cv::Mat::zeros(img.size(), img.type());
    int iLen = (int)mask.size();
    for (int i = 0; i < iLen; i++)
    {
        cv::Point &p = mask[i];
        ((double*)(res.data + res.step.p[0] * p.y))[p.x] = ((double*)(img.data + img.step.p[0] * p.y))[p.x] * fact;
    }
    return res;
}
1
Benno Geels 23 mai 2018 à 15:43

Construire un vecteur de points augmentera également le temps de calcul. Je pense que vous devriez envisager d'itérer sur tous les pixels et de multiplier si le pixel n'est pas égal à zéro.

L'itération sera plus rapide si vous avez la matrice sous forme de données brutes.

1
erkut 23 mai 2018 à 13:29