图像识别、图像模糊检测
最近有个项目,需要对图片进行模糊检测, 人脸识别等比较复杂的图像处理。经过一番尝试,决定好好研究一下OpenCV的原理和使用。
OpenCV官网
现在,项目中有个需求——需要对用户操作编辑以后的图片进行质量评估,做模糊检测。我采用了Tenengrad梯度和Laplacian梯度算法。
1. 算法
- Tenengrad 梯度函数
Tenengrad 梯度函数采用Sobel算子分别提取水平和垂直方向的梯度值,基与Tenengrad 梯度函数的图像清晰度定义如下:
G(x,y) 的形式如下:
其中:T是给定的边缘检测阈值,Gx和Gy分别是像素点(x,y)处Sobel水平和垂直方向边缘检测算子的卷积,建议使用以下的Sobel算子模板来检测边缘:
**
- Laplacian 梯度函数
Laplacian 梯度函数与Tenengrad梯度函数基本一致,用Laplacian算子替代Sobel算子即可,该算子定义如下:
基于Laplacian 梯度函数的图像星清晰度的定义如下:
其中G(x,y)是像素点(x,y)处Laplacian算子的卷积。
2. 编码
以安卓为例:OpenCV-3.1.0-android-sdk下载地址(python版本可以去官网下载,最新已经是4.x了)
写个图像处理得工具类
/** * <pre> * 作者:wujie on 2019/1/21 15:59 * 邮箱:705030268@qq.com * 功能:图像模糊检测 * 最直接的方法就是计算图片的快速傅里叶变换,然后查看高低频的分布。如果图片有少量的高频成分,那么该图片就可以被认为是模糊的 * </pre> */
public class OpenCVUtils {
/** * tenengrad梯度 {@link Imgproc} * @descrption: tenengrad梯度方法利用Sobel算子分别计算水平和垂直方向的梯度,同一场景下梯度值越高,图像越清晰。 * @param: image: bitmap * @return: 返回Sobel算子计算的tenengrad梯度的均值 * 算法:先对原图像进行灰度化 => 根据Tenengrad梯度函数,采用Sobel算子分别提取水平和垂直方向的梯度值 */
public static double calcBlurByTenengrad(Bitmap image) {
LogUtils.i("image.w=" + image.getWidth() + ",image.h=" + image.getHeight());
//将图片信息读取到Mat图像矩阵
Mat matImage = new Mat();
Utils.bitmapToMat(image, matImage);
// 图像灰度化
Mat matImageGrey = new Mat();
if (matImage.channels() != 1) { //1表示单通道
//进行灰度化
Imgproc.cvtColor(matImage, matImageGrey, Imgproc.COLOR_BGR2GRAY);
} else {
//如果==1,说明本来就是单通道灰度图片,无须再度灰度
matImageGrey = matImage.clone();
}
Mat imageSobel = new Mat();
//Sobel算子计算tenengrad梯度
Imgproc.Sobel(matImageGrey, imageSobel, CvType.CV_16U, 1, 1);
//图像的平均灰度
double meanValue;
Scalar mean = Core.mean(imageSobel);
// LogUtils.i("scalar:" + mean.toString());
meanValue = mean.val[0]; //第一个是均值
LogUtils.i("tenengrad梯度 均值 meanValue:" + meanValue);
return meanValue;
}
/** * 拉普拉斯梯度 {@link Imgproc} * @descrption: Laplacian梯度是另一种求图像梯度的方法,用Laplacian算子替代Sobel算子 * @param: image: bitmap * @return: 返回计算的Laplacian梯度的均值 * 算法:先对原图像进行灰度化 => 然后用3x3的拉普拉斯算子进行滤波处理 => 再计算处理后图像的梯度均值 */
public static double calcBlurByLaplacian(Bitmap image) {
LogUtils.i("image.w=" + image.getWidth() + ",image.h=" + image.getHeight());
//将图片信息读取到Mat图像矩阵
Mat matImage = new Mat();
Utils.bitmapToMat(image, matImage);
// 图像灰度化
Mat matImageGrey = new Mat();
if (matImage.channels() != 1) { //1表示单通道
//进行灰度化
Imgproc.cvtColor(matImage, matImageGrey, Imgproc.COLOR_BGR2GRAY);
} else {
//如果==1,说明本来就是单通道灰度图片,无须再度灰度
matImageGrey = matImage.clone();
}
Mat imageSobel = new Mat();
//再计算一下拉普拉斯
Imgproc.Laplacian(matImageGrey, imageSobel, CvType.CV_16U, 3, 1, 0);
//图像的平均灰度
double meanValue;
Scalar mean = Core.mean(imageSobel);
// LogUtils.i("scalar:" + mean.toString());
meanValue = mean.val[0];
LogUtils.i("拉普拉斯梯度 均值 meanValue:" + meanValue);
return meanValue;
}
}
3. 测试**
- 准备6张做过不同程度模糊处理的图片。
测试效果如下
算法 | 原图 | 20%高斯模糊 | 40%高斯模糊 | 60%高斯模糊 | 80%高斯模糊 | 100%高斯模糊 |
---|---|---|---|---|---|---|
Tenengrad梯度 | 4.672268 | 0.8224229166666667 | 0.5335 | 0.4327958333333334 | 0.37921458333333335 | 0.2528916666666667 |
拉普拉斯梯(Laplacian)梯度 | 18.481472 | 3.1599833333333334 | 2.2233875000000003 | 1.8840750000000002 | 1.7024541666666668 | 1.3291458333333335 |
还没有评论,来说两句吧...