最近一直在捣腾openCV,看到别人朋友圈总喜欢给图片打一点马赛克,充满神秘感。准备用openCV来实现打码,其实足够模糊就能实现马赛克效果。查看API发现ImgProc模块提供四种模糊方法:高斯模糊、均值模糊、中值模糊、双边滤波。在这里主要比较高斯模糊、均值模糊以及自定义覆盖层的实现效果。
首先,各种初始化:openCV库、模糊线程、人脸检测器。
/**
* 初始化openCV
*/
private void initOpenCV(){
boolean result = OpenCVLoader.initDebug();
if(result){
Log.i(TAG, "initOpenCV success...");
}else {
Log.e(TAG, "initOpenCV fail...");
}
}
/**
* 初始化mat
*/
private void initMat(){
mat = new Mat();
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.beauty);
Utils.bitmapToMat(bitmap, mat);
}
/**
* 初始化线程
*/
private void initThread(){
blurThread = new BlurThread(mHandler, blurMat);
blurThread.start();
blurThread.setRunning(true);
}
/**
* 初始化人脸检测器
* @param context context
*/
public void initDetector(Context context){
mFaceRect = new MatOfRect();
mFaceDetector = new ObjectDetector(context, R.raw.lbpcascade_frontalface,
6, 0.2F, 0.2F,
new Scalar(0, 0, 255, 0));
}
使用人脸检测器去检测人脸,得到待打码区域:
/**
* 检测人脸
*/
private void detectFace(){
Mat mGray = new Mat();
Imgproc.cvtColor(mat, mGray, Imgproc.COLOR_RGBA2GRAY);
Rect[] faceRect = mFaceDetector.detectObject(mGray, mFaceRect);
if(faceRect != null && faceRect.length > 0){
Rect face = faceRect[0];
//矩形标识
Imgproc.rectangle(mat, face.tl(), face.br(),
mFaceDetector.getRectColor(), 3);
//待打码区域
blurMat = mat.submat((int) face.tl().y, (int) face.br().y, (int) face.tl().x, (int) face.br().x);
}
mGray.release();
mHandler.obtainMessage(100).sendToTarget();
}
1、高斯模糊
高斯模糊是采用高斯核函数,创建高斯滤波器,遍历待滤波区域:每一个像素与给定像素矩阵模板相乘,求线性加权平均点。
//高斯模糊
private void gaussianBlur(int width, int height,double sigmaX){
Imgproc.GaussianBlur(blurMat, blurMat, new Size(width, height), sigmaX);
}
均值模糊是对给定像素矩阵取平均值,算法比高斯模糊简单点,耗时相对短一点。
//均值模糊
private void normalBlur(int width, int height){
Imgproc.blur(blurMat, blurMat, new Size(width, height));
}
3、深度模糊(自定义覆盖层)
自定义模糊算法相对简单:遍历待处理区域,重新赋值为指定颜色值。
//自定义模糊
private void customBlur(int color){
//ARGB转成RGBA
pixelColor[2] = color & 0xFF;//Blue
pixelColor[1] = (color >> 8) & 0xFF;//Green
pixelColor[0] = (color >> 16) & 0xFF;//Red
pixelColor[3] = (color >> 24) & 0xFF;//Alpha
for (int x=0; x<blurMat.rows(); x++){
for (int y=0; y<blurMat.cols(); y++){
blurMat.put(x, y, pixelColor);
}
}
}
如果需要在预览时,可采用均值模糊进行实时打码(高斯模糊耗时比较长,引起预览卡顿):
@Override
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
// 检测人脸
Rect[] faceRect = mFaceDetector.detectObject(mGray, mFaceRect);
if(faceRect != null && faceRect.length > 0){
Rect face = faceRect[0];
//采用均值模糊进行打码
Mat blurMat = mRgba.submat((int) face.tl().y, (int) face.br().y, (int) face.tl().x, (int) face.br().x);
Imgproc.blur(blurMat, blurMat, new Size(99, 99));
}
return mRgba;
}
好了,关于采用高斯模糊、均值模糊以及自定义覆盖层给图片打码分析完毕。如果各位有什么问题或建议,欢迎交流,如果觉得本篇文章对您有所帮助,麻烦点个赞。。。