OpenCV竟然可以这样学!成神之路终将不远(七)

返回目录

目录

7 图像上的算术运算

7.1 目标

7.2 图像加法

7.3 图像融合

7.4 按位运算

7.5 练习题


7 图像上的算术运算

7.1 目标

学习图像的几种算术运算,例如加法,减法,按位运算等。

您将学习以下功能:cv.add,cv.addWeighted等。

7.2 图像加法

您可以通过OpenCV函数cv.add() 或仅通过numpy操作res = img1 + img2 添加两个图像。两个图像应具有相同的深度和类型,或者第二个图像可以只是一个标量值。

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

示例如下:

x = np.uint8([250])
y = np.uint8([25])
print(cv.add(x, y))  # [[255]]:250+25=275=>255
print(x + y)  # [19]:250+25=275%256=19

当添加两个图像时,它将更加可见。OpenCV功能将提供更好的结果。因此,始终最好坚持使用OpenCV功能。

7.3 图像融合

这也是图像加法,但是对图像赋予不同的权重,以使其具有融合或透明的感觉。根据以下等式添加图像:

G(x)= (1 - \alpha)f_0(x)+ \alpha f_1(x)

通过从 \alpha0\rightarrow1更改,您可以在一个图像到另一个图像之间执行很酷的过渡,但是两个图像的宽高必须一致才行。

在这里,我拍摄了两个图像,将它们融合在一起。第一幅图像的权重为0.7,第二幅图像的权重为0.3。cv.addWeighted() 在图像上应用以下公式。

dst=\alpha \cdot img1+\beta \cdot img2 + \gamma

在这里,\gamma 被视为零。

import cv2 as cv

img1 = cv.imread('../girl02/05.jpg')
img2 = cv.imread('../girl02/06.jpg')
print('img1:{};img2:{}'.format(img1.shape, img2.shape))  # img1:(1080, 1920, 3);img2:(1080, 1920, 3)
cv.namedWindow('image', cv.WINDOW_NORMAL)
dst = cv.addWeighted(img1, 0.7, img2, 0.3, 0)
cv.imshow('image', dst)
cv.waitKey(0)
cv.destroyAllWindows()

融合结果如下:

OpenCV竟然可以这样学!成神之路终将不远(七)_第1张图片

7.4 按位运算

这包括按位 AND OR NOT XOR 操作。它们在提取图像的任何部分(我们将在后面的章节中看到)、定义和处理非矩形 ROI 等方面非常有用。 下面我们将看到一个例子,如何改变一个图像的特定区域。 我想把 OpenCV 的标志放在一个图像上面。如果我添加两个图像,它会改变颜色。如果我混合它,我得到一个透明的效果。但我希望它是不透明的。如果是一个矩形区域,我可以使用 ROI,就像我们在上一章中所做的那样。但是 OpenCV 的 logo 不是长方形的。所以你可以使用如下的按位操作来实现:

我想在图像上方放置OpenCV徽标。如果添加两个图像,它将改变颜色。如果混合它,我将获得透明效果。但我希望它不透明。如果是矩形区域,则可以像上一章一样使用ROI。但是OpenCV徽标不是矩形。因此,您可以按如下所示进行按位操作:

import cv2 as cv
import matplotlib.pyplot as plt

# 读取原图像
img = cv.imread('../girl6/14.jpg')
img = cv.cvtColor(img, cv.COLOR_BGR2RGB)  # 因为opencv是BGR通道,而matplotlib是RGB通道
plt.subplot(331), plt.imshow(img, 'gray'), plt.title('img')

# 读取logo图像
logo = cv.imread('../girl6/opencv.png')
logo = cv.cvtColor(logo, cv.COLOR_BGR2RGB)
plt.subplot(332), plt.imshow(logo, 'gray'), plt.title('logo')

# 把logo放在左上角,所以创建了ROI
rows, cols, channels = logo.shape  # 获取logo的行、列和通道数
roi = img[0:rows, 0:cols]  # 在img图像上面截取roi大小的区域
plt.subplot(339), plt.imshow(roi, 'gray'), plt.title('roi')

# 现在创建logo的掩码,并同时创建其相反掩码
logo2gray = cv.cvtColor(logo, cv.COLOR_BGR2GRAY)  # 将logo转换为灰度图像,以便二值化
plt.subplot(334), plt.imshow(logo2gray, 'gray'), plt.title('logo2gray')
# cv.threshold将灰度图二值化,ret为阈值,mask为二值化的图像,将低于第一个阈值的置为0,高于第二个阈值的置为255
ret, mask = cv.threshold(logo2gray, 200, 255, cv.THRESH_BINARY)
plt.subplot(335), plt.imshow(mask, 'gray'), plt.title('mask')
# bitwise_not是对二进制数据进行“非”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“非”操作
mask_inverse = cv.bitwise_not(mask)  # cv.bitwise_not将掩码取反
plt.subplot(336), plt.imshow(mask_inverse, 'gray'), plt.title('mask_inverse')

# 现在将ROI中logo的区域涂黑
# bitwise_and是对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作
img_background = cv.bitwise_and(roi, roi, mask=mask_inverse)
plt.subplot(337), plt.imshow(img_background, 'gray'), plt.title('img_background')

# 仅从logo图像中提取logo区域
logo_foreground = cv.bitwise_and(logo, logo, mask=mask)
plt.subplot(338), plt.imshow(logo_foreground, 'gray'), plt.title('logo_foreground')

# 将logo放入ROI并修改主图像
dst = cv.add(img_background, logo_foreground)
img[0:rows, 0:cols] = dst
plt.subplot(333), plt.imshow(img, 'gray'), plt.title('dst')

plt.show()

请看下面的结果。为了更加直观的看清楚,我将其用matplotlib进行了排列,可以看清楚每一个图像的意思。

OpenCV竟然可以这样学!成神之路终将不远(七)_第2张图片

7.5 练习题

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

大家可以先自己想想应该怎么做,我这里做的是循环读取文件夹的图片,达到幻灯片放映效果,先上运行结果:

具体代码如下:

import cv2 as cv
import os
from PIL import Image

# 读取文件夹下图片的数量
image_dir = '../girl6/'
count = os.listdir(image_dir)  # 读取image_dir文件夹中图片个数
print('count=', len(count))  # 打印文件夹中图片个数,我这里count=26

# 将图片裁剪成相同尺寸
for i in range(0, len(count)):
    # 获取图片的尺寸
    img = Image.open(image_dir + str(i).zfill(2) + '.jpg')
    img_size = img.size  # im_size[0]获取的是图片宽度,im_size[1]获取的是图片的高度
    # print('图片宽度和高度分别是{}'.format(img_size))
    img = img.resize((450, 288))  # 可以根据自己需求裁剪图片大小,第一个是宽度,第二个是高度
    # 将裁剪的图片按照0~count保存,zfill(2)表示两位数,不够前面填0
    img.save(image_dir + str(i).zfill(2) + '.jpg')

# 新建一个窗口
cv.namedWindow('image', cv.WINDOW_NORMAL)
a = 0  # 初始化权重系数
cv.waitKey(0)  # 等待按键开始

# 遍历文件夹下所有图片
for i in range(0, len(count)):
    image1 = cv.imread(image_dir + str(i).zfill(2) + '.jpg', 1)
    image2 = cv.imread(image_dir + str(i + 1).zfill(2) + '.jpg', 1)
    while a < 1.0:
        dst = cv.addWeighted(image2, a, image1, 1 - a, -1)
        cv.imshow('image', dst)
        cv.waitKey(88)  # 这里是自动跳转,也可以设置按键进行跳转
        a += 0.1
    a = 0  # 重新初始化权重系数
    print(i)
    i += 1
cv.waitKey(0)  # 等待按键结束
cv.destroyAllWindows()

欢迎评论区留言,一起探讨OpenCV成神之路的奥秘。

顺便给我加个关注,点个赞,加个收藏,让我们一起登上神坛。

你可能感兴趣的:(python,OpenCV,OpenCV成神之路,python,opencv,图像处理,计算机视觉,机器学习)