2015-08-31 1 views
1

Je complotais actuellement des ellipses dans un fond blanc ainsi que l'axe X et Y avec OpenCV comme ceci:ellipses Traçage avec transparence OpenCV

Mat image = Mat::zeros(size,size, CV_8UC3); 
image.setTo(Scalar(255,255,255)); /* White background */ 

/* Draw Axis */ 
line(image, 
     Point(originX, 0),        /*Point 1*/ 
     Point(originX, size),       /*Point 2*/ 
     Scalar(colorAxis.B,colorAxis.G,colorAxis.R), /*Color*/ 
     1,            /*Thickness*/ 
     8);            /*lineType*/ 

line(image, 
     Point(0, originY),        /*Point 1*/ 
     Point(size, originY),       /*Point 2*/ 
     Scalar(colorAxis.B,colorAxis.G,colorAxis.R), /*Color*/ 
     1,            /*Thickness*/ 
     8); 

for(i=0; i<numEllipses; i++) 
{ 
    ellipse(image, 
      Point(originX + dataEllipse[k].center[0]*ppu, originY - dataEllipse[k].center[1]*ppu), 
      Size(dataEllipse[k].axis[0]*ppu, dataEllipse[k].axis[1]*ppu), 
      -dataEllipse[k].angle, 
      0, 
      360, 
      Scalar(colorEllipse.B, colorEllipse.G, colorEllipse.R), 
      -1, 
      CV_FILLED); 
} 

imshow("Result", image); 
waitKey(1); 

Le présent est qu'il ya un nombre N de points de suspension et ils chevauchement. De plus, il y a une valeur de poids qui correspond à une couleur (du bleu au rouge). Je voudrais utiliser cette valeur de poids pour l'utiliser aussi comme un paramètre alpha. Pour ce que j'ai vu, il est possible d'utiliser une fonction addWeigth mais c'est entre deux images et je voudrais le faire avec les ellipses. Y at-il un moyen de le faire ou je devrais avoir une image par ellipse et utiliser addWeigth avec image0 et image1, puis (image0 et image1) et image2 et ainsi de suite?

Merci pour l'aide.

+1

rendre chaque ellipse à une image différente et utiliser addWeighted sur ces images! – Micka

+0

addWeight prend deux images à la fois, non? Si c'est comme ça, je devrais avoir l'arrière-plan avec l'axe dans l'image [0], et de l'image [1] à l'image [numEllipses] chaque ellipse puis faire une boucle addWeight (image [0], image [ n])? – aripod

+0

Cela n'a pas fonctionné .... Je me retrouve avec la transparence de la dernière ellipse pour chacun d'eux – aripod

Répondre

0

Voici un exemple de programme simple qui utilise des images d'ellipse temporaires pour dessiner des ellipses transparentes. Notez que poids = 1 signifie que l'ellipse n'est pas transparente mais solide, donc rien de "sous" cette ellipse n'est plus visible. Et l'ordre du dessin fait la différence!

int main() 
{ 
    //cv::Mat input = cv::imread("../inputData/Lenna.png"); 
    cv::Mat background = cv::Mat(512,512, CV_8UC3, cv::Scalar(255,255,255)); 

    std::vector<cv::Point2f> centers; 
    std::vector<cv::Scalar> colors; 
    std::vector<cv::Size> axes; 
    std::vector<float> angles; 
    std::vector<float> weights; 

    // make sure that there are same number of entries in each vector. 
    centers.push_back(cv::Point2f(255, 255)); 
    centers.push_back(cv::Point2f(275, 255)); 
    centers.push_back(cv::Point2f(255, 275)); 
    centers.push_back(cv::Point2f(275, 275)); 
    centers.push_back(cv::Point2f(255, 225)); 
    centers.push_back(cv::Point2f(225, 225)); 

    colors.push_back(cv::Scalar(255,0,0)); 
    colors.push_back(cv::Scalar(0,255,0)); 
    colors.push_back(cv::Scalar(0,0,255)); 
    colors.push_back(cv::Scalar(0,0,0)); 
    colors.push_back(cv::Scalar(0,0,0)); 
    colors.push_back(cv::Scalar(0,255,0)); 

    axes.push_back(cv::Size(128,128)); 
    axes.push_back(cv::Size(128,128)); 
    axes.push_back(cv::Size(128,128)); 
    axes.push_back(cv::Size(128,128)); 
    axes.push_back(cv::Size(128,128)); 
    axes.push_back(cv::Size(128,128)); 

    angles.push_back(0); 
    angles.push_back(0); 
    angles.push_back(0); 
    angles.push_back(0); 
    angles.push_back(0); 
    angles.push_back(0); 

    // weight 0 means completely transparent = invible. weight 1 means completely solid = will overwrite everything else 
    weights.push_back(0.5f); // half transparent 
    weights.push_back(0.5f); 
    weights.push_back(0.5f); 
    weights.push_back(1.0f); // solid 
    weights.push_back(0.3f); // quite transparent 
    weights.push_back(0.3f); // quite transparent 

    // ORDER DOES MATTER! 
    // printing a transparent ellipse over a solid ellipse will make the transparent ellipse partly visible, but printing the solid ellipse over anything will make only the solid ellipse visible 
    // you could however sort ellipses before printing so that more solid ones are more in the background for example 

    int thickness = 5; 

    for(unsigned int i=0; i<centers.size(); ++i) 
    { 
     cv::Mat temporaryEllipse = cv::Mat::zeros(background.rows, background.cols, background.type()); // same size and type as background; 
     cv::Mat temporaryMask = cv::Mat::zeros(background.rows, background.cols, CV_8UC1); // empty single channel 8bit mask 

     // draw ellipse to temporary 
     cv::ellipse(temporaryEllipse, centers[i], axes[i], angles[i], 0, 360, colors[i], thickness); 

     // draw same ellipse to mask 
     cv::ellipse(temporaryMask, centers[i], axes[i], angles[i], 0, 360, 255, thickness); 

     for(int y=0; y<temporaryEllipse.rows; ++y) 
      for(int x=0; x<temporaryEllipse.cols; ++x) 
      { 
       // only blend pixel that belong to the ellipse! 
       if(temporaryMask.at<unsigned char>(y,x)) 
       { 
        cv::Vec3b ellipsePixel = temporaryEllipse.at<cv::Vec3b>(y,x); 
        cv::Vec3b backgroundPixel = background.at<cv::Vec3b>(y,x); 

        float weight = weights[i]; 
        cv::Vec3b blendedPixel = weight*ellipsePixel + (1-weight)*backgroundPixel; 

        // update result 
        background.at<cv::Vec3b>(y,x) = blendedPixel; 
       } 
      } 
    } 


    cv::imshow("input", background); 
    cv::imwrite("../outputData/TransparentEllipses.png", background); 
    cv::waitKey(0); 
    return 0; 
} 

enter image description here

et ici dessiné avec une épaisseur de 15

enter image description here

+0

Je poste une réponse pour montrer mon code – aripod

0

J'ai testé votre code avec seulement deux ellipses remplies, un rouge et un bleu avec des tailles (1,2) et (2,1) avec 0,8 poids pour le rouge et 0,2 pour le bleu. Par conséquent, je devrais (ou je veux) finir avec l'ellipse rouge @ 0.8 et la bleue @ 0.2. Et où ils se chevauchent il devrait être un mélange entre le rouge et le bleu, non? De plus, si j'ai bien compris votre code, la première ellipse sera tracée complètement, mais lorsque la seconde sera tracée, les parties qui se chevauchent seulement seront affichées. Ai-je raison? Je suis votre code et j'ai fini avec ceci:

 cv::Mat background = cv::Mat(size,size, CV_8UC3, cv::Scalar(255,255,255)); 
    int color[nEll][3] = {{255,0,0},{0,0,255}}, y,x, s[nEll][2]={{2,1},{1,2}}; 
    float weights[nEll] = {0.8, 0.2}; 
    for(i=0; i<nEll; i++) 
    { 
     Mat temporaryEllipse = Mat::zeros(size,size, CV_8UC3); 
     Mat temporaryMask = Mat::zeros(size,size,CV_8UC1); 

     // draw ellipse to temporary 
     ellipse(temporaryEllipse, 
       Point(originX + 0.5*ppu, originY - 0.5*ppu), 
       Size(s[i][0]*ppu, s[i][1]*ppu), 
       0,//angle 
       0, 
       360, 
       Scalar(color[i][0], color[i][1], color[i][2]), 
       -1, 
       CV_FILLED); 

     // draw same ellipse to mask 
     ellipse(temporaryMask, 
       Point(originX + 0.5*ppu, originY - 0.5*ppu), 
       Size(s[i][0]*ppu, s[i][1]*ppu), 
       0,//angle 
       0, 
       360, 
       Scalar(color[i][0], color[i][1], color[i][2]), 
       -1, 
       CV_FILLED); 

     for(y=0; y<temporaryEllipse.rows; ++y) 
     { 
      for(int x=0; x<temporaryEllipse.cols; ++x) 
      { 
       // only blend pixel that belong to the ellipse 
       if(temporaryMask.at<unsigned char>(y,x)) 
       { 
        cv::Vec3b ellipsePixel = temporaryEllipse.at<cv::Vec3b>(y,x); 
        cv::Vec3b backgroundPixel = background.at<cv::Vec3b>(y,x); 

        cv::Vec3b blendedPixel = weights[i]*ellipsePixel + (1-weights[i])*backgroundPixel; 

        // update result 
        background.at<cv::Vec3b>(y,x) = blendedPixel; 
       } 
      } 
     } 
    } 
    cv::imshow("input", background); 

Mais je suis juste la dernière ellipse montré avec le poids = 1.

Merci beaucoup pour votre aide.

+0

vous devez écrire la valeur> 0 pour masquer. Masque est une matrice de canal unique, essayez donc ellipse (masque temporaire, Point (origineX + 0,5 * ppu, origineY - 0,5 * ppu), Taille (s [i] [0] * ppu, s [i] [1] * ppu), 0, // angle 0, 360, Scalaire (255), -1, CV_FILLED); – Micka

+0

en outre, le premier poids = 0,8 signifie que vous verrez le fond blanc qui brille à travers la première ellipse, pas sûr si cela est prévu. – Micka

+0

et je ne sais pas si je comprends bien. Si vous avez un fond avec colorB = (255,255,255) et que vous avez 2 ellipses, une avec color1 = (0,0,255) et une avec color2 = (255,0,0) et vous dessinez la première avec weight1 = 0,8 et la seconde une avec weight2 = 0.2 alors vous vous retrouverez avec 4 régions différentes: regionA = only background; regionB = seulement ellipse1; regionC = seulement ellipse2; regionD = ellipse1 et ellipse2. Alors regionA = [255,255,255]; regionB = [51, 51, 204]; regionC = [51,204,204]; regionD = [92,41,163] – Micka