web-dev-qa-db-fra.com

OpenCV: Prendre une image RVB à 3 canaux, diviser les canaux et visualiser une image avec seulement R + G

Je voulais regarder uniquement les canaux R + G dans une image RVB car j'obtiens de meilleurs contrastes pour détecter un objet lorsque le canal bleu est supprimé. J'ai utilisé OpenCV pour diviser les canaux, mais en fusionnant le même après avoir défini le canal bleu sur 0, mon code ne se compile pas.

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    if( argc != 2)
    {
     cout <<" Usage: display_image ImageToLoadAndDisplay" << endl;
     return -1;
    }

    Mat image,fin_img;
    image = imread(argv[1], CV_LOAD_IMAGE_COLOR);   // Read the file

    if(! image.data )                              // Check for invalid input
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

   namedWindow( "Display window", CV_WINDOW_AUTOSIZE );// Create a window for display.
                      // Show our image inside it.

    // Create Windows
    namedWindow("Red",1);
    namedWindow("Green",1);
    namedWindow("Blue",1);

    // Create Matrices (make sure there is an image in input!)

    Mat channel[3];
    imshow( "Original Image", image ); 


    // The actual splitting.
    split(image, channel);


   channel[0]=Mat::zeros(Size(image.rows, image.cols), CV_8UC1);//Set blue channel to 0

    //Merging red and green channels

    merge(channel,image);
    imshow("R+G", image);

    waitKey(0);//Wait for a keystroke in the window
    return 0;
}

Puis-je avoir des commentaires sur les erreurs que j'ai commises? Je suppose que c'est en mettant le canal bleu à 0. Y a-t-il une meilleure façon de le mettre à 0? Y a-t-il un moyen d'utiliser cvMixChannels () pour ce faire?

23
Sriharsha

Vous devez changer ces lignes

    channel[0]=Mat::zeros(Size(image.rows, image.cols), CV_8UC1);//Set blue channel to 0

    //Merging red and green channels
    merge(channel,image);

à

    channel[0]=Mat::zeros(image.rows, image.cols, CV_8UC1);//Set blue channel to 0

    //Merging red and green channels
    merge(channel,3,image);

Modifier

Selon votre commentaire, voici le code complet et le résultat.

#include <iostream>
#include "opencv2/opencv.hpp"
#include <stdio.h>    

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    if( argc != 2)
    {
     cout <<" Usage: display_image ImageToLoadAndDisplay" << endl;
     return -1;
    }

    Mat image,fin_img;
    image = imread("bgr.png", CV_LOAD_IMAGE_COLOR);   // Read the file

    if(! image.data )                              // Check for invalid input
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

   namedWindow( "Display window", CV_WINDOW_AUTOSIZE );// Create a window for display.
                      // Show our image inside it.

    // Create Windows
    namedWindow("Red",1);
    namedWindow("Green",1);
    namedWindow("Blue",1);

    // Create Matrices (make sure there is an image in input!)

    Mat channel[3];
    imshow( "Original Image", image );


    // The actual splitting.
    split(image, channel);


   channel[0]=Mat::zeros(image.rows, image.cols, CV_8UC1);//Set blue channel to 0

    //Merging red and green channels

    merge(channel,3,image);
    imshow("R+G", image);
    imwrite("dest.jpg",image);

    waitKey(0);//Wait for a keystroke in the window
    return 0;
}

Image source

enter image description here

Résultat sans composante bleue

enter image description here

32
Haris

D'accord, j'ai commencé à travailler avec mixChannels (): j'ai joint un ajout à l'extrait de code ci-dessus:

Mat gr( image.rows, image.cols, CV_8UC3);

// forming an array of matrices is a quite efficient operation,
// because the matrix data is not copied, only the headers
   Mat out[] = {gr};
// bgr[1] -> gr[1],
// bgr[2] -> gr[2], 
int from_to[] = {1,1, 2,2 };
mixChannels( &image, 1, out, 2, from_to, 2 );

imshow("R+G",gr);

Merci Harsha

6
Sriharsha

La façon la plus efficace de le faire est sans fractionner ni fusionner. Cela économise du temps et de la mémoire.

Juste au niveau du bit ET votre image avec cv::Scalar(0,255,255) et cela mettra votre canal bleu à zéro.

Comme dans: imshow("R+G", src & cv::Scalar(0,255,255));.

6
Adi Shavit

une autre façon consiste à soustraire Scalar(255,0,0) de l'image source

#include <opencv2/opencv.hpp>
using namespace cv;

int main(int argc, char **argv)
{
    Mat src = imread(argv[1], CV_LOAD_IMAGE_COLOR);
    imshow("src", src );
    src -= Scalar(255,0,0);
    imshow("Green and Red channels", src );
    waitKey();
    return 0;
}
4
sturkmen