问题
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