文章目录
1、np.hstack / np.vstack
利用 numpy 的 hstack 和 vstack,对图片进行拼接
import cv2
import numpy as np
h, w = 256,256
img1 = cv2.resize(cv2.imread("1.jpg"), (w, h))
img2 = cv2.resize(cv2.imread("2.png"), (w, h))
horizontal = np.hstack((img1, img2))
cv2.imwrite("horizontal.jpg", horizontal)
vertical = np.vstack((img1, img2))
cv2.imwrite("vertical.jpg", vertical)
输入图片
horizontal
vertical
2、Slice
学习来自 Python 图像合并:利用 OpenCV 的强大功能
图片 reszie 成同样大小,生成空白图,利用切片,给相应区域赋值
import cv2
import numpy as np
dimension = 256
canvas_dimension = 2 * dimension
img1 = cv2.resize(cv2.imread("1.png"), (dimension, dimension))
img2 = cv2.resize(cv2.imread("2.png"), (dimension, dimension))
img3 = cv2.resize(cv2.imread("3.png"), (dimension, dimension))
img4 = cv2.resize(cv2.imread("4.png"), (dimension, dimension))
canvas = np.zeros((canvas_dimension, canvas_dimension, 3), dtype=np.uint8)
canvas[0:dimension, 0:dimension] = img1
canvas[0:dimension, dimension:canvas_dimension] = img2
canvas[dimension:canvas_dimension, 0:dimension] = img3
canvas[dimension:canvas_dimension, dimension:canvas_dimension] = img4
# cv2.imwrite("merge.jpg", canvas)
cv2.imshow("merge", canvas)
cv2.waitKey(0)
cv2.destroyAllWindows()
输入图片1
输入图片2
输入图片3
输入图片4
合并结果
3、cv2.addWeighted
import cv2
w, h = 960, 540
img1 = cv2.resize(cv2.imread("1.jpg"), (w, h))
img2 = cv2.resize(cv2.imread("2.jpg"), (w, h))
merge = cv2.addWeighted(img1, 0.7, img2, 0.3, gamma=.0)
cv2.imwrite("merge.jpg", merge)
输入1
输入2
输出
4、自定义渐变式叠加
渐变透明度叠加
原图
from PIL import Image
flag = Image.open('1.png').convert("RGBA")
avatar = Image.open('2.jpg').convert("RGBA")
flag = flag.resize(avatar.size)
for i in range(flag.size[0]):
for j in range(flag.size[1]):
r, g, b, _ = flag.getpixel((i, j))
alpha = max(0, 255 - i // 5 - j // 7) # 核心代码,左上角到右下角越来越透明
# 重新填充像素
flag.putpixel((i, j), (r, g, b, alpha))
avatar.paste(flag, (0, 0), flag)
avatar.save('flag_avatar.png')
叠加后的效果
5、cv2.bitwise_not / cv2.bitwise_and / cv2.add
可以参考 【python】OpenCV—Paste Mask
A 图
A 图的 mask 标签
B 图
合并的结果
6、蒙太奇
参考学习来自:imutils基础(5)基于OpenCV与imutils实现蒙太奇
蒙太奇的含义有广狭之分:
-
狭义的蒙太奇:专指对镜头画面、声音、色彩诸元素编排组合的手段,即在后期制作中,将摄录的素材根据文学剧本和导演的总体构思精心排列,构成一部完整的影视作品。其中最基本的意义是画面的组合。
-
广义的蒙太奇:不仅指镜头画面的组接,也指从影视剧作开始直到作品完成整个过程中艺术家的一种独特的艺术思维方式。
imutils
是一个用于图像处理的Python库,它提供了许多简化图像处理任务的工具,比如图像转换、缩放、旋转等。然而,需要注意的是,imutils 库本身主要关注于图像的处理和转换,而imutils.paths.list_images函数则是这个库中用于处理图像文件路径的一个实用工具。
image_paths = list(paths.list_images(image_folder, ext=[".jpg", ".png"]))
- dirPath:要搜索的文件夹路径。
- ext(可选):一个字符串或字符串列表,指定要搜索的图像文件扩展名。如果未指定,则默认搜索所有常见的图像文件扩展名(如.jpg, .jpeg, .png, .bmp, .tiff, .gif, .dib等)。
# 导入包
from imutils import build_montages
from imutils import paths
import argparse
import random
import cv2
import numpy as np
def build_montages(image_list, image_shape, montage_shape):
"""
将单个图像列表转换为指定行和列的“蒙太奇”图像列表。
一旦填充了蒙太奇图像的行和列,就会启动新的蒙太奇图像。
不完整的蒙太奇图像的空白空间充满黑色像素
---------------------------------------------------------------------------------------------
:参数 image_list: 输入图像的python列表
:参数 image_shape: 元组,每个图像被调整后的大小(宽度,高度)
:参数 montage_shape: 元组,图像蒙太奇的形状(宽度,高度)
:return: numpy 数组格式的蒙太奇图像列表
---------------------------------------------------------------------------------------------
示例用法:
# 加载单个图像
img = cv2.imread('lena.jpg')
# 复制图像 25 次
num_imgs = 25
img_list = []
for i in xrange(num_imgs):
img_list.append(img)
# 5x5蒙太奇
montages = build_montages(img_list, (256, 256), (5, 5))
# 遍历蒙太奇列表并显示
for montage in montages:
cv2.imshow('montage image', montage)
cv2.waitKey(0)
----------------------------------------------------------------------------------------------
"""
if len(image_shape) != 2:
raise Exception('image shape must be list or tuple of length 2 (rows, cols)')
if len(montage_shape) != 2:
raise Exception('montage shape must be list or tuple of length 2 (rows, cols)')
image_montages = []
# 从黑色画布开始绘制图像
montage_image = np.zeros(shape=(image_shape[1] * (montage_shape[1]), image_shape[0] * montage_shape[0], 3),
dtype=np.uint8)
cursor_pos = [0, 0]
start_new_img = False
for img in image_list:
if type(img).__module__ != np.__name__:
raise Exception('input of type {} is not a valid numpy array'.format(type(img)))
start_new_img = False
img = cv2.resize(img, image_shape)
# 将图像绘制到黑色画布上
montage_image[cursor_pos[1]:cursor_pos[1] + image_shape[1], cursor_pos[0]:cursor_pos[0] + image_shape[0]] = img
cursor_pos[0] += image_shape[0] # 增加光标 x 位置
if cursor_pos[0] >= montage_shape[0] * image_shape[0]:
cursor_pos[1] += image_shape[1] # 增加光标y位置
cursor_pos[0] = 0
if cursor_pos[1] >= montage_shape[1] * image_shape[1]:
cursor_pos = [0, 0]
image_montages.append(montage_image)
# 重置黑色画布
montage_image = np.zeros(shape=(image_shape[1] * (montage_shape[1]), image_shape[0] * montage_shape[0], 3),
dtype=np.uint8)
start_new_img = True
if start_new_img is False:
image_montages.append(montage_image) # 添加未完成的蒙太奇
return image_montages
if __name__ == "__main__":
# 构造参数parse并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", default="./",
help="path to input directory of images")
ap.add_argument("-s", "--sample", type=int, default=36,
help="# of images to sample")
args = vars(ap.parse_args())
# 抓取图像的路径,然后随机选择样本
imagePaths = list(paths.list_images(args["images"]))
random.shuffle(imagePaths)
imagePaths = imagePaths[:args["sample"]]
# 初始化图像列表
images = []
# 遍历图像路径列表
for imagePath in imagePaths:
# 加载图像并更新图像列表
image = cv2.imread(imagePath)
images.append(image)
# 构建图像的蒙太奇
montages = build_montages(images, (256, 256), (6, 6))
# 循环蒙太奇并显示每个蒙太奇
for index, montage in enumerate(montages):
cv2.imwrite(f"Montage_{str(index)}.jpg", montage)
cv2.imshow("Montage", montage)
cv2.waitKey(0)
输入图像文件夹
结果