• 数字图像处理课程实验 基于颜色布局描述符(CLD)图像特征提取算法使用Python实现简单的人脸检测功能并使用PyQt5构建简单的功能界面


    一、环境准备

    需要安装:
    pyqt5
    pyqt5-tools

    在终端中输入以下命令进行安装:
    在这里插入图片描述

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyqt5
    
    • 1
    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyqt5-tools
    
    • 1

    若想实现自行设计界面将界面转换为python文件功能,可以安装好包后参考这篇博文进行配置:
    https://www.cnblogs.com/lovesoo/p/12491361.html

    二、数据集准备

    实验所需数据集可从这里下载http://www.vision.caltech.edu/datasets/(需要科学上网)
    下载到对应的人脸数据集后需要将图片从0-n重命名并修改代码中相关参数

    若需要处理好后的数据集可私信我或从我上传的资源中下载:
    数字图像处理Python+PyQt5实现基于CLD算法的人脸检测源码+数据集

    三、项目结构

    在这里插入图片描述
    image_org为人脸数据集存放位置
    test2为CLD及相关算法函数实现
    testUI3为PyQt5实现的界面代码及图像检索功能相关代码

    四、完整参考代码

    imgCode/testUI3.py

    # -*- coding: utf-8 -*-
    import cv2
    from PyQt5 import QtCore, QtGui, QtWidgets
    from PyQt5.QtWidgets import QFileDialog, QApplication
    
    import test2 as t2
    
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(775, 721)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
    
            self.pushButton_openImage = QtWidgets.QPushButton(self.centralwidget)
            self.pushButton_openImage.setGeometry(QtCore.QRect(70, 260, 93, 28))
            self.pushButton_openImage.setObjectName("pushButton_openImage")
    
            self.label_image = QtWidgets.QLabel(self.centralwidget)
            self.label_image.setGeometry(QtCore.QRect(200, 50, 321, 231))
            self.label_image.setFrameShape(QtWidgets.QFrame.Box)
            self.label_image.setObjectName("label_image")
            self.label_image.setScaledContents(True)  # 图片填充整个框
    
            self.pushButton_saveImage = QtWidgets.QPushButton(self.centralwidget)
            self.pushButton_saveImage.setGeometry(QtCore.QRect(70, 350, 93, 28))
            self.pushButton_saveImage.setObjectName("pushButton_saveImage")
    
            self.label_txt = QtWidgets.QLabel(self.centralwidget)
            self.label_txt.setGeometry(QtCore.QRect(200, 350, 321, 231))
            self.label_txt.setFrameShape(QtWidgets.QFrame.Box)
            self.label_txt.setObjectName("label_txt")
            self.label_txt.setScaledContents(True)  # 图片填充整个框
    
            self.label_imagePath = QtWidgets.QLabel(self.centralwidget)
            self.label_imagePath.setGeometry(QtCore.QRect(570, 60, 150,100))
            self.label_imagePath.setObjectName("label_imagePath")
            self.label_imagePath.setWordWrap(True)
    
            MainWindow.setCentralWidget(self.centralwidget)
    
            self.menubar = QtWidgets.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 775, 26))
            self.menubar.setObjectName("menubar")
    
            MainWindow.setMenuBar(self.menubar)
    
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
    
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
            self.pushButton_openImage.clicked.connect(self.openImage)
            self.pushButton_saveImage.clicked.connect(self.findImage)
    
    
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
            self.pushButton_openImage.setText(_translate("MainWindow", "上传图像"))
            self.label_image.setText(_translate("MainWindow", "待检索图像"))
            self.pushButton_saveImage.setText(_translate("MainWindow", "开始检索"))
            # self.pushButton_openFile.setText(_translate("MainWindow", "打开文件"))
            self.label_txt.setText(_translate("MainWindow", "检索到的图片(若找不到,显示“查无此人”)"))
            self.label_imagePath.setText(_translate("MainWindow", "图片路径"))
    
        def openImage(self):  # 选择本地图片上传
            global imgName  # 这里为了方便别的地方引用图片路径,我们把它设置为全局变量
            imgName, imgType = QFileDialog.getOpenFileName(self.centralwidget, "打开图片", "", "*.jpg;;*.png;;All Files(*)")    # 弹出一个文件选择框,第一个返回值imgName记录选中的文件路径+文件名,第二个返回值imgType记录文件的类型
            jpg = QtGui.QPixmap(imgName).scaled(self.label_image.width(), self.label_image.height())  # 通过文件路径获取图片文件,并设置图片长宽为label控件的长宽
            self.label_image.setPixmap(jpg)  # 在label控件上显示选择的图片
            self.label_imagePath.setText(imgName)  # 显示所选图片的本地路径
    
    
        def findImage(self):
            img = cv2.imread(imgName)  # 这里就是读取0.jpg
            img = cv2.resize(img, (256, 384))
    
            CLD_img1 = t2.CLD(img)  # 对img进行CLD处理
            cld_index = []
            cld_img = []
            cld_class = []
            cld_new_class = []
    
            # {坐标:距离}
            dict = {}
            for i in range(0, 432):
                img2 = cv2.imread('.\\image_org\\faces\\%d.jpg' % (i))
                img2 = cv2.resize(img2, (256, 384))
    
                CLD_img2 = t2.CLD(img2)
                distances = t2.distance_CLD(CLD_img1, CLD_img2)
    
                dict[i] = distances
    
            dict_sorted = sorted(dict.items(), key=lambda kv: (kv[1], kv[0]))
    
            print(dict_sorted)
            print(type(dict_sorted))  # list
            print(dict_sorted[0][0])
            print(type(dict_sorted[0][0]))
            img_out_index = str(dict_sorted[0][0])
    
            if dict_sorted[0][1] >= 1200:
                print("查无此人")
                self.label_txt.setText("查无此人")
            else:
                img_path = './image_org/faces/' + img_out_index + '.jpg'
    
                jpg = QtGui.QPixmap(img_path).scaled(self.label_image.width(),
                                                    self.label_image.height())  # 通过文件路径获取图片文件,并设置图片长宽为label控件的长宽
                self.label_txt.setPixmap(jpg)
    
        # def saveImage(self):  # 保存图片到本地
        #     screen = QApplication.primaryScreen()
        #     pix = screen.grabWindow(self.label_image.winId())
        #     fd,type= QFileDialog.getSaveFileName(self.centralwidget, "保存图片", "", "*.jpg;;*.png;;All Files(*)")
        #     print(fd)
        #     # pix.save(fd)
    
        # def openDirectory(self):  # 打开文件夹(目录)
        #     fd = QFileDialog.getExistingDirectory(self.centralwidget, "选择文件夹", "")
        #     self.label_directoryPath.setText(fd)
    
        # def openTextFile(self):  # 选择文本文件上传
        #     fd,fp = QFileDialog.getOpenFileName(self.centralwidget, "选择文件", "", "*.txt;;All Files(*)")
        #     f=open(fd,'r')
        #     self.label_txt.setText(f.read())
        #     self.label_filePath.setText(fd)
        #     f.close()
    
        # def saveTextFile(self):  # 保存文本文件
        #     fd,fp= QFileDialog.getSaveFileName(self.centralwidget, "保存文件", "", "*.txt;;All Files(*)")
        #     f=open(fd,'w')
        #     f.write(self.label_txt.text())
        #     f.close()
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        formObj = QtWidgets.QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(formObj)
        formObj.show()
        sys.exit(app.exec_())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148

    imgCode/test2.py

    # coding: utf-8
    
    # In[1]:
    
    
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    import pandas as pd
    from scipy.fftpack import dct
    import redis
    
    # In[2]:
    
    
    def cvshow(name, img):
        cv2.imshow(name, img)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    
    
    # In[3]:
    
    
    def CLD(img):
        # 图像分割8*8
        n = 8
    
        (height, width, channel) = img.shape
        # print(height,width,channel) #384 256 3
    
        block_h = np.fix(height / n)  # 每块的高度
        block_w = np.fix(width / n)  # 每块的宽度
        # print(block_h,block_w) # 48.0 32.0
    
        im_n = np.zeros((n, n, channel))
    
        for i in range(n):
            for j in range(n):
                for k in range(channel):
                    # 确定块
                    a = block_h * i + 1
                    b = block_h * (i + 1)  # height: b-a
                    c = block_w * j + 1
                    d = block_w * (j + 1)  # width: d-c
                    # 循环到右下角的块时
                    if i == (n - 1):
                        b = height - 1
                    if j == (n - 1):
                        d = width - 1
                    # 每块代表色的选择,实现“mpeg-7标准推荐使用区域块的平均像素颜色值作为代表颜色”
                    # print(img[int(a)][int(d)][int(k)])
    
                    arr = [img[int(a)][int(c)][k], img[int(a)][int(d)][k], img[int(b)][int(c)][k], img[int(b)][int(d)][k]]
    
                    pix = np.mean(np.mean(arr));
                    # print(pix)
                    im_n[i][j][k] = pix
                    # print(im_n)
    
        # 将rgb转换色彩空间为YCbCr
        mat = np.array(
            [[65.481, 128.553, 24.966],
             [-37.797, -74.203, 112.0],
             [112.0, -93.786, -18.214]])
        offset = np.array([16, 128, 128])
    
        # rgb2ycbcr():颜色空间转换的函数
        im_YCbCr = rgb2ycbcr(mat, offset, im_n)
    
        # DCT变换
        im_DCT = np.zeros((n, n, channel));
        # 因为dct操作只能对二维矩阵进行操作,所以这里要把r,g,b分别拎出来处理
        im_DCT[:, :, 0] = dct(im_YCbCr[:, :, 0])
        im_DCT[:, :, 1] = dct(im_YCbCr[:, :, 1])
        im_DCT[:, :, 2] = dct(im_YCbCr[:, :, 2])
        # print(im_DCT)
    
        # 按照之字形扫描im_DCT存储到descript中
        zig = [[0, 1, 5, 6, 14, 15, 27, 28],
               [2, 4, 7, 13, 16, 26, 29, 42],
               [3, 8, 12, 17, 25, 30, 41, 43],
               [9, 11, 18, 24, 31, 40, 44, 53],
               [10, 19, 23, 32, 39, 45, 52, 54],
               [20, 22, 33, 38, 46, 51, 55, 60],
               [21, 34, 37, 47, 50, 56, 59, 61],
               [35, 36, 48, 49, 57, 58, 62, 63]]
        descript = np.zeros((n * n, channel));
        for i in range(n):
            for j in range(n):
                descript[zig[i][j], :] = im_DCT[i, j, :];
                # print(descript);
    
        result = descript;
        return result;
    
    
    # In[4]:
    
    
    # 颜色空间转换的函数
    def rgb2ycbcr(mat, offset, rgb_img):
        n = 8
        channel = 3
        ycbcr_img = np.zeros((n, n, channel))
        for x in range(n):
            for y in range(n):
                ycbcr_img[x, y, :] = np.round(np.dot(mat, rgb_img[x, y, :] * 1.0 / 255) + offset)
        return ycbcr_img
    
    
    # In[5]:
    
    
    def distance_CLD(img1, img2):
        return np.sqrt(np.sum(np.square(img1 - img2)))  # 欧式距离
    
    
    # In[6]:
    
    
    def drawline(recall, precision):
        plt.plot(recall, precision)
        plt.xlabel("recall")
        plt.ylabel("precision")
        plt.title('PR Graph of CLD')
        plt.show()
    
    
    # In[7]:
    
    
    if __name__ == "__main__":
    
        img_index = 60;  # 设置样本img的编号
        img = cv2.imread('./image_org/faces/' + str(img_index) + '.jpg')  # 这里就是读取0.jpg
    
    
        CLD_img1 = CLD(img)  # 对img进行CLD处理
    
        cld_index = []
        cld_img = []
        cld_class = []
        cld_new_class = []
    
        # {坐标:距离}
        dict = {}
        for i in range(0, 432):
    
            img2 = cv2.imread('.\\image_org\\faces\\%d.jpg' % (i))
            img2 = cv2.resize(img2, (256, 384))
    
            CLD_img2 = CLD(img2)
    
            distances = distance_CLD(CLD_img1, CLD_img2)
    
            dict[i] = distances
    
        dict_sorted = sorted(dict.items(), key=lambda kv: (kv[1], kv[0]))
    
    
        print(dict_sorted)
        print(type(dict_sorted)) # list
        print(dict_sorted[0][0])
        print(type(dict_sorted[0][0]))
        img_out_index = str(dict_sorted[0][0])
    
        if dict_sorted[0][1]>=1200:
            print("查无此人")
        else:
            img_out = cv2.imread('./image_org/faces/' + img_out_index + '.jpg')
            cvshow("img",img_out)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173

    五、运行结果

    测试一:

    描述:上传一张存在于数据库中的人物的图像(上传的图片在数据库中没有完全相同的对应图像,只有与其相似的数张图像),检索后返回一张与上传图片最像(两者“距离”最小)的图片,表示在数据库中成功检索到该人物
    样例一:
    上传图片后界面显示:
    在这里插入图片描述
    点击“开始检索”后界面:
    在这里插入图片描述
    可以看到成功检索到了该人物

    样例二:
    在这里插入图片描述
    样例三:
    在这里插入图片描述
    可以看到都成功检索到了对应人物的图像

    测试二

    描述:上传一张不存在于数据库中的人物的图像,检索后若找不到则会显示“查无此人”,表示在数据库中检索不到该人物(本程序中阈值设置为1200,即通过计算后上传的图片与数据库中图片的最小距离若大于 1200,则认为该上传图像对应的人物不存在于数据库中,显示“查无此人”)

    样例一:
    上传图片后界面:
    在这里插入图片描述
    点击“开始检索”后界面:
    在这里插入图片描述
    可以看到在数据集中检索不到该人物,从控制台中输出可以看到上传的该图像与数据集中图像间最小“距离”大于阈值1200,因此判定为“检索不到”,显示“查无此人”
    在这里插入图片描述
    样例二:
    在这里插入图片描述
    在这里插入图片描述

    六、参考链接

    PyQt5环境搭建与基本使用

    pyqt5:利用QFileDialog从本地选择图片\文本文档显示到label、保存图片\label文本到本地(附代码)

    图像特征提取算法:颜色布局描述符Color Layout Descriptor

    数据集下载

    计算机视觉 实验四 分别使用颜色布局描述符(Color Layout Descriptor)与方向梯度直方图(HOG)实现图像检索,并且画出图像的PR曲线图

    本文章相关源代码与处理好的人脸数据集:数字图像处理Python+PyQt5实现基于CLD算法的人脸检测源码+数据集

  • 相关阅读:
    idea启动项目很久很慢的一种解决方案
    ArrayBlockingQueue
    MySQL数据库开发设计规范总结
    计算机毕业设计之java+ssm王道考研购物网站
    pandas分组与聚合groupby()函数详解
    MySQL 存储过程和函数
    腾讯云短信使用
    SpringBoot框架Mockito的使用
    安卓开发FirstDay
    KVM
  • 原文地址:https://blog.csdn.net/GCTTTTTT/article/details/127660091