使用PNG图像作为GrabCut的掩模

3

我有一个带有绿色和红色线条以及透明背景的png图像,需要将其作为执行GrabCut的掩码使用。但是我得到了意外的结果。以下是我的代码:

//find the mask
Mat mask;
mask.create( image.size(), CV_8UC1);
mask.setTo(Scalar::all(GC_BGD));
Mat maskImg = imread("messi5.png");

for(int i=0; i<maskImg.cols; i++)    
    for(int j=0; j<maskImg.rows; j++)    
    {               
        //if it's red, make it white
        if ((int)maskImg.at<cv::Vec3b>(j,i)[0]==0 && (int)maskImg.at<cv::Vec3b>(j,i)[1] == 0 && (int)maskImg.at<cv::Vec3b>(j,i)[2] == 255) {

            mask.at<cv::Vec3b>(j,i)[0]= GC_BGD;
            mask.at<cv::Vec3b>(j,i)[1] = GC_BGD;
            mask.at<cv::Vec3b>(j,i)[2] = GC_BGD;
        }           

        //if it's green, make it black
        if ((int)maskImg.at<cv::Vec3b>(j,i)[0]==0 && (int)maskImg.at<cv::Vec3b>(j,i)[1] == 255 && (int)maskImg.at<cv::Vec3b>(j,i)[2] == 0) {    
            mask.at<cv::Vec3b>(j,i)[0] = GC_FGD;
            mask.at<cv::Vec3b>(j,i)[1] = GC_FGD;
            mask.at<cv::Vec3b>(j,i)[2] = GC_FGD;
        }
    }

 ...

这是输出结果:http://prntscr.com/40kt4e。我猜测它好像没有矩形,只看到了GC_FGD像素,其他所有的都被视为BG。而且看起来有些缩放,但我不知道该如何修复。
1个回答

1
我想在

OpenCV (C++)中从PNG文件读取GrabCut掩模

中表达的是,您正在使用3通道访问器处理1通道图像。这会导致一些问题,请使用适用于1通道掩模的1通道版本。
    Mat image;
    image= cv::imread(file);

    //everything outside this box will be set to def. 
    //background GC_BGD, clearly from the image you can see that the players legs are outside the box, 
    //so this will cause problems. you need to either change the box, 
    //such that everything is outside the box is the background, or use your mask to scribble on the players legs in green.  
    cv::Rect rectangle(startX, startY, width, height);  
    cv::Mat bgModel,fgModel;

    //find the mask
    Mat mask;
    mask.create( image.size(), CV_8UC1);  //CV_8UC1 is single channel
    mask.setTo(Scalar::all(GC_BGD));  //you have set it to all def. background 

    Mat maskImg = imread("messi5.png");


    for(int i=0; i<maskImg.cols; i++)    
        for(int j=0; j<maskImg.rows; j++)    
        {               
            //if it's red, make it black
            if ((int)maskImg.at<cv::Vec3b>(j,i)[0]==0 && (int)maskImg.at<cv::Vec3b>(j,i)[1] == 0 && (int)maskImg.at<cv::Vec3b>(j,i)[2] == 255) {

                //the whole mask is black so this is redundant
                mask.at<uchar>(j,i)= GC_BGD;  //GC_BGD := 0 := black 

            }           

            //if it's green, make it white
            if ((int)maskImg.at<cv::Vec3b>(j,i)[0]==0 && (int)maskImg.at<cv::Vec3b>(j,i)[1] == 255 && (int)maskImg.at<cv::Vec3b>(j,i)[2] == 0) {    

                    mask.at<uchar>(j,i) = GC_FGD; //GC_FGD:= 1 := white 

            }
        }

如需更高效的图像循环代码,请参见: http://docs.opencv.org/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html

LUT函数可能会在这里发挥作用: http://docs.opencv.org/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html#the-core-function


这个很好用,但是对于大分辨率的图片来说速度非常慢。除了让它在GPU上运行之外,你有什么提高性能的建议吗? - nena
1
嗨,如果你只是指那个循环,那么你可以直接访问数据,而不使用 .at 函数。如果你指的是 GrabCut,恐怕不行,因为这意味着加速图割,而图割本质上是最大流,所以你会涉及到重度计算机科学工作。 - QED
1
https://dev59.com/11_Va4cB1Zd3GeqPUY_s - QED
@QUED 我认为我应该尝试并行编程,我认为这是提高性能的最佳方式。你能给我一些指导吗,只是让我知道从哪里开始? - nena

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接