目录
7.1 基于内容的图像检索
在大型图像数据库上,CBIR技术用于检索在视觉上具相似性的图像。在过去的几年里,研究者成功地引入文本挖掘技术到 CBIR 中处理问题,使在数百万图像中搜索具有相似内容的图像成为可能。
从文本挖掘中获取灵感------矢量空间模型
矢量空间模型是一个用于表示和搜索文本文档的模型。矢量包含了每个单词出现的次数,由于其忽略了单词出现的顺序及位置,该模型也被称为 BOW 表示模型。
最常用的权重是 tf-idf ( term frequency-inverse document frequency ,词频 - 逆向文
档频率 ) ,单词 w 在文档 d 中的 词频 是:
nw 是单词 w 在文档 d 中出现的次数。为了归一化,将 n w 除以整个文档中单词的总数。
逆向文档频率为:
|D| 是在语料库 D 中文档的数目,分母是语料库中包含单词 w 的文档数 d 。将两者
相乘可以得到矢量 v 中对应元素的 tf-idf 权重。
7.2 视觉单词
为了将文本挖掘技术应用到图像中,我们首先需要建立视觉等效单词;这通常可以 采用 2.2 节中介绍的 SIFT 局部描述子做到。它的思想是将描述子空间量化成一些典型实例,并将图像中的每个描述子指派到其中的某个实例中。这些典型实例可以通 过分析训练图像集确定,并被视为视觉单词。所有这些视觉单词构成的集合称为视觉词汇,有时也称为视觉码本。
利用一些聚类算法可以构建出视觉图像,搜索 聚类算法中最常用的是 K-means 1 ,这里也将采用 K-means 。
下面是关于聚类算法可以构建出视觉图像的实验:
实验代码:
python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import load_sample_image
# 加载样例图像
china = load_sample_image("china.jpg")
image = china / 255.0 # 归一化
# 将图像转换为二维数组
w, h, d = image.shape
image_array = image.reshape((w * h, d))
# 设置K-means参数
k = 16 # 选择16种颜色
kmeans = KMeans(n_clusters=k, random_state=0).fit(image_array)
# 将聚类结果应用于图像
segmented_img = kmeans.cluster_centers_[kmeans.labels_]
segmented_img = segmented_img.reshape((w, h, d))
# 绘制结果
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(image)
plt.subplot(1, 2, 2)
plt.title('Segmented Image')
plt.imshow(segmented_img)
plt.show()
分析:
- 使用
sklearn
的KMeans
来对图像进行聚类。 - 图像被转换为二维数组,以便K-means算法处理。
- 设定16种颜色(
k=16
)进行图像压缩。 - 聚类结果应用回图像中,得到每个像素的颜色对应其簇的中心颜色。
结果:
7.3 图像索引
在开始搜索之前,我们需要建立图像数据库和图像的视觉单词表示。
7.3.1 建立数据库
在索引图像前,我们需要建立一个数据库。这里,我们使用 SQLite 作为数据库。
python
import pickle
from pysqlite2 import dbapi2 as sqlite
class Indexer(object):
def __init__(self, db, voc):
""" 初始化数据库的名称及词汇对象 """
self.con = sqlite.connect(db)
self.voc = voc
def __del__(self):
""" 关闭数据库连接 """
self.con.close()
def db_commit(self):
""" 提交数据库事务 """
self.con.commit()
def create_tables(self):
""" 创建数据库表单及索引 """
self.con.execute('CREATE TABLE IF NOT EXISTS imlist (filename TEXT)')
self.con.execute('CREATE TABLE IF NOT EXISTS imwords (imid INTEGER, wordid INTEGER, vocname TEXT)')
self.con.execute('CREATE TABLE IF NOT EXISTS imhistograms (imid INTEGER, histogram BLOB, vocname TEXT)')
self.con.execute('CREATE INDEX IF NOT EXISTS im_idx ON imlist (filename)')
self.con.execute('CREATE INDEX IF NOT EXISTS wordid_idx ON imwords (wordid)')
self.con.execute('CREATE INDEX IF NOT EXISTS imid_idx ON imwords (imid)')
self.con.execute('CREATE INDEX IF NOT EXISTS imidhist_idx ON imhistograms (imid)')
self.db_commit()
python
from indexer import Indexer
if __name__ == "__main__":
# 创建词汇对象(在此示例中,我们将其设置为None,仅用于展示)
voc = None
# 指定数据库文件名称
db_name = 'example.db'
# 创建 Indexer 实例
indexer = Indexer(db_name, voc)
# 创建表单和索引
indexer.create_tables()
print(f"Database '{db_name}' and tables created successfully.")
创建完数据库后,查询表名以判断是否创建成功:
7.3.2 添加图像
有了数据库表单,我们便可以在索引中添加图像。为了实现该功能,我们需要在Indexer 类中添加 add_to_index() 方法。
下面是一个基本的实验代码示例,演示如何在数据库中添加图像,并进行分析和结果展示。
python
import sqlite3
import os
# 连接到数据库(如果数据库不存在,会自动创建)
conn = sqlite3.connect('images.db')
cursor = conn.cursor()
# 创建一个表用于存储图像
cursor.execute('''
CREATE TABLE IF NOT EXISTS image_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT,
data BLOB
)
''')
def insert_image(image_path):
# 读取图像文件并转换为二进制数据
with open(image_path, 'rb') as file:
img_data = file.read()
# 插入图像数据到数据库
cursor.execute('INSERT INTO image_data (name, data) VALUES (?, ?)',
(os.path.basename(image_path), img_data))
conn.commit()
def fetch_image(image_id, output_path):
# 从数据库中获取图像数据
cursor.execute('SELECT data FROM image_data WHERE id = ?', (image_id,))
img_data = cursor.fetchone()[0]
# 将图像数据写入文件
with open(output_path, 'wb') as file:
file.write(img_data)
# 实验操作
insert_image('1.jpg')
fetch_image(1, 'retrieved_image.jpg')
# 关闭数据库连接
分析:
-
创建表 :在数据库中创建一个
image_data
表用于存储图像数据。表中有两个字段:name
(图像名称)和data
(图像二进制数据)。 -
插入图像 :
insert_image
函数读取指定路径的图像文件,将其二进制数据插入到数据库中。 -
提取图像 :
fetch_image
函数从数据库中获取指定id
的图像数据,并将其保存为新文件。
结果:
7.4 在数据库中搜索图像
下面是在数据库中搜索图像的实验,image_data
表存储图像的元数据和图像文件本身(以 BLOB 格式存储)
实验代码:
python
import sqlite3
import io
from PIL import Image
# 连接到 SQLite 数据库
conn = sqlite3.connect('images.db')
cursor = conn.cursor()
# 查询图像(假设按名称搜索)
def search_image_by_name(image_name):
query = 'SELECT name, data FROM image_data WHERE name = ?'
cursor.execute(query, (image_name,))
result = cursor.fetchone()
if result:
img_name, img_data = result
# 将二进制数据转为图像对象
image = Image.open(io.BytesIO(img_data))
image.show() # 显示图像
return img_name, image
else:
print("Image not found.")
return None, None
# 示例搜索图像
image_name, image_obj = search_image_by_name('example_image.jpg')
# 关闭数据库连接
conn.close()
分析:
- 连接到数据库 :使用
sqlite3.connect
连接到 SQLite 数据库文件images.db
。 - 执行查询 :
search_image_by_name
函数接收一个图像名称作为参数,使用 SQL 查询从image_data
表中检索图像数据。?
是参数化查询的占位符,防止 SQL 注入。 - 处理图像数据 :
fetchone()
获取查询结果(假设结果只有一行)。io.BytesIO(img_data)
将图像的 BLOB 数据转换为字节流。Image.open
用于将字节流转换为图像对象,并使用show()
显示图像。
- 关闭连接:在操作完成后,关闭数据库连接。
结果:
表明从数据库中搜出次图像。
7.5 使用几何特性对结果排序
对图像进行几何特性排序通常涉及到提取图像的几何特征(如图像的面积、长宽比、边界框等),然后根据这些特征对图像进行排序。下面是一个示例,演示如何提取图像的几何特征并对图像进行排序。
实验代码:
python
import sqlite3
import io
import cv2
import numpy as np
from PIL import Image
# 连接到 SQLite 数据库
conn = sqlite3.connect('images.db')
cursor = conn.cursor()
# 查询所有图像数据
def fetch_all_images():
query = 'SELECT name, data FROM image_data'
cursor.execute(query)
return cursor.fetchall()
# 计算图像的几何特征(这里以面积为例)
def calculate_image_area(img_data):
# 将二进制数据转为图像对象
image = Image.open(io.BytesIO(img_data))
# 转为 OpenCV 格式
open_cv_image = np.array(image)
if len(open_cv_image.shape) == 3:
open_cv_image = cv2.cvtColor(open_cv_image, cv2.COLOR_RGB2GRAY) # 转为灰度图
# 计算图像的面积(即像素总数)
area = np.sum(open_cv_image > 0) # 计算非零像素的数量
return area
# 获取图像并按面积排序
def get_sorted_images_by_area():
images = fetch_all_images()
image_areas = []
for name, data in images:
area = calculate_image_area(data)
image_areas.append((name, area))
# 按面积排序
sorted_images = sorted(image_areas, key=lambda x: x[1], reverse=True)
return sorted_images
# 输出排序结果
sorted_images = get_sorted_images_by_area()
for name, area in sorted_images:
print(f"Image Name: {name}, Area: {area}")
# 关闭数据库连接
conn.close()
分析:
- 连接到数据库 :通过
sqlite3.connect
连接到 SQLite 数据库images.db
。 - 提取图像数据 :
fetch_all_images
函数从数据库中提取所有图像数据。 - 计算几何特征 :
calculate_image_area
函数将图像数据转换为 OpenCV 格式,然后计算图像的面积。我们将图像转换为灰度图,并计算非零像素的数量来估算面积。
- 排序图像 :
get_sorted_images_by_area
函数获取所有图像及其面积,并根据面积进行排序。 - 输出结果:打印每个图像的名称和计算出的面积
结果:
因为此数据库中是三张一样的图,所以显示相同。