利用Opencv和Python实现图片不同之处可视化

原文地址:-Image Difference with Opencv and Python-
本文是原作者之前提到的SSIM方法的一种延申,本文主要利用Opencv和Python依据SSIM来实现两幅图片不同之处的可视化。运行环境python3/opencv3

利用原作者的图片,通过调整阈值,本文可以得到非常好的结果,但是使用网络上的找茬图片,存在很多的噪声,效果不是很好,原因多在于图片经过了裁剪、旋转、移位、压缩等操作,后续继续研究另外一位作者cangyan的思路和方法。

原文效果图

image_difference_output_02

1.计算不同

我们肉眼可以轻松识别下面两幅图的不同之处:右图右下角缺少一个logo。


image_difference_input

我们可以立刻找到两幅图片的不同,也许要花一点点时间,但是当两幅图片的差别特别细微的时候,我们肉眼几乎是分辨不出的。

那么,识别图片的不同为什么这么重要呢?
比较常见的一个问题就是钓鱼网站,攻击者利用几乎一模一样的图片制作一个高仿的银行网站,迷惑那些毫无戒心的网友。

对比网站logo以及及时熟知网站的用户界面在很大程度上可以防止钓鱼攻击。相比于两幅图的比较,钓鱼网站检测系统将更为复杂,但我们仍然可以使用已有的知识来判别图像是否做了手脚。

读入图片

原文代码:

# 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)

查找轮廓函数cv2.findcontours需要图片是二值图,所以先将图片由BGR转为gray

image_difference_grayscale

接下来,计算两幅图之间的SSIM,由于diff的值范围[0, 1],为了可以用Opencv进一步操作,将其转换为[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))

然后,调整阈值,获得二值图,再利用Opencv找到两幅图内容差异diff的轮廓,并用矩形标出来;
参考代码:

# 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()函数,具体可以参考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.图片不同可视化

使用下面的命令,可以很好的发现两幅图片的不同:

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

image_difference_output_03
3.个人测试

详细代码参考:myGithub
使用网络图片2,得到了400多个轮廓,画出轮廓面积最大的10个结果,可以看到得到了较好的判定结果,除了发现不同之外,还多出了3处;

individual result2

使用网络图片1,效果相比差点,虽然也发现了稍有的几处不同,但误判的区域更占多数,主要原因更多是图片的质量问题,右边稍有压缩痕迹
individual result1

总结

利用Opencv/Python/Skimage计算的SSIM,我们实现了两幅图之间的差异可视化效果,要得到完全正确的结果,前提要保证变动的部分是严格在原始图上进行的操作,而且内容要重合好,这样可以得到像原作者文中的效果。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容