Ask Your Question

Help with alpha gradient

asked 2018-12-01 03:42:47 -0500

HI all! I'm using opencv for Unity in c# but I think is very similar to opencv for Java

I think my problem is a simple one, but I'm new to opencv and there are a lot of things that I don't know...

This is my situation: From a picture I need to cut the face and apply some sketch effect.


image description


image description

What I need is a gradient alpha border of the ellipse in the final image. Something like the next image but with a gradient in the border of the ellipse

image description

This is my code:

 Mat mask = new Mat(rgbaMat.rows(), rgbaMat.cols(), CvType.CV_8UC4, new Scalar(0, 0, 0, 0));
 Mat face = new Mat(rgbaMat.rows(), rgbaMat.cols(), CvType.CV_8UC4, new Scalar(0, 0, 0, 0));
 OpenCVForUnity.Rect rectCrop = new OpenCVForUnity.Rect((int)x, (int)y, (int)width, (int)height);
 RotatedRect rRect = new RotatedRect(new Point(centerX, centerY), new Size(width, height), 0);
 Imgproc.ellipse(mask, rRect, new Scalar(255, 255, 255, 255), -1);
 Imgcodecs.imwrite(Application.dataPath + "/mask.png", mask);

 Mat abs_grad_x = new Mat(rgbaMat.rows(), rgbaMat.cols(), CvType.CV_16SC4, new Scalar(0, 0, 0, 0));
 Mat abs_grad_y = new Mat(rgbaMat.rows(), rgbaMat.cols(), CvType.CV_16SC4, new Scalar(0, 0, 0, 0));
 Mat grad_x = new Mat(rgbaMat.rows(), rgbaMat.cols(), CvType.CV_16SC4, new Scalar(0, 0, 0, 0));
 Mat grad_y = new Mat(rgbaMat.rows(), rgbaMat.cols(), CvType.CV_16SC4, new Scalar(0, 0, 0, 0));
 int delta = 0;
 int scale = 1;
 int ddepth = CvType.CV_16S;

 Mat final = new Mat(rgbaMat.rows(), rgbaMat.cols(), CvType.CV_16SC4, new Scalar(0, 0, 0, 0));
 Imgproc.GaussianBlur(mask, mask, new Size(42, 42), 0);
 rgbaMat.copyTo(face, mask);
 face = face.submat(rectCrop);
 Imgproc.GaussianBlur(face, face, new Size(21, 21), 0);
 Imgproc.cvtColor(face, face, Imgproc.COLOR_RGBA2GRAY);
 Imgproc.Scharr(face, grad_x, ddepth, 1,0,scale, delta, 0);
 Core.convertScaleAbs(grad_x, abs_grad_x);

 Imgproc.Scharr(face, grad_y, ddepth,0, 1, scale, delta, 0);
 Core.convertScaleAbs(grad_y, abs_grad_y);
 Core.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, final);
 Core.bitwise_not(final, final);
 Imgproc.threshold(final, final, 230,255, Imgproc.THRESH_BINARY);
edit retag flag offensive close merge delete


may be this can help you. We cannot help you with unity or 3rd party wrappers

LBerger gravatar imageLBerger ( 2018-12-01 04:14:12 -0500 )edit

Hi, thank you for the answer but I'm already doing the face detection to make the ellipse in the right place. I'm having big troubles making the alpha gradient...I undertsand the wrapper problem but I think that here is not related. The problem could be discuss without code...I would need to know the right steps to do for making a gradient. There are some knowledges that I'm missing, can You help me with that? Thank you!

GuybrushThreepwood gravatar imageGuybrushThreepwood ( 2018-12-01 04:38:42 -0500 )edit

i think, he wants some kind of gaussian "vignette"

(and yea, though unity itself is c#, the opencv asset is actually using java there)

berak gravatar imageberak ( 2018-12-01 04:47:02 -0500 )edit

I don't know what is alpha gradient in image processing. Now if you want to locate ellipse border you draw ellipse with a thickness of t. You use result as a mask

LBerger gravatar imageLBerger ( 2018-12-01 04:50:02 -0500 )edit

Sorry for my english....I need something like this:

GuybrushThreepwood gravatar imageGuybrushThreepwood ( 2018-12-01 04:53:03 -0500 )edit

@LBerger -- the ellipse thing is exactly, what's already happening in the code above .. (ellipse mask & copyTo())

berak gravatar imageberak ( 2018-12-01 05:06:13 -0500 )edit

Ok then you can use this post result you can use as a weight is maskBlur : value near boundary are small and near center are constant

LBerger gravatar imageLBerger ( 2018-12-01 05:15:20 -0500 )edit

Ok thank you! I'll try and I'll let you know

GuybrushThreepwood gravatar imageGuybrushThreepwood ( 2018-12-01 05:37:46 -0500 )edit

2 answers

Sort by ยป oldest newest most voted

answered 2018-12-01 06:23:28 -0500

LBerger gravatar image

updated 2018-12-01 06:30:37 -0500

another way (but in c++) with an unknown mask :

Mat m = imread("g:/lib/opencv/samples/data/lena.jpg", IMREAD_GRAYSCALE);

Mat mask = Mat::zeros(m.size(), CV_8UC1), maskBlur, mc;
// mask is a contour
vector<vector<Point>> c = { {Point(200,100),Point(250,100),Point(350,250),Point(350,300),Point(150,350) } };
drawContours(mask, c, 0, Scalar(255), -1);
Mat negMask;
// neg mask
bitwise_not(mask, negMask);
Mat md, mdBlur, mdint;


// All pixels outside mask set to 0
md.setTo(0, negMask);
imshow("mask image", md);
// Convert image to int
md.convertTo(mdint, CV_32S);
Size fxy(41, 41);
blur(mdint, mdBlur, fxy);
mask.convertTo(maskBlur, CV_32S);

blur(maskBlur, maskBlur, fxy);
Mat mskB;
mskB.setTo(1, negMask);
Mat m1, m2, maskFloat,mweight;
maskBlur.convertTo(maskFloat, CV_32F,1/255.);
pow(maskFloat,4, maskFloat);
normalize(maskFloat, mweight, 1, NORM_MINMAX);
multiply(mdBlur, 1 - maskFloat, m1, 1, CV_32F);
multiply(m, maskFloat, m2,1, CV_32F);
mc = (m1 + m2);
mc.convertTo(mc, CV_8U);
imshow("Blur with mask", mc);

image description

edit flag offensive delete link more


Thank you for the answer! I used the berak's method but I'll try this in the future too, thank you again!

GuybrushThreepwood gravatar imageGuybrushThreepwood ( 2018-12-03 04:22:15 -0500 )edit

answered 2018-12-01 06:00:33 -0500

berak gravatar image

updated 2018-12-01 06:05:27 -0500

opencv != photoshop !

however, i think, we can help you with your alpha mask.

this is basically a 2d gaussian distribution, used as a vignette

it's a bit clumsy, using java but something like this:

Size s = image.size();
double sigma = 45.0;
double cutoff = 900;

Mat vert = Imgproc.getGaussianKernel(200, sigma, CvType.CV_64F);
Mat horz = Imgproc.getGaussianKernel(200, sigma, CvType.CV_64F);

Mat vignette = new Mat();
Core.gemm(vert,horz, 1, new Mat(), 0, vignette, Core.GEMM_2_T);

Core.normalize(vignette,vignette, cutoff*255, 0, Core.NORM_L2, CvType.CV_8U);

will result in an image like:

image description

then you can split the image into channels, and merge the vignette as alpha channel:

(this assumes, the image had 3 channels. if you have 4, you have to throw away the 4th channel before merging)

    List<Mat> chn = new ArrayList<Mat>();

image description

edit flag offensive delete link more


I tried this method and in my case it works well. Thank you very much...I need to study opencv, do you have some advise? A book or a pdf or something else? Thank you!

GuybrushThreepwood gravatar imageGuybrushThreepwood ( 2018-12-03 04:21:23 -0500 )edit

Another question, I need to make the gradient to alpha thinner. How can I do that? All 3 values seems to change the dimension of the ellipse in some way but not the dimension of the gradient (that take all the rest of the image

GuybrushThreepwood gravatar imageGuybrushThreepwood ( 2018-12-04 02:39:43 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower


Asked: 2018-12-01 03:42:47 -0500

Seen: 130 times

Last updated: Dec 01 '18