【问题标题】:OpenCV: custom area/image as a source of a "background" for GrabCutOpenCV:自定义区域/图像作为 GrabCut 的“背景”来源
【发布时间】:2026-02-04 13:45:01
【问题描述】:

我有一些想要消除某些模式的人类图像。请看下面的三张图片:

GrabCut 从第一张图片中提取了人物(第二张图片),没有任何问题。

现在我有一个与脸部相对应的矩形(第二张图片上的圆圈),我想将其用作“背景”(而图像的其余部分将是前景和背景的组合)以消除皮肤脱落只有衣服。

大致期望的结果在第三张图片上:

有没有办法让 GrabCut 做到这一点?我无法手动分配区域/蒙版,我所拥有的只是人脸检测提供的矩形。


UPD:在下面的代码中,我尝试使用蒙版进行此操作,但第 2 阶段似乎不起作用(因为至少应该剪掉脸部)。也许我只是不明白它是如何工作的,因为我刚刚修改了另一个示例代码正在工作:

static Mat my_segment(Mat _inImage, Rect assumption, Rect face){ 
// human segmentation opencv

        // _inImage - input image
        // assumption - human rectangle on _inImage
        // face - face rectangle on _inImage
        // iterations  - is being set externally


        /* 
        GrabCut segmentation        
        */


        Mat bgModel,fgModel; // the models (internally used)
        Mat result; // segmentation result


        //*********************** step1: GrabCut human figure segmentation
        grabCut(_inImage,    // input image
            result,   // segmentation result
            assumption,// rectangle containing foreground
            bgModel,fgModel, // models
            iterations,        // number of iterations
            cv::GC_INIT_WITH_RECT); // use rectangle

        // Get the pixels marked as likely foreground
        cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);

        // upsample the resulting mask       

        cv::Mat separated(assumption.size(),CV_8UC3,cv::Scalar(255,255,255));
        _inImage(assumption).copyTo(separated,result(assumption));  
         // (bg pixels not copied)

        //return(separated); // return the innerings of assumption rectangle


        //*********************** step2: 
        //cutting the skin with the mask based on the face rectangle
        Rect adjusted_face = face;
        adjusted_face.x = face.x - assumption.x;
        adjusted_face.y = face.y - assumption.y;

        //rectangle(separated,  
        //     adjusted_face.tl(), 
        //     adjusted_face.br(), 
        //     cv::Scalar(166,94,91), 2);  

        //creating mask
        Mat mymask(separated.size(),CV_8UC1);  

        // setting face area as sure background
        mymask.setTo(Scalar::all(GC_PR_FGD));
        mymask(adjusted_face).setTo(Scalar::all(GC_BGD));

        // performing grabcut
        grabCut(separated,
           mymask,
           cv::Rect(0,0,assumption.width,assumption.height),
           bgModel,fgModel,
           1,
           cv::GC_INIT_WITH_MASK);

        // Just repeating everything from before

        // Get the pixels marked as likely foreground
        cv::compare(mymask,cv::GC_PR_FGD,mymask,cv::CMP_EQ);

        //here was the error
        //separated.copyTo(separated,mymask);  // bg pixels not copied

        cv::Mat res(separated.size(),CV_8UC3,cv::Scalar(255,255,255));
        separated.copyTo(res,mymask);  // bg pixels not copied

        //*************************//   

        //return(separated); // return the innerings of assumption rectangle
        return(res);            

} 

【问题讨论】:

    标签: c++ opencv image-processing


    【解决方案1】:

    好的,我发现了错误,而不是

    separated.copyTo(separated,mymask); 
    

    最后几行应改为:

    cv::Mat res(separated.size(),CV_8UC3,cv::Scalar(255,255,255));
    separated.copyTo(res,mymask);  // bg pixels not copied
    //*************************//        
    return(res); // return the innerings of assumption rectangle
    

    第二次抓取调用还需要更多的迭代,比如 5-7 次迭代。

    结果不太好,欢迎大家给出可以改进的答案。

    【讨论】: