python图像领域平均_模糊图像检测-无参考图像的清晰度评价

1f54c65c4cb55fbb1f00a6809239bbf9.png

需求:在一堆图像中找到模糊图像,背景虚化(景深模式)的照片定义为清晰照片。

传统的图像清晰度评价算法:

Tenengrad 梯度函数

Tenengrad 梯度函数采用Sobel算子分别提取水平和垂直方向的梯度值,基与Tenengrad 梯度函数的图像清晰度定义如下:

18168df1ffbffb49e9617ea0bccd1663.png

G(x,y) 的形式如下:

ff84888eba14c9cd43e36bc86760e41f.png

其中:T是给定的边缘检测阈值,Gx和Gy分别是像素点(x,y)处Sobel水平和垂直方向边缘检测算子的卷积,建议使用以下的Sobel算子模板来检测边缘:

c8498a7f03d1bb246de10a189437176b.png

python程序实现:

Laplacian 梯度函数

Laplacian 梯度函数与Tenengrad梯度函数基本一致,用Laplacian算子替代Sobel算子即可,该算子定义如下:

d4664188f6a2478619181b50df896aaf.png

因此基于Laplacian 梯度函数的图像星清晰度的定义如下:

9b84bf3a2660f5535e08e99a744b1892.png

其中G(x,y)是像素点(x,y)处Laplacian算子的卷积。

python程序实现:

#Laplacian梯度函数计算
def Laplacian(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    return cv2.Laplacian(img,cv2.CV_64F).var()

SMD(灰度方差)函数

当完全聚焦时,图像最清晰,图像中的高频分量也最多,故可将灰度变化作为聚焦评价的依据,灰度方差法的公式如下:

c5c37145399552b3903488626f71f33a.png

python程序实现:

#SMD梯度函数计算
def SMD(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(1, shape[0]-1):
        for y in range(0, shape[1]):
            out+=math.fabs(int(img[x,y])-int(img[x,y-1]))
            out+=math.fabs(int(img[x,y]-int(img[x+1,y])))
    return out

SMD2 (灰度方差乘积)函数

灰度差分评价函数具有较好的计算性能,但其缺点也很明显,即在焦点附近灵敏度不高,即该函数在极值点附近过于平坦,从而导致聚焦精度难以提高。在文章《一种快速高灵敏度聚焦评价函数》中提出了一种新的评价函数,称之为灰度方差乘积法,即对每一个像素领域两个灰度差相乘后再逐个像素累加,该函数定义如下:

90d0ea61b8f00a59cbcc412e8cd9952f.png

python程序实现:

#SMD2梯度函数计算
def SMD2(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(0, shape[0]-1):
        for y in range(0, shape[1]-1):
            out+=math.fabs(int(img[x,y])-int(img[x+1,y]))*math.fabs(int(img[x,y]-int(img[x,y+1])))
    return out

Brenner 梯度函数

Brenner梯度函数是最简单的梯度评价函数,它只是简单的计算相邻两个像素灰度差的平方,该函数定义如下:

b1b87580a210826536be9680d1182fa4.png

其中:f(x,y) 表示图像f对应像素点(x,y)的灰度值,D(f)为图像清晰度计算结果.

python程序实现:

#brenner梯度函数计算
def brenner(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(0, shape[0]-2):
        for y in range(0, shape[1]):
            out+=(int(img[x+2,y])-int(img[x,y]))**2
    return out

方差函数

因为清晰聚焦的图像有着比模糊图像更大的灰度差异,可以将方差函数作为评价函数:

a6aff46a460461bce48e9223a0c8807f.png

其中:μ为整幅图像的平均灰度值,该函数对噪声比较敏感,图像画面越纯净,函数值越小。

python程序实现:

#方差函数计算
def variance(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    out = 0
    u = np.mean(img)
    shape = np.shape(img)
    for x in range(0,shape[0]):
        for y in range(0,shape[1]):
            out+=(img[x,y]-u)**2
    return out

能量梯度函数

能量梯度函数更适合实时评价图像清晰度,该函数定义如下:

4cddde403a1bd6d878ae6e348761f23d.png

python程序实现:

#energy函数计算
def energy(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(0, shape[0]-1):
        for y in range(0, shape[1]-1):
            out+=((int(img[x+1,y])-int(img[x,y]))**2)*((int(img[x,y+1]-int(img[x,y])))**2)
    return out

Vollath函数

Vollath函数定义如下:

bed2bbcc2be5f136cda60f2397570be1.png

其中:μ为整幅图像的平均灰度值,M和N分别为图像宽和高。

python程序实现:

#Vollath函数计算
def Vollath(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    u = np.mean(img)
    out = -shape[0]*shape[1]*(u**2)
    for x in range(0, shape[0]-1):
        for y in range(0, shape[1]):
            out+=int(img[x,y])*int(img[x+1,y])
    return out

熵函数

基于统计特征的熵函数是衡量图像信息丰富程度的一个重要指标,有信息论可知,一幅图像 f 的信息量是由该图像的信息熵 D(f) 来度量:

6b23998aa34f7ac54436177ee08a842a.png

其中:Pi 是图像中灰度值为i的像素出现的概率,L为灰度级总数(通常取值256)。根据Shannon信息论,熵最大时信息量最多。将此原理应用到对焦过程,D(f)越大则图像越清晰。熵函数灵敏度不高,依据图像内容不同容易出现与真实情况相反的结果。

python程序实现:

#entropy函数计算
def entropy(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    out = 0
    count = np.shape(img)[0]*np.shape(img)[1]
    p = np.bincount(np.array(img).flatten())
    for i in range(0, len(p)):
        if p[i]!=0:
            out-=p[i]*math.log(p[i]/count)/count
    return out

以上算法利用python实现,主要基于opencv,numpy, math库 ,以下是完整代码:

import cv2
import numpy as np
import math

#brenner梯度函数计算
def brenner(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(0, shape[0]-2):
        for y in range(0, shape[1]):
            out+=(int(img[x+2,y])-int(img[x,y]))**2
    return out

#Laplacian梯度函数计算
def Laplacian(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    return cv2.Laplacian(img,cv2.CV_64F).var()

#SMD梯度函数计算
def SMD(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(1, shape[0]-1):
        for y in range(0, shape[1]):
            out+=math.fabs(int(img[x,y])-int(img[x,y-1]))
            out+=math.fabs(int(img[x,y]-int(img[x+1,y])))
    return out

#SMD2梯度函数计算
def SMD2(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(0, shape[0]-1):
        for y in range(0, shape[1]-1):
            out+=math.fabs(int(img[x,y])-int(img[x+1,y]))*math.fabs(int(img[x,y]-int(img[x,y+1])))
    return out

#方差函数计算
def variance(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    out = 0
    u = np.mean(img)
    shape = np.shape(img)
    for x in range(0,shape[0]):
        for y in range(0,shape[1]):
            out+=(img[x,y]-u)**2
    return out

#energy函数计算
def energy(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    out = 0
    for x in range(0, shape[0]-1):
        for y in range(0, shape[1]-1):
            out+=((int(img[x+1,y])-int(img[x,y]))**2)*((int(img[x,y+1]-int(img[x,y])))**2)
    return out

#Vollath函数计算
def Vollath(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    shape = np.shape(img)
    u = np.mean(img)
    out = -shape[0]*shape[1]*(u**2)
    for x in range(0, shape[0]-1):
        for y in range(0, shape[1]):
            out+=int(img[x,y])*int(img[x+1,y])
    return out

#entropy函数计算
def entropy(img):
    '''
    :param img:narray 二维灰度图像
    :return: float 图像越清晰越大
    '''
    out = 0
    count = np.shape(img)[0]*np.shape(img)[1]
    p = np.bincount(np.array(img).flatten())
    for i in range(0, len(p)):
        if p[i]!=0:
            out-=p[i]*math.log(p[i]/count)/count
    return out

def main(img1, img2):
    print('Brenner',brenner(img1),brenner(img2))
    print('Laplacian',Laplacian(img1),Laplacian(img2))
    print('SMD',SMD(img1), SMD(img2))
    print('SMD2',SMD2(img1), SMD2(img2))
    print('Variance',variance(img1),variance(img2))
    print('Energy',energy(img1),energy(img2))
    print('Vollath',Vollath(img1),Vollath(img2))
    print('Entropy',entropy(img1),entropy(img2))

if __name__ == '__main__':
    #读入原始图像
    img1 = cv2.imread('./data/MotionL100H0_15.jpg')
    img2 = cv2.imread('./data/MotionL100H0_13.jpg')
    #灰度化处理
    img1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
    img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
    main(img1,img2)

c++实现请参考:

无参考图像的清晰度评价方法及c++实现 - 代码先锋网​www.codeleading.com

MATLAB实现请参考:

https://blog.csdn.net/kungfu_rabbit/article/details/90243838​blog.csdn.net

Reblur 二次模糊
如果一幅图像已经模糊了,那么再对它进行一次模糊处理,高频分量变化不大;但如果原图是清楚的,对它进行一次模糊处理,则高频分量变化会非常大。因此可以通过对待评测图像进行一次高斯模糊处理,得到该图像的退化图像,然后再比较原图像和退化图像相邻像素值的变化情况,根据变化的大小确定清晰度值的高低,计算结果越小表明图像越清晰,反之越模糊。这种思路可称作基于二次模糊的清晰度算法,其算法简化流程如下图:

7bc36b7b0879ccb6d7fb946a0fcee959.png

NRSS 梯度结构相似度

17238628e0d64bab1713185a73445401.png

python实现:

#encoding=utf-8
import cv2
import numpy as np
from skimage.measure import compare_ssim

def gauseBlur(img):
    img_Guassian = cv2.GaussianBlur(img,(7,7),0)
    return img_Guassian

def loadImage(filepath):
    img = cv2.imread(filepath, 0)  ##   读入灰度图
    return img
def showImage(img):
    cv2.imshow('image', img)
    cv2.waitKey(0)
def saveImage(path, img):
    cv2.imwrite(path, img)
def sobel(img):
    x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
    y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
    absX = cv2.convertScaleAbs(x)  # 转回uint8
    absY = cv2.convertScaleAbs(y)
    dst = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    return dst
def getBlock(G,Gr):
    (h, w) = G.shape
    G_blk_list = []
    Gr_blk_list = []
    sp = 6
    for i in range(sp):
        for j in range(sp):
            G_blk = G[int((i / sp) * h):int(((i + 1) / sp) * h), int((j / sp) * w):int(((j + 1) / sp) * w)]
            Gr_blk = Gr[int((i / sp) * h):int(((i + 1) / sp) * h), int((j / sp) * w):int(((j + 1) / sp) * w)]
            G_blk_list.append(G_blk)
            Gr_blk_list.append(Gr_blk)
    sum = 0
    for i in range(sp*sp):
        mssim = compare_ssim(G_blk_list[i], Gr_blk_list[i])
        sum = mssim + sum
    nrss = 1-sum/(sp*sp*1.0)
    print(nrss)
def NRSS(path):
    image = loadImage(path)
    #高斯滤波
    Ir = gauseBlur(image)
    G = sobel(image)
    Gr = sobel(Ir)
    blocksize = 8
    ## 获取块信息
    getBlock(G, Gr)
if __name__ == "__main__":
    filepath = "F:testpicnewblurtestclear3.jpg"
    NRSS(filepath)

传统的图像模糊检测主要存在以下缺点:

1.模糊界限难以确定,需要定一个阈值去区分(根据应用场景确定)。

2.众多的算法那个算法更适合,需要去验证。

针对传统算法也有一些机器学习和深度学习的方法去解决:

机器学习方法:

  1. 使用拉普拉斯滤镜在输入图像中查找边缘
  2. 计算方差和已过滤图像像素值的最大值
  3. 高方差(和高最大值)表明边缘清晰可见,即图像清晰。低方差表明图像模糊。
  4. 基于Laplace的特征的图,我们注意到我们的两类(模糊和非模糊)是线性可分离的,然后利用SVM进行

实现代码:

#计算laplace算子
import numpy as np 
from scipy.ndimage import variance
from skimage import io
from skimage.color import rgb2gray
from skimage.filters import laplace
from skimage.transform import resize

# Load image
path = f'test_data/0001.jpg'
img = io.imread(path)

# Resize image
img = resize(img, (400, 600))

# Grayscale image
img = rgb2gray(img)

# Edge detection
edge_laplace = laplace(img, ksize=3)

# Print output
print(f"Variance: {variance(edge_laplace)}")
print(f"Maximum : {np.amax(edge_laplace)}")
#利用SVM进行分类
import numpy as np

from sklearn import preprocessing, svm

# start with the results from the previous script
sharp_laplaces = [ (variance(edge_laplace_sharp_1), np.amax(edge_laplace_sharp_1)), ... ]
blurry_laplaces = [ (variance(edge_laplace_blurry_1), np.amax(edge_laplace_blurry_1)), ... ]

# set class labels (non-blurry / blurry) and prepare features
y = np.concatenate((np.ones((25, )), np.zeros((25, ))), axis=0)
laplaces = np.concatenate((np.array(sharp_laplaces), np.array(blurry_laplaces)), axis=0)

# scale features
laplaces = preprocessing.scale(laplaces)

# train the classifier (support vector machine)
clf = svm.SVC(kernel='linear', C=100000)
clf.fit(laplaces, y)

# print parameters
print(f'Weights: {clf.coef_[0]}')
print(f'Intercept: {clf.intercept_}')

# make sample predictions
clf.predict([[0.00040431, 0.1602369]])  # result: 0 (blurred)
clf.predict([[0.00530690, 0.7531759]])  # result: 1 (sharp)

深度学习方法:

针对模糊非模糊进行简单的二分类

数据集:

CERTH Image Blur Dataset - MKLab​mklab.iti.gr

方法参考:

priyabagaria/Image-Blur-Detection​github.com
133fd09b66746f97be942b722680c183.png

模糊区域检测,利用奇异值分解(SVD):

https://github.com/fled/blur_detection​github.com

参考:

[1].https://blog.csdn.net/Real_Myth/article/details/50827940

[2].https://medium.com/snapaddy-tech-blog/mobile-image-blur-detection-with-machine-learning-c0b703eab7de

[3].https://github.com/Leezhen2014/python--/blob/master/BlurDetection.py

  • 1
    点赞
  • 0
    评论
  • 7
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
<p> <span style="color:#337FE5;font-size:16px;">【课程简介】</span> </p> <p> <br /> </p> <p> <span style="font-size:14px;">本课程基于面向PythonOpenCV,以OpenCV官方文档知识脉络为主线,</span><span style="font-size:14px;">介绍了OpenCV函数具体使用方法、函数所使用算法具体原理。</span> </p> <p> <span style="font-size:14px;">在介绍函数使用时,提供了大量程序案例演示。</span> </p> <p> <span style="font-size:14px;">在介绍具体原理时,采用了通俗易懂语言和贴近生活示例来说明问题,尽量避免涉及过于复杂抽象公式。</span> </p> <p> <span style="font-size:14px;"> 课程包含数字图像处理常用知识点,覆盖面全,方便学员系统深入全面地掌握OpenCV。</span> </p> <p> <br /> </p> <p> <span style="font-size:16px;color:#337FE5;">【你将收获什么】</span> </p> <p> <span style="font-size:16px;color:#337FE5;"><span> </span></span> </p> <p align="left" class="ql-long-10663260 ql-align-left" style="font-size:11pt;color:#494949;"> <span style="font-size:14px;">1.  掌握数字图像在计算机内表示</span><span style="font-size:14px;"></span><span style="font-size:14px;">方法和处理基本原理。掌握数字图像表示方法是进行图像处理前提和基础,能够为后续智能图像处理打下坚实基础。</span> </p> <p align="left" class="ql-long-10663260 ql-align-left" style="font-size:11pt;color:#494949;"> <span style="font-size:14px;">2.  使用好OpenCV开源库对于提升工作效率具有很大帮助。OpenCV是优秀开源库,提供了大量函数帮助我们提升工作效率。大多数情况下,我们直接调用函数就能够满足我们需求。同时,它函数具有较好交互性,能够根据需要更好地掌控图像处理具体细节。</span> </p> <p class="ql-long-10663260" style="font-size:11pt;color:#494949;"> <span style="font-size:14px;">3.  学习图像处理常用算法。课程不仅介绍函数具体使用,也介绍了常用算法基本原理,帮助学习者更好地理解图像处理基本逻辑、方法,快速入门图像处理领域。</span> </p> <br /> <p> <br /> </p> <p> <span style="font-size:16px;color:#337FE5;">【我将如何教你】</span> </p> <p> <span style="font-size:14px;">1)在“黑盒”和“白盒“之间取得平衡</span> </p> <p> <span style="font-size:14px;"> </span><span style="font-size:14px;">可以将OpenCV看成“黑盒”,不用关心其函数是如何实现。在需要实现某一个功能时,直接调用其对应函数即可,像使用Photoshop各种功能一样。也可以将OpenCV看成“白盒”,关注其每一个函数具体实现,认真研究每一个函数具体实现方法和实现细节。这两种方式都是学习图像处理很好方式,但是大多数课程过于强调其中某一种,要么忽略了算法实现、要么忽略了使用方法。本课程尽量将OpenCV在“黑盒”和“白盒”之间取得平衡。既介绍算法原理和方法,又将重点放在如何调用函数上,让学习者能够更加游刃有余地在计算机视觉项目中使用OpenCV来解决具体问题。</span> </p> <p> <span style="font-size:14px;"><br /> </span> </p> <p> <span style="font-size:14px;">2)将枯燥算法采用具体案例介绍</span> </p> <p> <span style="font-size:14px;"> 在图像处理中,有大量算法保证了</span><span style="font-size:14px;">图像处理准确、高效。OpenCV将一些常用算法进行了封装,我们可以直接调用OpenCV函数来使用对应算法。但是,深入地理解算法能够帮助学习者更好地使用OpenCV函数。本课程尝试抛弃传统使用复杂公式介绍算法形式,尽量通过简单、通俗易懂生活中实例来帮助学习者理解算法基本逻辑</span> </p> <p> <span style="font-size:14px;"><br /> </span> </p> <p> <span style="font-size:14px;">3)案例驱动、强调实战</span> </p> <p> <span style="font-size:14px;">OpenCV是一个庞大资源库,提供了非常多函数帮助我们高效地处理问题。初学者使用OpenCV最大困惑就是熟练地掌握了每一个函数调用方法,但是在解决实际问题时,不知道具体应该使用哪个函数。本课程通过大量具体案例帮助学习快速掌握每个函数应用场景,快速掌握OpenCV核心使用方法和技巧。</span><br /> <span style="font-size:14px;"></span><span style="font-size:14px;"></span> </p>
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值