[学习记录]基于小波变换的图片分解

写在前面 :本博客仅作记录学习之用,部分图片来自网络,如需使用请注明出处,同时如有侵犯您的权益,请联系删除!

前言

本博客仅为学习记录之用,目的在于后续若需要相关的有资可查。在言语上恐有诸多纰漏,如有错误,欢迎指出交流学习!
本博客所包含的大致内容: 小波介绍;基于python-opencv的RGB图像的小波分解与合成;基于PIL的RGB图像的小波分解与合成;解析命令行的简单使用。

小波变换

小波变换(wavelet transform,WT)继承和发展了短时傅立叶变换局部化的思想,同时又克服了窗口大小不随频率变化等缺点,能够提供一个随频率改变的“时间-频率”窗口,是进行信号时频分析和处理的理想工具。
主要特点:通过变换能够充分突出问题某些方面的特征,能对时间(空间)频率的局部化分析,通过伸缩平移运算对信号(函数)逐步进行多尺度细化,最终达到高频处时间细分,低频处频率细分,能自动适应时频信号分析的要求。小波变换联系了应用数学、物理学、计算机科学、信号与信息处理、图像处理、地震勘探等多个学科。[1]
对于一张图片而言,其可分为高频的纹理信息已经平滑的低频信息,而小波变化可根据选取的小波基实现高低频信号的分解,如下图。

图1
图2

更详细的原理可参考

图1来源:稍有常识的人的知乎
图2来源:维维手作的博客

基于cv2的分解与合成

对于小波的分解,一般是需要灰度图像,或者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)

基于PIL的分解与合成

和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()

效果

对于下面的美猴王为例子,进行分解后的效果展示,需要注意的是分解之后的图片大小变成了原图的一半。
美猴王

低频
高频

在这里插入图片描述

低频
高频

致谢

欲尽善本文,因所视短浅,怎奈所书皆是瞽言蒭议。行文至此,诚向予助与余者致以谢意。

  • 13
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值