【基于python的图像质量测试】ISO12233 eSFR MTF (一)

标准步骤

在这里插入图片描述

操作步骤

1,选择ROI
2,图像线性化转化为有效曝光(gamma反变换,将相机光电转换功能(OECF)转换为焦平面曝光或场景亮度的数字信号转换)
3,边缘位置估计

  • 3.1,计算每一行的一维导数(每行的ESF)
  • 3.2,计算每一行的边缘位置
  • 3.3,综合每一行图像计算拟合边缘位置的斜率和截距

4,边缘扩展函数ESF
5,线扩散函数LSF
6,傅里叶变换DFT

步骤详解

一、选择ROI

请添加图片描述

  • 水平方向斜边
  • 左暗右亮

引入我所用到的包

import cv2
from matplotlib.lines import lineStyles
import numpy as np
import matplotlib.pyplot as plt

导入图像

img = cv2.imread(r"C:\Users\Thinkpad\Desktop\123.jpg")
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#使用灰度图像

二、线性化处理

gamma变换公式:
O = c ∗ I γ O=c*I^γ O=cIγ

  • O:输出灰度级别
  • I:输入灰度级别
  • c:参数
  • γ:调整参数,较小时降低对比度,较高时增加对比度

根据定义,线性化即为将图像还原
我这边简化了操作,把系数c设为1,那么将上面的输出O代入下面的公式
推导线性化公式即为:
L u m i n a n c e = O 1 / γ = ( I γ ) 1 / γ = I Luminance = O^{1/γ}=(I^γ)^{1/γ}=I Luminance=O1/γ=(Iγ)1/γ=I
不确定这线性化公式对不对,没有找到相关资料

def luminance_trance(image,gamma = 0.5):#这个gamma是可调整的,通常设为0.5左右
    return np.power(image,1/gamma)
img_lum = luminance_trance(gray)
cv2.imshow("img_correct ",img_lum )
cv2.waitKey(0)

得到的图像结果:

三、边缘位置估计

边缘位置公式贴图:
求导

3.1 计算每一行的一维导数

对于得到的阵列中的每一行像素,线性化图像数据的导数是使用有限冲激响应(FIR)滤波器。结果是一个数组,它的大小与输入ROI大小相同。该导数矩阵的一维质心是逐行计算的,以确定每一条线上的边的位置。
将上述公式进行步骤拆分,先进行求导:
Φ ( p + 1 , r ) − Φ ( p , r ) Φ(p+1,r)-Φ(p,r) Φ(p+1,r)Φ(p,r)
这里对于这个公式的使用我找到了不同的版本,基本是基于不同的滤波器,
当滤波器为[-1,1],将滤波器应用到每一行像素

这里介绍python函数:
np.diff()☞函数用法
这是个用于计算差分的函数,对于一维数组的差分则近似于求导

h,w = gray.shape#获取图像的高和宽
for i in range(h):#逐行求导
    single_row= img_lum[i].astype(int)#因为差分后会出现负数,所以将uint8转化为int
    diff_row = np.diff(single_row)
    hamming_window_1 = np.hamming(len(diff_row))#汉明窗
    diff_row = diff_row*hamming_window_1#将每一行的数据进行汉明滤波

当系数Φ=1/2,即滤波器为[-1/2,1/2]时np.diff()将不再实用,这里我没有找到合适的函数,尝试使用如下函数:
np.convolve()☞函数用法
这是一个处理卷积的函数
根据离散线性卷积的步骤,该函数会对卷积核做180度反转,然后再进行滑动滤波。因此,当滤波器为[-1/2,1/2]时,卷积核即为[1/2,-1/2]

kernel = np.array([0.5,-0.5])
for i in range(h):
    single_row= img_lum[i].astype(int)#因为差分后会出现负数,所以将uint8转化为int
    #diff_row = np.diff(single)
    diff_row = np.convolve(single_row,kernel,mode="valid")#自定义的求导
    hamming_window_1 = np.hamming(len(diff_row))#汉明窗
    diff_row = diff_row*hamming_window_1#将每一行的数据进行汉明滤波

在上述的方法中,我不仅进行了求导,还应用了汉明窗滤波

下面展示的时两种求导方式以及运用汉明窗的区别

[-1,1]滤波求导:

求导和汉明窗

[-1/2,1/2]滤波求导

求导和汉明窗
这里提一嘴汉明窗☞内容参考
在ISO12233:2017标准中使用的是汉明窗,而ISO12233:2023标准中使用的是海宁窗
区别参见下图
汉明海宁

3.2,计算每一行的边缘位置

每一行的边缘位置即为一阶导数的矩心
贴图公式简化为:
c ( r ) = ∑ p = 1 p p ∗ d i f f ( p , r ) ∑ p = 1 p d i f f ( p , r ) c(r)=\frac{ \sum_{p=1}^p p*diff(p,r)} {\sum_{p=1}^p diff(p,r)} c(r)=p=1pdiff(p,r)p=1ppdiff(p,r)
其中diff即为上面求的导数
设置两个列表x = [],y= []分别存入边缘点横坐标和纵坐标,这里我使用[-1/2,1/2]滤波+汉明窗。
接之前的代码:

kernel = np.array([-0.5,0.5])
x = []
y = []
for i in range(h):
    single_row= img_lum[i].astype(int)#因为差分后会出现负数,所以将uint8转化为int
    #diff_row = np.diff(single)
    diff_row = np.convolve(single_row,kernel,mode="valid")#自定义的求导
    hamming_window_1 = np.hamming(len(diff_row))#汉明窗
    diff_row = diff_row*hamming_window_1#将每一行的数据进行汉明滤波
    dt1 = np.sum(diff_row)
    dt = result = np.sum(diff_row * (np.arange(len(diff_row))+1))#每个元素*(元素索引+1),因为索引从0开始所以需要+1
    shift = dt/dt1
    x.append(int(shift))
    y.append(i)

x,y中存放的是所有边缘点的合集

3.3,综合每一行图像计算拟合边缘位置的斜率和截距

在获得xy组成的坐标集合后,使用最小二乘法拟合直线
斜率 b = ∑ i = 1 n ( x [ i ] − a v e r a g e ( x ) ) ∗ ( y [ i ] − a v e r a g e ( y ) ) ∑ i = 1 n ( x [ i ] − a v e r a g e ( x ) ) 2 斜率b = \frac{\sum_{i=1}^n (x[i]-average(x))*(y[i]-average(y))}{\sum_{i=1}^n(x[i]-average(x))^2} 斜率b=i=1n(x[i]average(x))2i=1n(x[i]average(x))(y[i]average(y))
截距 a = a v e r a g e ( y ) − b ∗ a v e r a g e ( x ) 截距a=average(y) - b*average(x) 截距a=average(y)baverage(x)
python有现成的公式np.polyfit()☞函数参考
获得的直线代码及直线效果图,x,y为前面获取的点坐标合集

coefficients = np.polyfit(x, y, 1)#线的拟合
slope = coefficients[0]#斜率
intercept = coefficients[1]#截距

cv2.line(img,(0,int(intercept)),(int(-intercept/slope),0),(0,0,255),2)#这个方法在斜率为正时画出的线段将不可见
cv2.imshow("2",img)
cv2.waitKey(0)

红色为拟合直线:
在这里插入图片描述

未完待续。。。

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值