OpenCV_008-OpenCV 中的图像算术运算

本文主要内容来自于 OpenCV-Python 教程核心操作 部分,这个部分的主要内容如下:

目标

  • 学习一些图像的算术运算操作,比如加、减、位运算,等等。
  • 学习这些函数:cv.add()cv.addWeighted(),等等。

图像加法

我们可以利用 OpenCV 的函数,cv.add(),或简单地通过 numpy 操作 res = img1 + img2,将两幅图像加起来。两幅图像应该具有相同的深度和类型,或者第二幅图像可以仅仅是个标量值。

注意
OpenCV 的加法和 Numpy 的加法是有区别的。OpenCV 加法是饱和运算,而 Numpy 加法是模运算。

比如,考虑下面的例子:

def diff_add():
    x = np.uint8([250])
    y = np.uint8([10])

    print(cv.add(x,y)) # 250+10 = 260 => 255
    print(x + y)  # 250+10 = 260 % 256 = 4

这几行代码的输出如下:

[[255]]
[4]

当将两个图像相加时,这将更加明显。坚持使用 OpenCV 函数,因为它们会提供更好的结果。

图像混合

这也是一个图像相加操作,但会给不同的图像以不同的权重,为了给人一种混合或透明的感觉。图像相加操作按以下公式进行:

g(x) = (1 - alpha)f_0(x) + alphaf_1(x)

通过从 0 -> 1 改变 alpha 的值,我们可以执行一个从一幅图像到另一幅图像之间很酷的转换。

这里我们拿两幅图像来混合。给第一个图像一个权重 0.7,给第二个图像一个权重 0.7。 cv.addWeighted() 对图像应用如下的公式:

dst = alpha * img1 + beta * img2 + gamma

这里的 gamma 我们取 0。

def image_blending():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    file_ml = cv.samples.findFile('ml.png')
    img1 = cv.imread(file_ml)

    file_logo = cv.samples.findFile('opencv-logo.png')
    img2 = cv.imread(file_logo)
    print(img1.shape)
    img2 = cv.resize(img2, (img1.shape[1], img1.shape[0]))
    print(img2.shape)
    dst = cv.addWeighted(img1, 0.7, img2, 0.3, 0)

    plt.subplot(131), plt.imshow(img1, 'gray'), plt.title('ORIGINAL')
    plt.subplot(132), plt.imshow(img2, 'gray'), plt.title('REPLICATE')
    plt.subplot(133), plt.imshow(dst, 'gray'), plt.title('REFLECT')

    plt.subplots_adjust(wspace=0.4, hspace=0.4)

    plt.show()

由于上面的两幅图像大小不一样,因而通过 cv.resize() 将其中一幅图像的大小做调整,以便后面的混合操作可以正常执行。检查最终的结果如下:

Image

下面这个例子演示如上相同的函数,但引入 cv.hconcat() 来将原始图像和结果图像水平拼接起来,以另一种方式展示结果:

def image_blending1():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    file_ml = cv.samples.findFile('ml.png')
    img1 = cv.imread(file_ml)

    file_logo = cv.samples.findFile('opencv-logo.png')
    img2 = cv.imread(file_logo)
    print(img1.shape)
    img2 = cv.resize(img2, (img1.shape[1], img1.shape[0]))
    print(img2.shape)
    dst = cv.addWeighted(img1, 0.7, img2, 0.3, 0)

    images = [img1, img2, dst]
    img4 = cv.hconcat(images)

    cv.imshow('Image', img4)
    cv.waitKey(0)
    cv.destroyAllWindows()

检查最终的结果如下:

Image

下面这个示例则通过图像混合,实现一个渐入和渐出的动画效果:

def image_blending2():
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    file_ml = cv.samples.findFile('ml.png')
    img1 = cv.imread(file_ml)

    file_logo = cv.samples.findFile('opencv-logo.png')
    img2 = cv.imread(file_logo)
    img2 = cv.resize(img2, (img1.shape[1], img1.shape[0]))

    weight = 0.01
    step = 0.02
    while True:
        dst = cv.addWeighted(img1, weight, img2, 1 - weight, 0)
        cv.imshow('Image', dst)

        key = cv.waitKey(35)
        if key == ord('q'):
            break

        weight += step
        if (weight > 1.0):
            step = -step
        elif weight < 0:
            step = -step

    cv.destroyAllWindows()

位操作

这里包括位 AND,OR,NOT 和 XOR 操作。在提取图像的任何部分(我们将在接下来的章节中看到)、定义和使用非矩形 ROI 等时,它们将非常有用。下面我们将看到一个如何更改图像特定区域的示例。

我想把 OpenCV logo 放到一幅图像上面。如果我将两幅图像相加,则它将改变颜色。如果我混合它们,我得到一个透明效果。但我希望它是不透明的。如果它是一个矩形区域,我可以使用 ROI,就像我们在前面的章节中做的那样。但 OpenCV logo 不是一个矩形。因而,我们可以用位操作来实现,如下所示:

def bitwise_operations():
    # Load two images
    cv.samples.addSamplesDataSearchPath("/media/data/my_multimedia/opencv-4.x/samples/data")
    img1 = cv.imread(cv.samples.findFile('messi5.jpg'))
    img2 = cv.imread(cv.samples.findFile('opencv-logo-white.png'))

    # I want to put logo on top-left corner, So I create a ROI
    rows, cols, channels = img2.shape
    roi = img1[0:rows, 0:cols]

    # Now create a mask of logo and create its inverse mask also
    img2gray = cv.cvtColor(img2, cv.COLOR_BGR2GRAY)
    ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
    mask_inv = cv.bitwise_not(mask)

    images = [img2gray, mask, mask_inv]
    image = cv.hconcat(images)

    # Now black-out the area of logo in ROI
    img1_bg = cv.bitwise_and(roi, roi, mask=mask_inv)

    # Take only region of logo from logo image.
    img2_fg = cv.bitwise_and(img2, img2, mask=mask)

    # Put logo in ROI and modify the main image
    dst = cv.add(img1_bg, img2_fg)

    images2 = [img1_bg, img2_fg, dst]
    image2 = cv.hconcat(images2)

    img1[0:rows, 0:cols] = dst

    plt.subplot(211), plt.imshow(image, 'gray'), plt.title('MASK')
    plt.subplot(212), plt.imshow(image2, 'gray'), plt.title('ROI')

    plt.subplots_adjust(wspace=0.1, hspace=0.3)

    plt.show()

执行上面的代码,MASK 和 ROI 区域的变化如下图:

MASK 和 ROI

查看最终的结果。左图显示了我们创建的蒙版。右图展示了最终的结果。为了获得更好的理解,显示上面代码中所有的中间图像,特别是 img1_bgimg2_fg

Image

将左边图像和右边图像拼接起来并显示的代码如下:

    image4 = np.zeros((img1.shape[0], img2.shape[1], 3), np.uint8)
    merged = cv.merge((mask, mask, mask))
    image4[0:rows, 0:cols] = merged

    img1[0:rows, 0:cols] = dst

    images5 = [image4, img1]
    dest = cv.hconcat(images5)

    cv.imshow('res', dest)
    cv.waitKey(0)
    cv.destroyAllWindows()

其它资源

练习

  1. 使用 cv.addWeighted 函数,创建文件夹中图像的幻灯片放映,并在图像之间平滑过渡。

参考文档

Arithmetic Operations on Images

OPENCV基础(三):图像的混合

opencv实现几幅图像拼接成一整幅大图

Done.

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

推荐阅读更多精彩内容