Mask not displayed in OpenCV camera preview

折月煮酒 提交于 2019-12-21 22:20:16

问题


I want to make a simple Android app which put a mask on a detected face with OpenCV such as this example :

Mask on face detection tutorial

I translate the C++ into Java for my app.The mask is well resized and the white part eliminated (I displayed the result for testing in an ImageView on the Preview) but the mask never appear on the detected face int the green rectangle :

Screenshot of the result

My code :

    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;
}

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

Thanks to @hariprasad :) here the working code :

 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;
}

回答1:


src.submat(roi) is not equalent to src(roi) in c++.Because in c++ src(roi) actually modifying the src data matrix in the roi area but in java submat is making clone of the roi of src.So any changes done to roi will not effect src that is why you got nothing in camera preview. to make it correct you need to use constructor like c++ i.e use

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

instead of

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


来源:https://stackoverflow.com/questions/38749867/mask-not-displayed-in-opencv-camera-preview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!