遮罩未显示在OpenCV摄影机预览中

Mask not displayed in OpenCV camera preview

本文关键字:摄影机 OpenCV 显示      更新时间:2023-10-16

我想制作一个简单的Android应用程序,用OpenCV在检测到的人脸上戴上口罩,比如这个例子:

人脸面具检测教程

我为我的应用程序将C++翻译成Java。掩码的大小调整得很好,白色部分被消除了(我在预览的ImageView中显示了测试结果),但掩码从未出现在绿色矩形中的检测面上:

结果的屏幕截图

我的代码:

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
             [...]
    for( int i = 0; i < facesArray.length; i++)
        min_face_size = facesArray[0].width*0.7;
        max_face_size = facesArray[0].width*1.5;
        Point center=new Point (facesArray[i].x + facesArray[i].width/2, facesArray[i].y + facesArray[i].height/2);
        mRgba=putMask(mRgba,center, new Size(facesArray[i].width, facesArray[i].height));
    }
    return mRgba;
}
Mat putMask(Mat src, Point center, Size face_size)
{
    //mask : loaded mask image
    Mat mask1 = new Mat(); //resized mask
    src1 = new Mat(); //ROI
    m = new Mat();
    Imgproc.resize(mask ,mask1,face_size);
    // ROI selection
    roi = new Rect((int) (center.x - face_size.width/2), (int) (center.y - face_size.height/2),(int) face_size.width, (int) face_size.height);
    //Rect roi = new Rect(100, 100, (int) face_size.width, (int) face_size.height);
    src.submat(roi).copyTo(src1);

    // to make the white region transparent
    Mat mask2 = new Mat(); //greymask
    m1= new Mat();
    Imgproc.cvtColor(mask1,mask2, Imgproc.COLOR_BGR2GRAY);
    Imgproc.threshold(mask2,mask2,230,255, Imgproc.THRESH_BINARY_INV);
    ArrayList<Mat> maskChannels = new ArrayList<>(3);
    ArrayList<Mat> result_mask = new ArrayList<>(3);
    result_mask.add(new Mat());
    result_mask.add(new Mat());
    result_mask.add(new Mat());
    Core.split(mask1, maskChannels);
    Log.e(TAG, "MASK maskChannels :"+maskChannels.get(0).size());
    Log.e(TAG, "MASK mask2 :"+mask2.size());
    Core.bitwise_and(maskChannels.get(0),mask2, result_mask.get(0));
    Core.bitwise_and(maskChannels.get(1),mask2, result_mask.get(1));
    Core.bitwise_and(maskChannels.get(2),mask2, result_mask.get(2));
    Core.merge(result_mask, m);        

    Core.subtract(mask2, new Scalar(255), mask2);
    ArrayList<Mat> srcChannels = new ArrayList<>(3);
    Core.split(src1, srcChannels);
    Core.bitwise_and(srcChannels.get(0),mask2, result_mask.get(0));
    Core.bitwise_and(srcChannels.get(1),mask2, result_mask.get(1));
    Core.bitwise_and(srcChannels.get(2),mask2, result_mask.get(2));
    Core.merge(result_mask,m1);        

    Core.addWeighted(m,1,m1,1,0,m1);    
    m1.copyTo(src.submat(roi));
    return src;
}

===============

感谢@hariprasad:)这里的工作代码:

 onCreate(){
          [...]
                try {
                    File file = new File(Environment.getExternalStorageDirectory(), "1-alpha.png");
                    mask = Imgcodecs.imread(file.getPath(), -1);
                }catch (Exception e){
                    e.printStackTrace();
                }
        }

Mat putMask(Mat src, Point center, Size face_size)
{
    //mask : masque chargé depuis l'image
    Mat mask_resized = new Mat(); //masque resizé
    src_roi = new Mat(); //ROI du visage croppé depuis la preview
    roi_gray = new Mat();

    Imgproc.resize(mask ,mask_resized,face_size);
    // ROI selection
    roi = new Rect((int) (center.x - face_size.width/2), (int) (center.y - face_size.height/2),(int) face_size.width, (int) face_size.height);
    //Rect roi = new Rect(10, 10, (int) face_size.width, (int) face_size.height);
    src.submat(roi).copyTo(src_roi);
    Log.e(TAG, "MASK SRC1 :"+ src_roi.size());
    // to make the white region transparent
    Mat mask_grey = new Mat(); //greymask
    roi_rgb = new Mat();
    Imgproc.cvtColor(mask_resized,mask_grey, Imgproc.COLOR_BGRA2GRAY);
    Imgproc.threshold(mask_grey,mask_grey,230,255, Imgproc.THRESH_BINARY_INV);
    ArrayList<Mat> maskChannels = new ArrayList<>(4);
    ArrayList<Mat> result_mask = new ArrayList<>(4);
    result_mask.add(new Mat());
    result_mask.add(new Mat());
    result_mask.add(new Mat());
    result_mask.add(new Mat());
    Core.split(mask_resized, maskChannels);
    Core.bitwise_and(maskChannels.get(0),mask_grey, result_mask.get(0));
    Core.bitwise_and(maskChannels.get(1),mask_grey, result_mask.get(1));
    Core.bitwise_and(maskChannels.get(2),mask_grey, result_mask.get(2));
    Core.bitwise_and(maskChannels.get(3),mask_grey, result_mask.get(3));
    Core.merge(result_mask, roi_gray);        
    Core.bitwise_not(mask_grey,mask_grey);
    ArrayList<Mat> srcChannels = new ArrayList<>(4);
    Core.split(src_roi, srcChannels);
    Core.bitwise_and(srcChannels.get(0),mask_grey, result_mask.get(0));
    Core.bitwise_and(srcChannels.get(1),mask_grey, result_mask.get(1));
    Core.bitwise_and(srcChannels.get(2),mask_grey, result_mask.get(2));
    Core.bitwise_and(srcChannels.get(3),mask_grey, result_mask.get(3));
    Core.merge(result_mask, roi_rgb);          
    Core.addWeighted(roi_gray,1, roi_rgb,1,0, roi_rgb); 
    roi_rgb.copyTo(new Mat(src,roi));
    return src;
}

src.submat(roi)不等于c++中的src(roi)。因为在c++中src(roi)实际上修改了roi区域中的src数据矩阵,而在java中submat是对src的roi进行克隆。因此,对roi所做的任何更改都不会影响src,这就是为什么你在相机预览中一无所获的原因。要使其正确,您需要使用类似c的构造函数++即使用

m1.copyTo(new Mat(src,roi));

而不是

 m1.copyTo(src.submat(roi));