1. 程式人生 > >python+opencv實現相似圖片的搜尋

python+opencv實現相似圖片的搜尋

在學習時: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值來計算,後續在貼出來吧。