在每个人的手机相册功能中,都可以找到“滤镜”这一功能。这种滤镜就是简单的图像风格转换,本篇文章将使用OpenCV库对图像进行多种风格的处理,包括复古风格、油画和素描效果。同时,考虑到后续项目中的可调用性。这里先简单的将不同的风格转换方法封装起来,以备后续的进一步修改。
【注1】本篇文章同样以方圆圆的《人脸识别与美颜算法实战-基于python、机器学习与深度学习》一书为理论依据,在原书的代码中进行修改和优化!
【注2】本系列的所有代码,均在win11系统、python3.9、pycharm2023及以上版本中实现。若无具体要求,可根据开源代码中的requirments.txt文件进行相同配置!开源链接及后续项目的代码统一见文章最后!
1. 复古风格
复古风格处理是通过修改图像的颜色值来模拟老旧照片的效果。具体实现通过对每个像素点的RGB值进行线性变换来实现。这段代码对每个像素的RGB值进行线性变换来生成复古效果。通过特定的系数对原始的RGB值进行加权计算,并对结果进行裁剪以确保像素值在0到255之间。
def retro_style(img):
img2 = img.copy()
height, width, n = img.shape
for i in range(height):
for j in range(width):
b, g, r = img[i, j]
# 计算新的图像中的RGB值
B = int(0.272 * r + 0.534 * g + 0.131 * b)
G = int(0.349 * r + 0.686 * g + 0.168 * b)
R = int(0.393 * r + 0.769 * g + 0.189 * b)
# 约束图像像素值,防止溢出
img2[i, j] = [max(0, min(B, 255)), max(0, min(G, 255)), max(0, min(R, 255))]
return img2
在这里,可以使用NumPy进行矢量化操作,避免循环。同时,提前计算变换矩阵,简化计算过程。优化后的代码如下所示:
import cv2
import numpy as np
def retro_style(img):
# 计算变换矩阵
transformation_matrix = np.array([[0.272, 0.534, 0.131],
[0.349, 0.686, 0.168],
[0.393, 0.769, 0.189]])
# 使用矩阵变换进行复古处理
img2 = np.dot(img[..., :3], transformation_matrix.T)
# 约束图像像素值在0到255之间
img2 = np.clip(img2, 0, 255).astype(np.uint8)
return img2
def resize_image(img, max_size=800):
height, width = img.shape[:2]
if max(height, width) > max_size:
scaling_factor = max_size / float(max(height, width))
img = cv2.resize(img, None, fx=scaling_factor, fy=scaling_factor, interpolation=cv2.INTER_AREA)
return img
def retro_style_main(img_path):
img = cv2.imread(img_path)
retro_img = retro_style(img)
resized_img = resize_image(retro_img)
cv2.imshow("Retro Style Image", resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 例如:
# retro_style_main("path_to_your_image.jpg")
实现效果:
2. 素描风格
下面这段代码将输入图像转换为素描风格的效果。
def sketch_style(img, maxsize=800):
height, width, _ = img.shape # 获取图像的高度和宽度
gray0 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 将图像转换为灰度图
# 创建一个与原图像大小相同的黑色图像
img2 = np.zeros((height, width), dtype='uint8')
# 使用加权和的方法进行图像反转,创建类似负片效果的图像
gray1 = cv2.addWeighted(gray0, -1, img2, 0, 255, 0)
# 使用高斯模糊平滑图像,调整模糊内核大小和标准差
gray1 = cv2.GaussianBlur(gray1, (15, 15), 0)
# 增加对比度
gray1 = cv2.convertScaleAbs(gray1, alpha=1.5, beta=0)
# 将原始灰度图和模糊后的负片图像混合,调整混合权重
dst = cv2.addWeighted(gray0, 0.7, gray1, 0.3, 0)
# 反转颜色,使之变为白底黑画
dst = cv2.bitwise_not(dst)
# 调整输出图像大小并保持长宽比
dst = resize_with_aspect_ratio(dst, maxsize)
# 显示素描效果图像
cv2.imshow('sketch_img', dst)
def sketch_style_main(img_path, max_size=800):
# 读取输入图像
img = cv2.imread(img_path)
if img is None:
print(f"Error: Unable to load image at {img_path}")
return
# 应用素描风格处理
sketch_style(img, max_size)
# 等待按键事件并关闭所有窗口
cv2.waitKey(0)
cv2.destroyAllWindows()
首先,通过 `sketch_style_main` 函数读取输入图像文件并检查是否成功读取,如果失败则输出错误信息并返回。接着调用 `sketch_style` 函数对图像进行处理。在 `sketch_style` 函数中,首先获取图像的高度和宽度,然后将图像转换为灰度图。接着创建一个与原图像大小相同的全黑图像,并使用加权和方法将灰度图像反转,生成一个类似负片效果的图像。对负片图像进行高斯模糊处理使图像变得更加平滑,并增加其对比度。然后将原始灰度图和模糊后的负片图像混合,调整权重使得效果更接近素描风格。再通过反转颜色将图像变为白底黑画,并调整输出图像的大小以保持长宽比。最后,显示处理后的素描效果图像,并在等待按键事件后关闭所有显示窗口。
实现效果:
3. 油画风格
下面这段代码通过 oil_style_main
函数实现了将输入图像转换为油画风格并增强颜色的效果。首先,oil_style_main
函数读取输入图像文件,并检查图像是否成功读取,如果失败则输出错误信息并返回。接着调用 oil_style
函数,该函数通过遍历图像的每个像素,随机选择邻近像素的颜色值来生成油画效果图像。然后,调用 color_add
函数,该函数将油画效果图像转换为 PIL 图像并使用 ImageEnhance.Color
增强颜色,最终将图像转换回 OpenCV 格式。处理完毕后,oil_style_main
函数显示最终处理后的图像,并在等待按键事件后关闭所有显示窗口。优化后的代码确保只生成和显示最终的图像,不再创建中间图像文件。
def oil_style(img):
height, width, n = img.shape
output = np.zeros((height, width, n), dtype='uint8')
for i in range(1, height - 1):
for j in range(1, width - 1):
rand_choice = random.randint(0, 2)
if rand_choice == 0:
output[i, j] = img[i + 1, j]
elif rand_choice == 1:
output[i, j] = img[i - 1, j]
else:
output[i, j] = img[i, j - 1]
return output
def color_add(img):
image = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
enhancer = ImageEnhance.Color(image)
image_colored = enhancer.enhance(2.0)
return cv2.cvtColor(np.array(image_colored), cv2.COLOR_RGB2BGR)
def oil_style_main(img_path, maxsize=800):
img = cv2.imread(img_path)
if img is None:
print(f"Error: Unable to load image at {img_path}")
return
oil_img = oil_style(img)
final_img = color_add(oil_img)
final_img = resize_with_aspect_ratio(final_img, maxsize)
cv2.imshow("Oil Painting Style Image", final_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果:
4. 项目开源地址
后续项目及本代码的更新地址如下所示,如有问题请私信或者评论区留言。https://github.com/damoshishen/FRBA