反向应用SVD(奇异值分解)算法检测显示屏缺陷(续)

《点绛唇·重楼》

酒入愁肠 一生惆怅情多少 纵横吟啸 思恋相萦绕

魔堕凡尘 难遣流年老 人间道 天涯芳草 依旧多情好

之前有一篇知乎,工作需要,实现论文《Automatic defect inspection for LCDs using singular value decomposition》中反向使用SVD算法检测屏幕缺陷。本文在论文作者的基础上,做了一些修改。

为了区别,本文章“论文作者”指该论文作者的观点和方法,“本文作者”为本篇文章作者;

前提内容见上一篇:反向应用SVD(奇异值分解)算法检测显示屏缺陷,链接如下:

反向应用SVD(奇异值分解)算法检测显示屏缺陷-CSDN博客

目录:

  • 算法修改点;
  • Python代码实现;

算法修改点

论文作者使用SVD算法分解得到图像的奇异值矩阵,并将包含图像主要特征的前k个较大的奇异值置零以过滤掉图像主要信息,保留包含图像缺陷特征的剩下所有的较小的奇异值,使用新的奇异值矩阵和左右奇异向量矩阵重构图片,新图片凸显原图缺陷信息,用于显示屏缺陷检测。

本文作者使用OLED显示屏的Mura缺陷照片进行测试,发现几个现象:

  1. 重构图片中,除了凸显出Mura缺陷外,还包含很多雪花状噪声
  2. 随着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

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千穹凌帝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值