《点绛唇·重楼》
酒入愁肠 一生惆怅情多少 纵横吟啸 思恋相萦绕
魔堕凡尘 难遣流年老 人间道 天涯芳草 依旧多情好
之前有一篇知乎,工作需要,实现论文《Automatic defect inspection for LCDs using singular value decomposition》中反向使用SVD算法检测屏幕缺陷。本文在论文作者的基础上,做了一些修改。
为了区别,本文章“论文作者”指该论文作者的观点和方法,“本文作者”为本篇文章作者;
前提内容见上一篇:反向应用SVD(奇异值分解)算法检测显示屏缺陷,链接如下:
目录:
- 算法修改点;
- Python代码实现;
算法修改点
论文作者使用SVD算法分解得到图像的奇异值矩阵,并将包含图像主要特征的前k个较大的奇异值置零以过滤掉图像主要信息,保留包含图像缺陷特征的剩下所有的较小的奇异值,使用新的奇异值矩阵和左右奇异向量矩阵重构图片,新图片凸显原图缺陷信息,用于显示屏缺陷检测。
本文作者使用OLED显示屏的Mura缺陷照片进行测试,发现几个现象:
- 重构图片中,除了凸显出Mura缺陷外,还包含很多雪花状噪声;
- 随着k值的增大,当k值超过一个阈值后,重构图片中Mura缺陷将会消失;
论文作者将奇异值矩阵分为两部分,包含图像主要特征的较大奇异值和包含缺陷特征的较小奇异值。根据SVD的算法原理,较大奇异值包含图像主要特征,而较小奇异值包含噪声信息,即论文作者把缺陷特征和噪声特征归为一类。本文作者认为,重构图中的噪声信息对于缺陷检测会有影响,应该去除图像主要信息和噪声信息,只保留缺陷信息。
本文作者将奇异值矩阵分为3部分:包含图像主要特征的较大奇异值,包含缺陷特征的相对较大奇异值,包含噪声特征的较小奇异值,将较大奇异值和较小奇异值都置零,只保留相对较大奇异值,以此重构图像,在图像缺陷信息基础上同时做去噪处理。论文作者只设置了奇异值阈值上限,本文增加奇异值阈值下限。
Python代码实现
代码较为简单,在前篇的代码基础上略作修改,代码放在GitHub上,链接如下:
GitHub - tklk610/Sequel-of-Defect-detection-of-display-screen-by-SVD
代码分两部分,一个是使用SVD算法分解图片,并根据k值和l值重建奇异值矩阵,k值和l值可以根据奇异值自动计算或是人工设置,然后重构图片的模块。
def svd(src_path, tar_path, r, g) :
#print("path = %s" %(path))
for file in os.listdir(src_path) :
file_path = os.path.join(src_path, file)
if os.path.isdir(file_path):
os.list_dir(file_path)
else:
img = cv2.imread(file_path)
print(img.shape)
ch = img.shape[2]
print(ch)
if ch == 3: # color image with 3 channels
print("This is color image!")
image = img
for ch in range(3) :
img_index = img[:, :, ch]
U, sigma, VT = linalg.svd(img_index)
u_shape = U.shape[0]
vt_shape = VT.shape[0]
k, l = k_value(r, g, *sigma)
# k = 2 # set k and l value artificially
#
# l = 50
if k <0 :
raise Exception("k should lager than 0!", k)
if l <= k :
raise Exception("l should lager than K!", l, k)
# print(U.shape)
# print(sigma.shape)
# print(VT.shape)
sigma[0:k] = 0
#print(sigma)
new_sigma = np.zeros((u_shape, vt_shape))
index = u_shape if u_shape < vt_shape else vt_shape
index = l if l < index else index
print("index is %g" %(index))
for row in range(index) :
for col in range(index) :
if row == col :
new_sigma[row][col] = sigma[row]
print(new_sigma.shape)
# 重构矩阵
# dig = np.mat(np.eye(num) * sigma[:]) # 获得对角矩阵
# dim = data.T * U[:,:count] * dig.I # 降维
image[:, :, ch] = np.dot(np.dot(U[:, :], new_sigma), VT[:, :]) # 重构
print(image.shape)
new_file = file[:-4] + '_' + str(k) + '_' + str(l) + '.bmp'
#new_file = file[:-4] + '_' + str(k) + '_' + str(l) + '.tif'
#new_file = file[:-5] + '_' + str(k) + '_' + str(l) + '.tiff'
new_name = os.path.join(tar_path, new_file)
cv2.imwrite(new_name, image)
else : # gray image
print("This is gray image!")
U, sigma, VT = linalg.svd(img)
u_shape = U.shape[0]
vt_shape = VT.shape[0]
#k, l = k_value(r, sigma)
k = 17 # set k and l value artificially
l = 20
if k < 0:
raise Exception("k should lager than 0!", k)
if l <= k:
raise Exception("l should lager than K!", l, k)
# print(U.shape)
# print(sigma.shape)
# print(VT.shape)
sigma[0:k] = 0
new_sigma = np.zeros((u_shape, vt_shape))
index = u_shape if u_shape < vt_shape else vt_shape
index = l if l < index else index
for row in range(index):
for col in range(index):
if row == col:
new_sigma[row][col] = sigma[row]
print(new_sigma.shape)
image = np.dot(np.dot(U[:, :], new_sigma), VT[:, :]) # 重构
print(image.shape)
new_file = file[:-4] + '_' + str(k) + '.bmp'
new_file = file[:-4] + '_' + str(k) + '.tif'
#new_file = file[:-5] + '_' + str(k) + '.tiff'
new_name = os.path.join(tar_path, new_file)
cv2.imwrite(new_name, image)
src_path是原图存放地址,tar_path是结果图保存地址,r为计算k值时的σ'阈值,g为计算l值的σ'阈值。
另一部分是根据奇异值以及给定的阈值θ自动计算阈值k和l的模块,并将k和l传回主模块。
def k_value(r, g, *args) :
new = list(args)
mean = np.mean(new)
std = np.std(new, ddof = 1)
k, l = 0, 0
if r <= g:
raise Exception("r should lager than l!", r, g)
for i in range(len(new)) :
new[i] = (new[i] - mean) / std
sigma_date = []
num_data = []
for i in range(len(new)) :
if i == 0 :
pass
else :
sigma = new[i-1] - new[i]
#print(sigma)
sigma_date.append(sigma)
j = i-1
num_data.append(j)
plt.plot(num_data, sigma_date) # 绘制输入的结果和值的结果
plt.title("Sigma data", fontsize=15) # 标题
plt.xlabel("num", fontsize=15) # 横坐标
plt.ylabel("sigma", fontsize=15) # 纵坐标
plt.show() # 显示
#cv2.waitKey()
for i in range(len(sigma_date)) :
if sigma_date[i] <= r :
print("Singular value is %g,number is %g" %(sigma_date[i], i))
k = i
if sigma_date[i] >= g:
print("Singular value is %g,number is %g" % (sigma_date[i], i))
l = i
return k, l