这里我们将介绍一些常用的图像融合方式,并不涉及到诸如CutMix、MixUp、TokenMix、Mosaic、Copy-Paste等图像增强方法。
首先是读取图像,我们这边采用了PIL库进行,那么读进来就应该是一个Image
对象。下面介绍Image
对象与array
的转换方式。
from PIL import Image
import numpy as np
img=Image.open(path)
# 从Image读取数据
img=np.array(img,dtype=np.float32)
# 从array转为Image
img=Image.fromarray(img)
有了前置知识后,我们就可以来进行图像融合了。注意,接下来的方法适用于图像大小相等的情况,如果不相等可以重设图像的尺寸。
import numpy as np
import random
from PIL import Image
def combine_images(original_img, augmented_img,combine_choice=None, blend_width=20):
width, height = 640, 640
combine_choice = random.choice(['horizontal', 'vertical',]) if combine_choice==None else combine_choice
if combine_choice == 'randomMix':
o,a=np.array(original_img),np.array(augmented_img)
data = [i for i in range(640 * 640)]
idx = random.sample(data, int(640 * 640 * 0.5))
for k in idx:
i, j = k // 640, k % 640
o[i][j] = a[i][j]
return Image.fromarray(o)
elif combine_choice == 'vertical': # Vertical combination
mask = np.linspace(0, 1, blend_width).reshape(-1, 1)
mask = np.tile(mask, (1, width)) # Extend mask horizontally
mask = np.vstack([np.zeros((height // 2 - blend_width // 2, width)), mask,
np.ones((height // 2 - blend_width // 2 + blend_width % 2, width))])
mask = np.tile(mask[:, :, np.newaxis], (1, 1, 3))
elif combine_choice == 'horizontal':
mask = np.linspace(0, 1, blend_width).reshape(1, -1)
mask = np.tile(mask, (height, 1)) # Extend mask vertically
mask = np.hstack([np.zeros((height, width // 2 - blend_width // 2)), mask,
np.ones((height, width // 2 - blend_width // 2 + blend_width % 2))])
mask = np.tile(mask[:, :, np.newaxis], (1, 1, 3))
elif combine_choice == 'diag1':
mask = np.ones((width, height))
mask[:width // 2, :height // 2] = 0
mask[width // 2:, height // 2:] = 0
mask = np.tile(mask[:, :, np.newaxis], (1, 1, 3))
else:
mask = np.zeros((width, height))
mask[:width // 2, :height // 2] = 1
mask[width // 2:, height // 2:] = 1
mask = np.tile(mask[:, :, np.newaxis], (1, 1, 3))
original_array = np.array(original_img, dtype=np.float32) / 255.0
augmented_array = np.array(augmented_img, dtype=np.float32) / 255.0
blended_array = (1 - mask) * original_array + mask * augmented_array
blended_array = np.clip(blended_array * 255, 0, 255).astype(np.uint8)
return Image.fromarray(blended_array)
RandomMix
将从图像A中随机选择像素点,并由B图像的像素点替代。
Horizontal
、Vertical
、Diag
则是会创造一个水平、垂直、对角线掩膜,用于遮盖A图的部分,并有B图替代。
下面看使用案例。
import matplotlib.pyplot as plt
combines=['randomMix', 'vertical','horizontal', 'diag1', 'diag2']
def draw(img,idx,title):
plt.subplot(int("15"+str(idx)))
plt.imshow(img)
plt.title(title)
plt.xticks([])
plt.yticks([])
p=r"C:\Users\Administrator\Downloads\result1.5\result\original_resized\class0"
img1,img2=Image.open(p+"//0.jpg"),Image.open(p+"//1.jpg")
res=combine_images(img1,img2)
plt.figure(figsize=(20,6))
for i,j in enumerate(combines):
draw(combine_images(img1,img2,j),i+1,j)
plt.show()
我们选择两张不同的图像A,B,进行操作后的结果如下图所示:
ISH变换
将高分辨率图像的I分量替换低分辨率的图像,在保留结构纹理的同时获取色彩信息。
def IHS(data_low, data_high, alpha=0.7):
Trans = np.matrix([
[1. / 3., 1. / 3., 1. / 3.],
[-2 ** 0.5 / 6, -2 ** 0.5 / 6, 2 * 2 ** 0.5 / 6],
[1 / 2 ** 0.5, -1 / 2 ** 0.5, 0]
])
Itrans = np.matrix([
[1, -1 / 2 ** 0.5, 1 / 2 ** 0.5],
[1, -1 / 2 ** 0.5, -1 / 2 ** 0.5],
[1, 2 ** 0.5, 0]
])
data_high = data_high.transpose()
data_low = data_low.transpose()
data_high = data_high.reshape(3, 640 * 640)
data_low = data_low.reshape(3, 640 * 640)
AIHS = np.dot(Trans, np.matrix(data_high))
BIHS = np.dot(Trans, np.matrix(data_low))
BIHS[0, :] = BIHS[0, :] * (1 - alpha) + AIHS[0, :] * (alpha)
RGB = np.array(np.dot(Itrans, BIHS))
RGB = RGB.reshape((3, 640, 640))
return RGB.transpose()
注意,ISH变换需要较长的运行时间,而且在性能上可能提升不大。
元素乘法/加法
我们从Beta分布中选取随机数来进行元素乘法(加法):
def get_ab(beta):
if np.random.random() < 0.5:
a = np.float32(np.random.beta(beta, 1))
b = np.float32(np.random.beta(1, beta))
else:
a = 1 + np.float32(np.random.beta(1, beta))
b = -np.float32(np.random.beta(1, beta))
return a, b
# 如果传进来的是Image,需要转成array
def add(img1, img2, beta):
a, b = get_ab(beta)
img1, img2 = img1 * 2 - 1, img2 * 2 - 1
out = a * img1 + b * img2
out = (out + 1) / 2
return out
def multiply(img1, img2, beta):
a, b = get_ab(beta)
img1, img2 = img1 * 2, img2 * 2
out = (img1 ** a) * (img2.clip(1e-37) ** b)
out = out / 2
return out
叠置、前后幕等方法
def screen(img1, img2, beta):
img1, img2 = invert(img1), invert(img2)
out = multiply(img1, img2, beta)
return invert(out)
def overlay(img1, img2, beta):
case1 = multiply(img1, img2, beta)
case2 = screen(img1, img2, beta)
if np.random.random() < 0.5:
cond = img1 < 0.5
else:
cond = img1 > 0.5
return np.where(cond, case1, case2)
def darken_or_lighten(img1, img2):
if np.random.random() < 0.5:
cond = img1 < img2
else:
cond = img1 > img2
return np.where(cond, img1, img2)
def swap_channel(img1, img2):
channel = np.random.randint(3)
img1[channel] = img2[channel]
return img1
图像直接相加
def imageAdd(base_img, overlay_img, alpha=0.20):
overlay_img_resized = overlay_img.resize(base_img.size)
base_array = np.array(base_img, dtype=np.float32)
overlay_array = np.array(overlay_img_resized, dtype=np.float32)
blended_array = (1 - alpha) * base_array + alpha * overlay_array
blended_array = np.clip(blended_array, 0, 255).astype(np.uint8)
blended_img = Image.fromarray(blended_array)
return blended_img
def ImageListAdd(imglist, weight=None):
n=[1/len(imglist)]*len(imglist) if not weight else weight
base_array=np.array(imglist[0],dtype=np.float32)*n[0]
for idx,i in enumerate(imglist[1:]):
i=np.array(i,dtype=np.float32)
base_array+=n[idx+1]*i
blended_array = np.clip(base_array, 0, 255).astype(np.uint8)
blended_img = Image.fromarray(blended_array)
return blended_img