赞
踩
在每个人的手机相册功能中,都可以找到“滤镜”这一功能。这种滤镜就是简单的图像风格转换,本篇文章将使用OpenCV库对图像进行多种风格的处理,包括复古风格、油画和素描效果。同时,考虑到后续项目中的可调用性。这里先简单的将不同的风格转换方法封装起来,以备后续的进一步修改。
【注1】本篇文章同样以方圆圆的《人脸识别与美颜算法实战-基于python、机器学习与深度学习》一书为理论依据,在原书的代码中进行修改和优化!
【注2】本系列的所有代码,均在win11系统、python3.9、pycharm2023及以上版本中实现。若无具体要求,可根据开源代码中的requirments.txt文件进行相同配置!开源链接及后续项目的代码统一见文章最后!
复古风格处理是通过修改图像的颜色值来模拟老旧照片的效果。具体实现通过对每个像素点的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")
实现效果:
下面这段代码将输入图像转换为素描风格的效果。
- 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` 函数中,首先获取图像的高度和宽度,然后将图像转换为灰度图。接着创建一个与原图像大小相同的全黑图像,并使用加权和方法将灰度图像反转,生成一个类似负片效果的图像。对负片图像进行高斯模糊处理使图像变得更加平滑,并增加其对比度。然后将原始灰度图和模糊后的负片图像混合,调整权重使得效果更接近素描风格。再通过反转颜色将图像变为白底黑画,并调整输出图像的大小以保持长宽比。最后,显示处理后的素描效果图像,并在等待按键事件后关闭所有显示窗口。
实现效果:
下面这段代码通过 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()
运行效果:
后续项目及本代码的更新地址如下所示,如有问题请私信或者评论区留言。https://github.com/damoshishen/FRBA
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。