写在前面 :本博客仅作记录学习之用,部分图片来自网络,如需使用请注明出处,同时如有侵犯您的权益,请联系删除!
本博客仅为学习记录之用,目的在于后续若需要相关的有资可查。在言语上恐有诸多纰漏,如有错误,欢迎指出交流学习!
本博客所包含的大致内容: 小波介绍;基于python-opencv的RGB图像的小波分解与合成;基于PIL的RGB图像的小波分解与合成;解析命令行的简单使用。
小波变换(wavelet transform,WT)继承和发展了短时傅立叶变换局部化的思想,同时又克服了窗口大小不随频率变化等缺点,能够提供一个随频率改变的“时间-频率”窗口,是进行信号时频分析和处理的理想工具。
主要特点:通过变换能够充分突出问题某些方面的特征,能对时间(空间)频率的局部化分析,通过伸缩平移运算对信号(函数)逐步进行多尺度细化,最终达到高频处时间细分,低频处频率细分,能自动适应时频信号分析的要求。小波变换联系了应用数学、物理学、计算机科学、信号与信息处理、图像处理、地震勘探等多个学科。[1]
对于一张图片而言,其可分为高频的纹理信息已经平滑的低频信息,而小波变化可根据选取的小波基实现高低频信号的分解,如下图。
|
|
更详细的原理可参考
图1来源:稍有常识的人的知乎
图2来源:维维手作的博客
对于小波的分解,一般是需要灰度图像,或者RGB图片的一个通道,也就是八位的灰度图片。因此对于一张图片可以直接转成灰度图片进行分解,也可以逐通道进行分解后再进行通道的结合。
对于cv2而言,基本的函数如下
cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#RGB转灰度图
(b, g, r) = cv2.split(img)#按bgr分解
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")#小波分解,低频+高频
cv2.merge([bcA, gcA, rcA])#RGB的低频分解按照bgr进行合成彩图
相关函数
def harr_cv2(img, gray=False): # cv2
if img.shape[-1] == 3:
if gray:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
return bcA, (bcH + bcV + bcD)
else:
(b, g, r) = cv2.split(img)
bcA, (bcH, bcV, bcD) = pywt.dwt2(b, "haar")
gcA, (gcH, gcV, gcD) = pywt.dwt2(g, "haar")
rcA, (rcH, rcV, rcD) = pywt.dwt2(r, "haar")
return (cv2.merge([bcA, gcA, rcA])), (bcV+gcV+rcV+bcH+gcH+rcH+bcD+gcD+rcD)
else:
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
return bcA, (bcH+bcV+bcD)
和cv2的介绍一致,也是转灰度或者分解后进行小波变换。
img = img.convert('L')#转灰度图
(b, g, r) = img.split()#通道分解
Image.merge('RGB', (Image.fromarray(bcA).convert('L'),
Image.fromarray(gcA).convert('L'),
Image.fromarray(rcA).convert('L'))))#merge支持的是没通道是灰度的数据,按照bgr顺序即可实现彩色的低频
def harr_PIL(img, gray=False, vh=None): # PIL
if img.mode == 'RGB':
if gray:
img = img.convert('L')
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
if vh:
return Image.fromarray(bcH).convert('RGB'), Image.fromarray(bcV).convert('RGB')
else:
return Image.fromarray(bcA).convert('RGB'), Image.fromarray((bcH+bcV+bcD)).convert('RGB')
else:
(b, g, r) = img.split()
bcA, (bcH, bcV, bcD) = pywt.dwt2(b, "haar")
gcA, (gcH, gcV, gcD) = pywt.dwt2(g, "haar")
rcA, (rcH, rcV, rcD) = pywt.dwt2(r, "haar")
if vh:
return Image.fromarray(bcH+gcH+rcH).convert('RGB'), Image.fromarray(bcV+gcV+rcV).convert('RGB')
else:
return (Image.merge('RGB', (Image.fromarray(bcA).convert('L'),
Image.fromarray(gcA).convert('L'),
Image.fromarray(rcA).convert('L')))), \
Image.fromarray(bcV+gcV+rcV+bcH+gcH+rcH+bcD+gcD+rcD).convert('L')
elif img.mode == 'RGBA':
img = img.convert('RGB')
if gray:
img = img.convert('L')
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
if vh:
return Image.fromarray(bcH).convert('RGB'), Image.fromarray(bcV).convert('RGB')
else:
return Image.fromarray(bcA), Image.fromarray((bcH+bcV+bcD))
else:
r, g, b = img.split()
bcA, (bcH, bcV, bcD) = pywt.dwt2(b, "haar")
gcA, (gcH, gcV, gcD) = pywt.dwt2(g, "haar")
rcA, (rcH, rcV, rcD) = pywt.dwt2(r, "haar")
if vh:
return Image.fromarray(bcH+gcH+rcH).convert('RGB'), Image.fromarray(bcV+gcV+rcV).convert('RGB')
else:
return (Image.merge('RGB', (Image.fromarray(bcA).convert('L'),
Image.fromarray(gcA).convert('L'),
Image.fromarray(rcA).convert('L')))),\
Image.fromarray(bcV+gcV+rcV+bcH+gcH+rcH+bcD+gcD+rcD).convert('L')
elif img.mode == 'L':
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
if vh:
return Image.fromarray(bcH).convert('RGB'), Image.fromarray(bcV).convert('RGB')
else:
return Image.fromarray(bcA), Image.fromarray((bcH+bcV+bcD))
else:
raise ValueError('please check the pic')
相比于程序直接写死运行条件,采用解析命令行的方法具有灵活性,这里是简单的使用。
def parser_options():
parser = argparse.ArgumentParser(description='haar')#实例化
parser.add_argument('--test_dir', type=bool, default=True, help='TEST DIR path')#添加可选参数,可提供默认值,以及数据类型和提示信息
parser.add_argument('--pic_path', type=str, default='img/hzgg.jpg', help='if test dir pic path, or the pic path')
parser.add_argument('--mode', type=str, default='cv2', help='cv2 or PIL')
parser.add_argument('--save_path', type=str, default='img/Result', help='save path')
parser.add_argument('--gray', type=bool, default=False, help='gray')
return parser
完整的程序可以实现文件夹图片以及单张图片的分解,若选择默认条件,直接运行python Harr.py即可得到结果。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@File :Harr.py
@Author :Xiaodong
@Function:
@Date :2022/4/7 15:25
'''
import pywt
from tqdm import tqdm
import argparse
from PIL import Image
import cv2
import os
def harr_cv2(img, gray=False): # cv2
if img.shape[-1] == 3:
if gray:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
return bcA, (bcH + bcV + bcD)
else:
(b, g, r) = cv2.split(img)
bcA, (bcH, bcV, bcD) = pywt.dwt2(b, "haar")
gcA, (gcH, gcV, gcD) = pywt.dwt2(g, "haar")
rcA, (rcH, rcV, rcD) = pywt.dwt2(r, "haar")
return (cv2.merge([bcA, gcA, rcA])), (bcV+gcV+rcV+bcH+gcH+rcH+bcD+gcD+rcD)
else:
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
return bcA, (bcH+bcV+bcD)
def harr_PIL(img, gray=False, vh=None): # PIL
if img.mode == 'RGB':
if gray:
img = img.convert('L')
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
if vh:
return Image.fromarray(bcH).convert('RGB'), Image.fromarray(bcV).convert('RGB')
else:
return Image.fromarray(bcA).convert('RGB'), Image.fromarray((bcH+bcV+bcD)).convert('RGB')
else:
(b, g, r) = img.split()
bcA, (bcH, bcV, bcD) = pywt.dwt2(b, "haar")
gcA, (gcH, gcV, gcD) = pywt.dwt2(g, "haar")
rcA, (rcH, rcV, rcD) = pywt.dwt2(r, "haar")
if vh:
return Image.fromarray(bcH+gcH+rcH).convert('RGB'), Image.fromarray(bcV+gcV+rcV).convert('RGB')
else:
return (Image.merge('RGB', (Image.fromarray(bcA).convert('L'),
Image.fromarray(gcA).convert('L'),
Image.fromarray(rcA).convert('L')))), \
Image.fromarray(bcV+gcV+rcV+bcH+gcH+rcH+bcD+gcD+rcD).convert('L')
elif img.mode == 'RGBA':
img = img.convert('RGB')
if gray:
img = img.convert('L')
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
if vh:
return Image.fromarray(bcH).convert('RGB'), Image.fromarray(bcV).convert('RGB')
else:
return Image.fromarray(bcA), Image.fromarray((bcH+bcV+bcD))
else:
r, g, b = img.split()
bcA, (bcH, bcV, bcD) = pywt.dwt2(b, "haar")
gcA, (gcH, gcV, gcD) = pywt.dwt2(g, "haar")
rcA, (rcH, rcV, rcD) = pywt.dwt2(r, "haar")
if vh:
return Image.fromarray(bcH+gcH+rcH).convert('RGB'), Image.fromarray(bcV+gcV+rcV).convert('RGB')
else:
return (Image.merge('RGB', (Image.fromarray(bcA).convert('L'),
Image.fromarray(gcA).convert('L'),
Image.fromarray(rcA).convert('L')))),\
Image.fromarray(bcV+gcV+rcV+bcH+gcH+rcH+bcD+gcD+rcD).convert('L')
elif img.mode == 'L':
bcA, (bcH, bcV, bcD) = pywt.dwt2(img, "haar")
if vh:
return Image.fromarray(bcH).convert('RGB'), Image.fromarray(bcV).convert('RGB')
else:
return Image.fromarray(bcA), Image.fromarray((bcH+bcV+bcD))
else:
raise ValueError('please check the pic')
def parser_options():
parser = argparse.ArgumentParser(description='haar')
parser.add_argument('--test_dir', type=bool, default=True, help='TEST DIR path')
parser.add_argument('--pic_path', type=str, default='img/hzgg.jpg', help='if test dir pic path, or the pic path')
parser.add_argument('--mode', type=str, default='cv2', help='cv2 or PIL')
parser.add_argument('--save_path', type=str, default='img/Result', help='save path')
parser.add_argument('--gray', type=bool, default=False, help='gray')
return parser
def main():
parser = parser_options()
args = parser.parse_args()#获得输入参数的信息
if not args.test_dir:
if not os.path.exists(args.save_path):
os.makedirs(args.save_path)
if args.mode == 'cv2':
pic = cv2.imread(args.pic_path)
if pic is None:
pass
low, high = harr_cv2(pic, args.gray)
cv2.imwrite(f'{args.save_path}/low.png', low)
cv2.imwrite(f'{args.save_path}/high.png', high)
elif args.mode == 'PIL':
pic = Image.open(args.pic_path)
low, high = harr_PIL(pic, args.gray)
low.save(f'{args.save_path}/low.png')
high.save(f'{args.save_path}/high.png')
else:
pics = os.listdir(args.pic_path)
if not os.path.exists(args.save_path):
os.makedirs(args.save_path)
if args.mode == 'cv2':
for i, pic in enumerate(tqdm(pics)):
name = pic.split('.')[0]
pic = cv2.imread(os.path.join(args.pic_path, pic))
low, high = harr_cv2(pic, args.gray)
cv2.imwrite(f'{args.save_path}/{name}_low.png', low)
cv2.imwrite(f'{args.save_path}/{name}_high.png', high)
elif args.mode == 'PIL':
for i, pic in enumerate(tqdm(pics)):
name = pic.split('.')[0]
pic = Image.open(os.path.join(args.pic_path, pic))
low, high = harr_PIL(pic, args.gray)
print(pic)
low.save(f"{args.save_path}/{name}_low.png")
high.save(f'{args.save_path}/{name}_high.png')
if __name__ == '__main__':
main()
对于下面的美猴王为例子,进行分解后的效果展示,需要注意的是分解之后的图片大小变成了原图的一半。
|
|
|
|
欲尽善本文,因所视短浅,怎奈所书皆是瞽言蒭议。行文至此,诚向予助与余者致以谢意。