1

I'm trying to replace a detected face in an image with a modified one. I have no issue utilizing a regular rectangular roi. However, to be a bit more precise, I'm trying to use a circle ROI. I know you have to create a rectangular mask to do this. Here I am using a black mask. Maybe there is a way to make the mask transparent? I think I'm close, yet when I merge the augmented face onto the image, the modified face portion has the square black border (from the mask i presume) included. How do i eliminate the black square border? Is this possible? Thank you!

See the problem: https://pasteboard.co/JscU9re.png

Here is the relevant code ... let me know if you need all of it.

int radius = faces[ic].width / 2;
Mat mask(Size(faces[ic].width,faces[ic].height), CV_8U, Scalar(0)); // all black
Rect region = Rect(faces[ic].x,faces[ic].y,faces[ic].width,faces[ic].height);
Mat circ_roi;

Mat roi(img,region);
Mat insetImage(img, region);


circle(mask, Point(radius,radius), radius, Scalar(255), -1);
bitwise_and(roi, roi, circ_roi, mask); // retain only pixels inside the circle

// create a mat to store the modified mat from the gpu
Mat h_result (circ_roi.size(), circ_roi.type());

// create GPU/device images, same size and type as original host image
cuda::GpuMat d_crop(circ_roi);
cuda::GpuMat d_result;

// create the gaussian filter
cv::Ptr<cuda::Filter> gauss = cv::cuda::createGaussianFilter(d_crop.type(),
d_result.type(), Size(ksize, ksize), 6.0, 6.0);

// apply the gaussian filter to our cropped image
gauss->apply(d_crop, d_result);

// download the result image from device to host
d_result.download(h_result);

// leaves the black border around circle :(
h_result.copyTo(insetImage);

Thank you, Chris

chris
  • 11
  • 1
  • I think [here](https://answers.opencv.org/question/174551/how-to-show-transparent-images/?answer=175045) is your answer. – Yunus Temurlenk Sep 24 '20 at 06:13
  • Hmm, thank you. Yet, this doesn't appear to work as it would expect one of the images to have 4 channels include an alpha channel. My images are not 4 channels, just 3. – chris Sep 29 '20 at 04:11

1 Answers1

0

I got this to work by tweaking your code a bit to do the blur first and then the bitwise operation. That gets rid of the black circle that appears around the blur area, I guess because if you try to blur after doing the bitwise then there are a bunch of black pixels around the blur area that end up getting moved into the circle area by the blur effect.

I just started using openCV for Android yesterday so not 100% sure if that explanation is correct but I can show you my code in Java that worked for me:

int blurRadius = 50; // or however much you want to blur..

// (x and y are the co-ordinates where the user has touched the image in my case)
Rect areaToBlur = new Rect(x, y, blurRadius * 2, blurRadius * 2);

// Create a matrix from the rectangle area to blur (img is the original Mat img)
Mat rectangularSubImage = img.submat(areaToBlur).clone();

// Blur the whole rectangularSubImage
Imgproc.GaussianBlur(rectangularSubImage, rectangularSubImage, new Size(0,0), 5, 5);

// Create a matrix with the same size as the rectangularSubImage with all black pixels
Mat circleMask = new Mat(rectangularSubImage.size(), CvType.CV_8U, new Scalar(0,0,0));

// Draw a circle on circleMask matrix with all white pixels
Imgproc.circle(
        circleMask,
        new Point(blurRadius, blurRadius),
        blurRadius,
        new Scalar(255,255,255),
        -1
);

Mat circularSubImage = new Mat();

// Removes any pixels from rectangularSubImage that overlap with the black pixels
// in circleMask and stores the result in circularSubImage
bitwise_and(rectangularSubImage, rectangularSubImage, circularSubImage, circleMask);

circularSubImage.copyTo(matImage.submat(areaToBlur), circleMask);