文章目录

  • 一、环境准备
  • 二、数据集准备
  • 三、项目结构
  • 四、完整参考代码
  • imgCode/testUI3.py
  • imgCode/test2.py
  • 五、运行结果
  • 测试一:
  • 测试二
  • 六、参考链接


一、环境准备

需要安装:
pyqt5
pyqt5-tools

在终端中输入以下命令进行安装:

python 提取图像直方图数据 python提取图像特征代码_python

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

若想实现自行设计界面将界面转换为python文件功能,可以安装好包后参考这篇博文进行配置:

二、数据集准备

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

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

三、项目结构

python 提取图像直方图数据 python提取图像特征代码_python_02


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_())

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)

五、运行结果

测试一:

描述:上传一张存在于数据库中的人物的图像(上传的图片在数据库中没有完全相同的对应图像,只有与其相似的数张图像),检索后返回一张与上传图片最像(两者“距离”最小)的图片,表示在数据库中成功检索到该人物

样例一:

上传图片后界面显示:

python 提取图像直方图数据 python提取图像特征代码_算法_03


点击“开始检索”后界面:

python 提取图像直方图数据 python提取图像特征代码_python_04


可以看到成功检索到了该人物样例二:

python 提取图像直方图数据 python提取图像特征代码_算法_05


样例三:

python 提取图像直方图数据 python提取图像特征代码_python 提取图像直方图数据_06


可以看到都成功检索到了对应人物的图像

测试二

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

样例一:

上传图片后界面:

python 提取图像直方图数据 python提取图像特征代码_pyqt_07


点击“开始检索”后界面:

python 提取图像直方图数据 python提取图像特征代码_图像处理_08


可以看到在数据集中检索不到该人物,从控制台中输出可以看到上传的该图像与数据集中图像间最小“距离”大于阈值1200,因此判定为“检索不到”,显示“查无此人”

python 提取图像直方图数据 python提取图像特征代码_python_09


样例二:

python 提取图像直方图数据 python提取图像特征代码_算法_10


python 提取图像直方图数据 python提取图像特征代码_图像处理_11

六、参考链接

PyQt5环境搭建与基本使用

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

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

数据集下载

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

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