在学习时:http://python.jobbole.com/80860/
在这里对上面给出的链接中的代码进行整理和修改了下,图像搜索的原理,以及搜索的大致步骤和想法,在原博主文章中已经讲解的很详细了,在这里我就不写了,对于上面链接中的代码,有些地方是需要改动的
先贴出我的代码:
直接上代码:
color_descriptor.py
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2018/11/6 15:17
# @Author : xhh
# @Desc : 颜色空间特征提取器
# @File : color_descriptor.py
# @Software: PyCharm
import cv2
import numpy
class ColorDescriptor:
__slot__ = ["bins"]
def __init__(self, bins):
self.bins = bins
# 得到图片的色彩直方图,mask为图像处理区域的掩模
def getHistogram(self, image, mask, isCenter):
# 利用OpenCV中的calcHist得到图片的直方图
imageHistogram = cv2.calcHist([image], [0, 1, 2], mask, self.bins, [0, 180, 0, 256, 0, 256])
# 标准化(归一化)直方图normalize
imageHistogram = cv2.normalize(imageHistogram, imageHistogram).flatten()
# isCenter判断是否为中间点,对色彩特征向量进行加权处理
if isCenter:
weight = 5.0 # 权重记为0.5
for index in range(len(imageHistogram)):
imageHistogram[index] *= weight
return imageHistogram
# 将图像从BGR色彩空间转换为HSV色彩空间
def describe(self, image):
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
features = []
# 获取图片的中心点和图片的大小
height, width = image.shape[0], image.shape[1]
centerX, centerY = int(width * 0.5), int(height * 0.5)
# initialize mask dimension
# 生成左上、右上、左下、右下、中心部分的掩模。
# 中心部分掩模的形状为椭圆形。这样能够有效区分中心部分和边缘部分,从而在getHistogram()方法中对不同部位的色彩特征做加权处理。
segments = [(0, centerX, 0, centerY), (0, centerX, centerY, height), (centerX, width, 0, centerY), (centerX, width, centerY, height)]
# 初始化中心部分
axesX, axesY = int(width * 0.75) / 2, int (height * 0.75) / 2
ellipseMask = numpy.zeros([height, width], dtype="uint8")
cv2.ellipse(ellipseMask, (int(centerX), int(centerY)), (int(axesX), int(axesY)), 0, 0, 360, 255, -1)
#cv2.ellipse(ellipMask, (int(cX), int(cY)), (int(axesX), int(axesY)), 0, 0, 360, 255, -1)
# 初始化边缘部分
for startX, endX, startY, endY in segments:
cornerMask = numpy.zeros([height, width], dtype="uint8")
cv2.rectangle(cornerMask, (startX, startY), (endX, endY), 255, -1)
cornerMask = cv2.subtract(cornerMask, ellipseMask)
# 得到边缘部分的直方图
imageHistogram = self.getHistogram(image, cornerMask, False)
features.append(imageHistogram)
# 得到中心部分的椭圆直方图
imageHistogram = self.getHistogram(image, ellipseMask, True)
features.append(imageHistogram)
# 得到最终的特征值
return features
structure_descriptor.py
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2018/11/6 15:18
# @Author : xhh
# @Desc : 构图空间提取器
# @File : structure_descriptor.py
# @Software: PyCharm
import cv2
# 将图片进行归一化处理,返回HSV色彩空间矩阵
class StructureDescriptor:
__slot__ = ["dimension"]
def __init__(self, dimension):
self.dimension = dimension
def describe(self, image):
image = cv2.resize(image, self.dimension, interpolation=cv2.INTER_CUBIC)
# 将图片转化为BGR图片转化为HSV格式
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# print(image)
return image
searchEngine.py
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2018/11/6 15:21
# @Author : xhh
# @Desc :
# @File : searchEngine.py
# @Software: PyCharm
import color_descriptor
import structure_descriptor
import searcher
import argparse
import cv2
# 构造解析函数
searchArgParser = argparse.ArgumentParser()
searchArgParser.add_argument("-c", "--colorindex", required = True, help = "Path to where the computed color index will be stored")
searchArgParser.add_argument("-s", "--structureindex", required = True, help = "Path to where the computed structure index will be stored")
searchArgParser.add_argument("-q", "--query", required=True, help = "Path to the query image")
searchArgParser.add_argument("-r", "--resultpath", required = True, help = "Path to the result path")
searchArguments = vars(searchArgParser.parse_args())
idealBins = (8, 12, 3)
idealDimension = (16, 16)
# 传入色彩空间的bins
colorDescriptor = color_descriptor.ColorDescriptor(idealBins)
# 传入构图空间的bins
structureDescriptor = structure_descriptor.StructureDescriptor(idealDimension)
queryImage = cv2.imread(searchArguments["query"])
colorIndexPath = searchArguments["colorindex"]
structureIndexPath = searchArguments["structureindex"]
resultPath = searchArguments["resultpath"]
queryFeatures = colorDescriptor.describe(queryImage)
queryStructures = structureDescriptor.describe(queryImage)
imageSearcher = searcher.Searcher(colorIndexPath, structureIndexPath)
searchResults = imageSearcher.search(queryFeatures, queryStructures)
# 对搜索到的图片进行展示
for imageName, score in searchResults:
queryResult = cv2.imread(resultPath + "/" + imageName)
cv2.imshow("Result Score: " + str(int(score)) + " (lower is better)", queryResult)
cv2.waitKey(0)
cv2.imshow("Query", queryImage)
cv2.waitKey(0)
index.py
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2018/11/6 15:20
# @Author : xhh
# @Desc :
# @File : index.py
# @Software: PyCharm
import color_descriptor
import structure_descriptor
import glob
import argparse
import cv2
# 创建解析函数
searchArgParser = argparse.ArgumentParser()
searchArgParser.add_argument("-d", "--dataset", required = True, help = "Path to the directory that contains the images to be indexed")
searchArgParser.add_argument("-c", "--colorindex", required = True, help = "Path to where the computed color index will be stored")
searchArgParser.add_argument("-s", "--structureindex", required = True, help = "Path to where the computed structure index will be stored")
arguments = vars(searchArgParser.parse_args())
idealBins = (8, 12, 3)
colorDesriptor = color_descriptor.ColorDescriptor(idealBins)
output = open(arguments["colorindex"], "w")
# 色彩空间的特征存储
for imagePath in glob.glob(arguments["dataset"] + "/*.png"):
imageName = imagePath[imagePath.rfind("\\") + 1 : ] # 这里也是需要修改的
image = cv2.imread(imagePath)
features = colorDesriptor.describe(image)
# 将色彩空间的特征写入到csv文件中去
features = [str(feature).replace("\n", "") for feature in features]
output.write("%s,%s\n" % (imageName, ",".join(features)))
# close index file
output.close()
idealDimension = (16, 16)
structureDescriptor = structure_descriptor.StructureDescriptor(idealDimension)
output = open(arguments["structureindex"], "w")
# 构图空间的色彩特征存储
for imagePath in glob.glob("dataset" + "/*.png"):
# imageName = imagePath[imagePath.rfind("/") + 1 : ] # 这里是需要修改的
imageName = imagePath[imagePath.rfind("\\") + 1 : ]
image = cv2.imread(imagePath)
structures = structureDescriptor.describe(image)
# 将构图空间的色彩特征写入到文件中去 write structures to file
structures = [str(structure).replace("\n", "") for structure in structures]
output.write("%s,%s\n" % (imageName, ",".join(structures)))
# close index file
output.close()
searcher.py
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# @Time : 2018/11/6 15:19
# @Author : xhh
# @Desc : 图片搜索内核
# @File : searcher.py
# @Software: PyCharm
import numpy
import csv
import re
class Searcher:
# colorIndexPath色彩空间特征索引表路径,structureIndexPath结构特征索引表路径
__slot__ = ["colorIndexPath", "structureIndexPath"]
def __init__(self, colorIndexPath, structureIndexPath):
self.colorIndexPath, self.structureIndexPath = colorIndexPath, structureIndexPath
# 计算色彩空间的距离,卡方相似度计算
def solveColorDistance(self, features, queryFeatures, eps = 1e-5):
distance = 0.5 * numpy.sum([((a - b) ** 2) / (a + b + eps) for a, b in zip(features, queryFeatures)])
return distance
# 计算构图空间的距离
def solveStructureDistance(self, structures, queryStructures, eps = 1e-5):
distance = 0
normalizeRatio = 5e3
for index in range(len(queryStructures)):
for subIndex in range(len(queryStructures[index])):
a = structures[index][subIndex]
b = queryStructures[index][subIndex]
distance += (a - b) ** 2 / (a + b + eps)
return distance / normalizeRatio
def searchByColor(self, queryFeatures):
searchResults = {}
with open(self.colorIndexPath) as indexFile:
reader = csv.reader(indexFile)
for line in reader:
features = []
for feature in line[1:]:
feature = feature.replace("[", "").replace("]", "")
findStartPosition = 0
feature = re.split("\s+", feature)
rmlist = []
for index, strValue in enumerate(feature):
if strValue == "":
rmlist.append(index)
for _ in range(len(rmlist)):
currentIndex = rmlist[-1]
rmlist.pop()
del feature[currentIndex]
feature = [float(eachValue) for eachValue in feature]
features.append(feature)
distance = self.solveColorDistance(features, queryFeatures)
searchResults[line[0]] = distance
indexFile.close()
# print "feature", sorted(searchResults.iteritems(), key = lambda item: item[1], reverse = False)
return searchResults
def transformRawQuery(self, rawQueryStructures):
queryStructures = []
for substructure in rawQueryStructures:
structure = []
for line in substructure:
for tripleColor in line:
structure.append(float(tripleColor))
queryStructures.append(structure)
return queryStructures
def searchByStructure(self, rawQueryStructures):
searchResults = {}
queryStructures = self.transformRawQuery(rawQueryStructures)
with open(self.structureIndexPath) as indexFile:
reader = csv.reader(indexFile)
for line in reader:
structures = []
for structure in line[1:]:
structure = structure.replace("[", "").replace("]", "")
structure = re.split("\s+", structure)
if structure[0] == "":
structure = structure[1:]
structure = [float(eachValue) for eachValue in structure]
structures.append(structure)
distance = self.solveStructureDistance(structures, queryStructures)
searchResults[line[0]] = distance
indexFile.close()
# print "structure", sorted(searchResults.iteritems(), key = lambda item: item[1], reverse = False)
return searchResults
def search(self, queryFeatures, rawQueryStructures, limit = 6):
featureResults = self.searchByColor(queryFeatures)
structureResults = self.searchByStructure(rawQueryStructures)
results = {}
for key, value in featureResults.iteritems():
results[key] = value + structureResults[key]
results = sorted(results.iteritems(), key = lambda item: item[1], reverse = False)
return results[ : limit]
在这里返回的结果集只有一个值:
运行:我是在windows10下项目下直接cmd的
步骤:
1.提取特征图片的直方图特征,以及图片的构图空间特征,index.csv
python index.py --dataset dataset --colorindex color——index.csv --structure structure_index.csv
2.图片查找:
python searchEngine.py -c color_index.csv -s structure_index.csv -r dataset -q query/mm.png
查找出来的图片,感觉差不多
注意:
对于灰度图,在这里效果很差,,我对一个图片进行处理转化为灰度图处理了之后,在进行相似图片的查找直接放图吧
查找出来的图片:
效果很差
以上的相似图片的搜索,利用的直方图的差异来查找,,直方图只是对色彩空间的敏感度高,后续还需要要改进,也利用了hash值来计算,后续在贴出来吧。