圖像相似度匹配

這個(gè)周末解決了一個(gè)實(shí)際問題。
硬盤里存有大量圖片厨埋。(大約2萬)
當(dāng)需要找某一圖片時(shí)邪媳,如何找出與之相似的呢。

在查資料的過程中荡陷。我知道可以使用
PIL(Python Image Library)或者是openCV雨效。
對(duì)于學(xué)習(xí)來說,使用后者更好废赞,因?yàn)閛pencv具有跨平臺(tái)的特性徽龟,且支持多種語言的接口。而且在python上也不乏很多資料可查唉地。

開發(fā)環(huán)境我選擇了 opencv3.1 + pycharm
在python中圖像使用numpy.ndarray表示据悔,所以要提前裝好numpy庫(kù)传透。

下一步就是匹配算法了。
一開始我想用的是Template Matching
后來發(fā)現(xiàn)這種模式匹配的方式還需要涉及縮放問題极颓。
于是朱盐,簡(jiǎn)單點(diǎn)的話還是使用直方圖匹配的方式進(jìn)行。
參考 pil的這個(gè)博客菠隆。不過我使用的是opencv兵琳。
opencv的直方圖使用資料可以從readdoc網(wǎng)查到

好的。講了這么多骇径。還是直接貼代碼吧~

import cv2
import numpy as np
import os
import os.path
from matplotlib import pyplot as plt

此處安裝后躯肌,需要配置cv2的so庫(kù)地址。報(bào)錯(cuò)不要緊破衔,不影響調(diào)用清女。見我的安裝筆記即可。

獲取直方圖算法:簡(jiǎn)單說一下运敢,就是分別獲取rgb三個(gè)通道的直方圖校仑,然后加在一起,成為一個(gè)768*1的數(shù)組传惠。
返回的是一個(gè)元組迄沫。分別是直方圖向量和圖像的像素點(diǎn)總和。我利用這個(gè)比例縮放來進(jìn)行圖片的大小匹配卦方。

def get_histGBR(path):
    img = cv2.imread(path)

    pixal = img.shape[0] * img.shape[1]
    # print(pixal)
    # scale = pixal/100000.0
    # print(scale)
    total = np.array([0])
    for i in range(3):
        histSingle = cv2.calcHist([img], [i], None, [256], [0, 256])
        total = np.vstack((total, histSingle))
    # plt.plot(total)
    # plt.xlim([0, 768])
    # plt.show()
    return (total, pixal)

相似度計(jì)算:

計(jì)算公式
def hist_similar(lhist, rhist, lpixal,rpixal):
    rscale = rpixal/lpixal
    rhist = rhist/rscale
    assert len(lhist) == len(rhist)
    likely =  sum(1 - (0 if l == r else float(abs(l - r)) / max(l, r)) for l, r in zip(lhist, rhist)) / len(lhist)
    if likely == 1.0:
        return [1.0]
    return likely

該算法反悔一個(gè)0到1的[float]相似度羊瘩。來代表兩個(gè)向量之間的幾何距離。輸入的4個(gè)參數(shù)分別為圖像的直方圖和圖像的尺寸盼砍。

最后加上一些文件訪問的代碼和排序代碼尘吗。即可給出
對(duì)于指定圖片,在目標(biāo)文件夾中的所有圖片中相似度排名最高的N個(gè)圖的路徑和相似度浇坐。

import cv2
import numpy as np
import os
import os.path
from matplotlib import pyplot as plt


# 文件讀取并顯示
# img = cv2.imread("kitchen.jpeg")
# print("hello opencv "+ str(type(img)))
# # print(img)
# cv2.namedWindow("Image")
# cv2.imshow("Image",img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()


# img = cv2.imread('kitchen.jpeg', 1)
# temp = cv2.imread('Light.png', 1)
# w,h = temp.shape[::-1]
#
# print(w,h,sep="  ")
# # print(img)
# cv2.namedWindow("Image")
# cv2.imshow("Image", img)
# cv2.waitKey(0)
# cv2.destroyAllWindows()


# img = cv2.imread('kitchen.jpeg', 0)
# img2 = img.copy()
# template = cv2.imread('Light.png', 0)
# w, h = template.shape[::-1]
# print(template.shape)
#
# # All the 6 methods for comparison in a list
# methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
#            'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
#
# for meth in methods:
#     img = img2.copy()
#     method = eval(meth)
#
#     # Apply template Matching
#     res = cv2.matchTemplate(img, template, method)
#     min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
#
#     # If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
#     if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
#         top_left = min_loc
#     else:
#         top_left = max_loc
#     bottom_right = (top_left[0] + w, top_left[1] + h)
#
#     cv2.rectangle(img, top_left, bottom_right, 255, 2)
#
#     plt.subplot(121), plt.imshow(res, cmap='gray')
#     plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
#     plt.subplot(122), plt.imshow(img, cmap='gray')
#     plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
#     plt.suptitle(meth)
#
#     plt.show()

# image = cv2.imread("kitchen.jpeg", 0)
# hist = cv2.calcHist([image],
#                     [0],
#                     None,
#                     [256],
#                     [0, 256])
# plt.plot(hist),plt.xlim([0,256])
# plt.show()

# # hist = cv2.calcHist([image],[0,1,2],None,[256,256,256],[[0,255],[0,255],[0,255]])
# # cv2.imshow("img",image)
# cv2.imshow("hist", hist)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

# image = cv2.imread("kitchen.jpeg", 0)
# hist = plt.hist(image.ravel(), 256, [0, 256])
# plt.show(hist)

def hist_similar(lhist, rhist, lpixal,rpixal):
    rscale = rpixal/lpixal
    rhist = rhist/rscale
    assert len(lhist) == len(rhist)
    likely =  sum(1 - (0 if l == r else float(abs(l - r)) / max(l, r)) for l, r in zip(lhist, rhist)) / len(lhist)
    if likely == 1.0:
        return [1.0]
    return likely


def get_histGBR(path):
    img = cv2.imread(path)

    pixal = img.shape[0] * img.shape[1]
    # print(pixal)
    # scale = pixal/100000.0
    # print(scale)
    total = np.array([0])
    for i in range(3):
        histSingle = cv2.calcHist([img], [i], None, [256], [0, 256])
        total = np.vstack((total, histSingle))
    # plt.plot(total)
    # plt.xlim([0, 768])
    # plt.show()
    return (total, pixal)


if __name__ == '__main__':
    targetHist, targetPixal = get_histGBR('test.jpg')
    rootdir = "/Users/YM/Desktop/DCIM"
    # aHist = get_histGBR('a.png')
    # bHist = get_histGBR('Light.png')
    #
    # print(hist_similar(aHist, bHist))
    resultDict = {}
    for parent, dirnames, filenames in os.walk(rootdir):
        # for dirname in dirnames:
        #     print("parent is: " + parent)
        #     print("dirname is: " + dirname)
        for filename in filenames:
            if (filename[-3:] == 'jpg'):
                jpgPath = os.path.join(parent, filename)
                testHist, testPixal = get_histGBR(jpgPath)
                # print(hist_similar(targetHist,testHist)[0])
                resultDict[jpgPath]=hist_similar(targetHist,testHist,targetPixal,testPixal)[0]

    # print(resultDict)
    # for each in resultDict:
    #     print(each, resultDict[each],sep="----")
    sortedDict = sorted(resultDict.items(), key=lambda asd: asd[1], reverse=True)
    for i in range(5):
        print(sortedDict[i])
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末睬捶,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子近刘,更是在濱河造成了極大的恐慌擒贸,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件觉渴,死亡現(xiàn)場(chǎng)離奇詭異介劫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)案淋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門座韵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人踢京,你說我怎么就攤上這事誉碴』鹿祝” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵翔烁,是天一觀的道長(zhǎng)渺氧。 經(jīng)常有香客問我,道長(zhǎng)蹬屹,這世上最難降的妖魔是什么侣背? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮慨默,結(jié)果婚禮上贩耐,老公的妹妹穿的比我還像新娘。我一直安慰自己厦取,他們只是感情好潮太,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著虾攻,像睡著了一般铡买。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上霎箍,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天奇钞,我揣著相機(jī)與錄音,去河邊找鬼漂坏。 笑死景埃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的顶别。 我是一名探鬼主播谷徙,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼驯绎!你這毒婦竟也來了完慧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤剩失,失蹤者是張志新(化名)和其女友劉穎骗随,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赴叹,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年指蚜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乞巧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摊鸡,死狀恐怖绽媒,靈堂內(nèi)的尸體忽然破棺而出蚕冬,到底是詐尸還是另有隱情,我是刑警寧澤是辕,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布囤热,位于F島的核電站,受9級(jí)特大地震影響获三,放射性物質(zhì)發(fā)生泄漏旁蔼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一疙教、第九天 我趴在偏房一處隱蔽的房頂上張望棺聊。 院中可真熱鬧,春花似錦贞谓、人聲如沸限佩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)祟同。三九已至,卻和暖如春理疙,著一層夾襖步出監(jiān)牢的瞬間晕城,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工沪斟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留广辰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓主之,卻偏偏與公主長(zhǎng)得像择吊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子槽奕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 這些年計(jì)算機(jī)視覺識(shí)別和搜索這個(gè)領(lǐng)域非常熱鬧几睛,后期出現(xiàn)了很多的創(chuàng)業(yè)公司,大公司也在這方面也花了很多力氣在做粤攒。做視覺搜...
    方弟閱讀 6,444評(píng)論 6 24
  • # Python 資源大全中文版 我想很多程序員應(yīng)該記得 GitHub 上有一個(gè) Awesome - XXX 系列...
    aimaile閱讀 26,444評(píng)論 6 428
  • GitHub 上有一個(gè) Awesome - XXX 系列的資源整理,資源非常豐富所森,涉及面非常廣。awesome-p...
    若與閱讀 18,615評(píng)論 4 418
  • 環(huán)境管理管理Python版本和環(huán)境的工具夯接。p–非常簡(jiǎn)單的交互式python版本管理工具焕济。pyenv–簡(jiǎn)單的Pyth...
    MrHamster閱讀 3,783評(píng)論 1 61
  • 買菜時(shí)經(jīng)過海鮮區(qū),見有個(gè)攤位上騰出一塊地方來盔几,反放著貨箱蓋晴弃,上面擺放著一塊一塊白瑩瑩透明的“果凍”。是海蜇!我的眼...
    春山雨閱讀 711評(píng)論 2 1