利用Opencv和Python實(shí)現(xiàn)圖片不同之處可視化

原文地址:-Image Difference with Opencv and Python-
本文是原作者之前提到的SSIM方法的一種延申,本文主要利用Opencv和Python依據(jù)SSIM來(lái)實(shí)現(xiàn)兩幅圖片不同之處的可視化。運(yùn)行環(huán)境python3/opencv3

利用原作者的圖片,通過(guò)調(diào)整閾值,本文可以得到非常好的結(jié)果颇蜡,但是使用網(wǎng)絡(luò)上的找茬圖片,存在很多的噪聲辆亏,效果不是很好风秤,原因多在于圖片經(jīng)過(guò)了裁剪、旋轉(zhuǎn)扮叨、移位缤弦、壓縮等操作,后續(xù)繼續(xù)研究另外一位作者cangyan的思路和方法彻磁。

原文效果圖

image_difference_output_02

1.計(jì)算不同

我們?nèi)庋劭梢暂p松識(shí)別下面兩幅圖的不同之處:右圖右下角缺少一個(gè)logo碍沐。


image_difference_input

我們可以立刻找到兩幅圖片的不同,也許要花一點(diǎn)點(diǎn)時(shí)間衷蜓,但是當(dāng)兩幅圖片的差別特別細(xì)微的時(shí)候累提,我們?nèi)庋蹘缀跏欠直娌怀龅摹?/p>

那么,識(shí)別圖片的不同為什么這么重要呢磁浇?
比較常見(jiàn)的一個(gè)問(wèn)題就是釣魚(yú)網(wǎng)站斋陪,攻擊者利用幾乎一模一樣的圖片制作一個(gè)高仿的銀行網(wǎng)站,迷惑那些毫無(wú)戒心的網(wǎng)友。

對(duì)比網(wǎng)站logo以及及時(shí)熟知網(wǎng)站的用戶界面在很大程度上可以防止釣魚(yú)攻擊无虚。相比于兩幅圖的比較鞍匾,釣魚(yú)網(wǎng)站檢測(cè)系統(tǒng)將更為復(fù)雜,但我們?nèi)匀豢梢允褂靡延械闹R(shí)來(lái)判別圖像是否做了手腳骑科。

讀入圖片

原文代碼:

# import the necessary packages
from skimage.measure import compare_ssim
import argparse
import imutils
import cv2
 
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-f", "--first", required=True,
    help="first input image")
ap.add_argument("-s", "--second", required=True,
    help="second")
args = vars(ap.parse_args())

# load the two input images
imageA = cv2.imread(args["first"])
imageB = cv2.imread(args["second"])
 
# convert the images to grayscale
grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)

查找輪廓函數(shù)cv2.findcontours需要圖片是二值圖橡淑,所以先將圖片由BGR轉(zhuǎn)為gray

image_difference_grayscale

接下來(lái)咆爽,計(jì)算兩幅圖之間的SSIM梁棠,由于diff的值范圍[0, 1],為了可以用Opencv進(jìn)一步操作斗埂,將其轉(zhuǎn)換為[0, 255]符糊;
參考代碼:

# compute the Structural Similarity Index (SSIM) between the two
# images, ensuring that the difference image is returned
(score, diff) = compare_ssim(grayA, grayB, full=True)
diff = (diff * 255).astype("uint8")
print("SSIM: {}".format(score))

然后,調(diào)整閾值呛凶,獲得二值圖男娄,再利用Opencv找到兩幅圖內(nèi)容差異diff的輪廓,并用矩形標(biāo)出來(lái)漾稀;
參考代碼:

# threshold the difference image, followed by finding contours to
# obtain the regions of the two input images that differ
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

原文作者考慮的甚是周全模闲,考慮到用戶的Opencv版本可能不同,使用了imutils.grab_contours()函數(shù)崭捍,具體可以參考imutils.grab_contours源碼

# if the length the contours tuple returned by cv2.findContours
    # is '2' then we are using either OpenCV v2.4, v4-beta, or
    # v4-official
    if len(cnts) == 2:
        cnts = cnts[0]
    # if the length of the contours tuple is '3' then we are using
    # either OpenCV v3, v4-pre, or v4-alpha
    elif len(cnts) == 3:
        cnts = cnts[1]
    # otherwise OpenCV has changed their cv2.findContours return
    # signature yet again and I have no idea WTH is going on
    else:
        raise Exception(("Contours tuple must have length 2 or 3, "
            "otherwise OpenCV changed their cv2.findContours return "
            "signature yet again. Refer to OpenCV's documentation "
            "in that case"))
    # return the actual contours array
    return cnts

顯示得到的二值圖尸折,效果非常理想;

image_difference_thresh

使用紅色矩形圈出“不同之處”的輪廓殷蛇;
image_difference_output_01

參考代碼:

# loop over the contours
for c in cnts:
    # compute the bounding box of the contour and then draw the
    # bounding box on both input images to represent where the two
    # images differ
    (x, y, w, h) = cv2.boundingRect(c)
    cv2.rectangle(imageA, (x, y), (x + w, y + h), (0, 0, 255), 2)
    cv2.rectangle(imageB, (x, y), (x + w, y + h), (0, 0, 255), 2)
 
# show the output images
cv2.imshow("Original", imageA)
cv2.imshow("Modified", imageB)
cv2.imshow("Diff", diff)
cv2.imshow("Thresh", thresh)
cv2.waitKey(0)
2.圖片不同可視化

使用下面的命令实夹,可以很好的發(fā)現(xiàn)兩幅圖片的不同:

$ python image_diff.py --first images/original_02.png --second images/modified_02.png
image_difference_output_02 (1)

image_difference_output_03
3.個(gè)人測(cè)試

詳細(xì)代碼參考:myGithub
使用網(wǎng)絡(luò)圖片2,得到了400多個(gè)輪廓粒梦,畫出輪廓面積最大的10個(gè)結(jié)果亮航,可以看到得到了較好的判定結(jié)果,除了發(fā)現(xiàn)不同之外匀们,還多出了3處缴淋;

individual result2

使用網(wǎng)絡(luò)圖片1,效果相比差點(diǎn)昼蛀,雖然也發(fā)現(xiàn)了稍有的幾處不同宴猾,但誤判的區(qū)域更占多數(shù)圆存,主要原因更多是圖片的質(zhì)量問(wèn)題叼旋,右邊稍有壓縮痕跡
individual result1

總結(jié)

利用Opencv/Python/Skimage計(jì)算的SSIM沦辙,我們實(shí)現(xiàn)了兩幅圖之間的差異可視化效果夫植,要得到完全正確的結(jié)果,前提要保證變動(dòng)的部分是嚴(yán)格在原始圖上進(jìn)行的操作,而且內(nèi)容要重合好详民,這樣可以得到像原作者文中的效果延欠。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沈跨,隨后出現(xiàn)的幾起案子由捎,更是在濱河造成了極大的恐慌,老刑警劉巖饿凛,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狞玛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡涧窒,警方通過(guò)查閱死者的電腦和手機(jī)心肪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纠吴,“玉大人硬鞍,你說(shuō)我怎么就攤上這事〈饕眩” “怎么了固该?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)糖儡。 經(jīng)常有香客問(wèn)我蹬音,道長(zhǎng),這世上最難降的妖魔是什么休玩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任著淆,我火速辦了婚禮,結(jié)果婚禮上拴疤,老公的妹妹穿的比我還像新娘永部。我一直安慰自己,他們只是感情好呐矾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布苔埋。 她就那樣靜靜地躺著,像睡著了一般蜒犯。 火紅的嫁衣襯著肌膚如雪组橄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,610評(píng)論 1 305
  • 那天罚随,我揣著相機(jī)與錄音玉工,去河邊找鬼。 笑死淘菩,一個(gè)胖子當(dāng)著我的面吹牛遵班,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狭郑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼腹暖!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起翰萨,我...
    開(kāi)封第一講書(shū)人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤脏答,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后亩鬼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體以蕴,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年辛孵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丛肮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魄缚,死狀恐怖宝与,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冶匹,我是刑警寧澤习劫,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站嚼隘,受9級(jí)特大地震影響诽里,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜飞蛹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一谤狡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卧檐,春花似錦墓懂、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至盈罐,卻和暖如春榜跌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盅粪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工钓葫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人湾揽。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓瓤逼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親库物。 傳聞我的和親對(duì)象是個(gè)殘疾皇子霸旗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

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