当前位置:

首页 > 编程开发 > 使用Python代码去除图像中的摩尔纹纹理

使用Python代码去除图像中的摩尔纹纹理

1、前言当感光元件像素的空间频率与影像中条纹的空间频率接近时,可能产生一种新的波浪形的干扰图案,即所谓的摩尔纹。传感器的网格状纹理构成了一个这样的图案。当图案中的细条状结构与传感器的结构以小角度交叉时,这种效应也会在图像中产生明显的干扰。这种现象在一些细密纹理情况下,比如时尚摄影中的布料上,非常普遍。这种摩尔纹可能通过亮度也可能通过颜色来展现。但是在这里,仅针对在翻拍过程中产生的图像摩尔纹进行处理。翻拍即从计算机屏幕上捕获图片,或对着屏幕拍摄图片;该方式会在图片上产生摩尔纹现象论文主要处理思路对原图作Ha

本文目录

    1、前言

    当感光元件像素的空间频率与影像中条纹的空间频率接近时,可能产生一种新的波浪形的干扰图案,即所谓的摩尔纹。传感器的网格状纹理构成了一个这样的图案。当图案中的细条状结构与传感器的结构以小角度交叉时,这种效应也会在图像中产生明显的干扰。这种现象在一些细密纹理情况下,比如时尚摄影中的布料上,非常普遍。这种摩尔纹可能通过亮度也可能通过颜色来展现。但是在这里,仅针对在翻拍过程中产生的图像摩尔纹进行处理。

    翻拍即从计算机屏幕上捕获图片,或对着屏幕拍摄图片;该方式会在图片上产生摩尔纹现象

    使用Python代码去除图像中的摩尔纹纹理

    论文主要处理思路

    • 对原图作Haar变换得到四个下采样特征图(原图下二采样cA、Horizontal横向高频cH、Vertical纵向高频cV、Diagonal斜向高频cD)

    • 然后分别利用四个独立的CNN对四个下采样特征图卷积池化,提取特征信息

    • 原文随后对三个高频信息卷积池化后的结果的每个channel、每个像素点比对,取max

    • 将上一步得到的结果和cA卷积池化后的结果作笛卡尔积

    论文地址

    2、网络结构复现

      如下图所示,本项目复现了论文的图像去摩尔纹方法,并对数据处理部分进行了修改,并且网络结构上也参考了源码中的结构,对图片产生四个下采样特征图,而不是论文中的三个,具体处理方式大家可以参考一下网络结构。

    使用Python代码去除图像中的摩尔纹纹理

    import math
    import paddle
    import paddle.nn as nn
    import paddle.nn.functional as F
    # import pywt
    from paddle.nn import Linear, Dropout, ReLU
    from paddle.nn import Conv2D, MaxPool2D
    class mcnn(nn.Layer):
        def __init__(self, num_classes=1000):
            super(mcnn, self).__init__()
            self.num_classes = num_classes
            self._conv1_LL = Conv2D(3,32,7,stride=2,padding=1,)      
            # self.bn1_LL = nn.BatchNorm2D(128)
            self._conv1_LH = Conv2D(3,32,7,stride=2,padding=1,)  
            # self.bn1_LH = nn.BatchNorm2D(256)
            self._conv1_HL = Conv2D(3,32,7,stride=2,padding=1,)
            # self.bn1_HL = nn.BatchNorm2D(512)
            self._conv1_HH = Conv2D(3,32,7,stride=2,padding=1,)
            # self.bn1_HH = nn.BatchNorm2D(256)
            self.pool_1_LL = nn.MaxPool2D(kernel_size=2,stride=2, padding=0)
            self.pool_1_LH = nn.MaxPool2D(kernel_size=2,stride=2, padding=0)
            self.pool_1_HL = nn.MaxPool2D(kernel_size=2,stride=2, padding=0)
            self.pool_1_HH = nn.MaxPool2D(kernel_size=2,stride=2, padding=0)
            self._conv2 = Conv2D(32,16,3,stride=2,padding=1,)
            self.pool_2 = nn.MaxPool2D(kernel_size=2,stride=2, padding=0)
            self.dropout2 = Dropout(p=0.5)
            self._conv3 = Conv2D(16,32,3,stride=2,padding=1,)
            self.pool_3 = nn.MaxPool2D(kernel_size=2,stride=2, padding=0)
            self._conv4 = Conv2D(32,32,3,stride=2,padding=1,)
            self.pool_4 = nn.MaxPool2D(kernel_size=2,stride=2, padding=0)
            self.dropout4 = Dropout(p=0.5)
            # self.bn1_HH = nn.BatchNorm1D(256)
            self._fc1 = Linear(in_features=64,out_features=num_classes)
            self.dropout5 = Dropout(p=0.5)
            self._fc2 = Linear(in_features=2,out_features=num_classes)
        def forward(self, inputs1, inputs2, inputs3, inputs4):
            x1_LL = self._conv1_LL(inputs1)
            x1_LL = F.relu(x1_LL)
            x1_LH = self._conv1_LH(inputs2)
            x1_LH = F.relu(x1_LH)
            x1_HL = self._conv1_HL(inputs3)
            x1_HL = F.relu(x1_HL)
            x1_HH = self._conv1_HH(inputs4)
            x1_HH = F.relu(x1_HH)
            pool_x1_LL = self.pool_1_LL(x1_LL)
            pool_x1_LH = self.pool_1_LH(x1_LH)
            pool_x1_HL = self.pool_1_HL(x1_HL)
            pool_x1_HH = self.pool_1_HH(x1_HH)
            temp = paddle.maximum(pool_x1_LH, pool_x1_HL)
            avg_LH_HL_HH = paddle.maximum(temp, pool_x1_HH)
            inp_merged = paddle.multiply(pool_x1_LL, avg_LH_HL_HH)
            x2 = self._conv2(inp_merged)
            x2 = F.relu(x2)
            x2 = self.pool_2(x2)
            x2 = self.dropout2(x2)
            x3 = self._conv3(x2)
            x3 = F.relu(x3)
            x3 = self.pool_3(x3)
            x4 = self._conv4(x3)
            x4 = F.relu(x4)
            x4 = self.pool_4(x4)
            x4 = self.dropout4(x4)
            x4 = paddle.flatten(x4, start_axis=1, stop_axis=-1)
            x5 = self._fc1(x4)
            x5 = self.dropout5(x5)
            out = self._fc2(x5)
            return out
    model_res = mcnn(num_classes=2)
    paddle.summary(model_res,[(1,3,512,384),(1,3,512,384),(1,3,512,384),(1,3,512,384)])
    ---------------------------------------------------------------------------
     Layer (type)       Input Shape          Output Shape         Param #    
    ===========================================================================
       Conv2D-1      [[1, 3, 512, 384]]   [1, 32, 254, 190]        4,736     
       Conv2D-2      [[1, 3, 512, 384]]   [1, 32, 254, 190]        4,736     
       Conv2D-3      [[1, 3, 512, 384]]   [1, 32, 254, 190]        4,736     
       Conv2D-4      [[1, 3, 512, 384]]   [1, 32, 254, 190]        4,736     
      MaxPool2D-1   [[1, 32, 254, 190]]    [1, 32, 127, 95]          0       
      MaxPool2D-2   [[1, 32, 254, 190]]    [1, 32, 127, 95]          0       
      MaxPool2D-3   [[1, 32, 254, 190]]    [1, 32, 127, 95]          0       
      MaxPool2D-4   [[1, 32, 254, 190]]    [1, 32, 127, 95]          0       
       Conv2D-5      [[1, 32, 127, 95]]    [1, 16, 64, 48]         4,624     
      MaxPool2D-5    [[1, 16, 64, 48]]     [1, 16, 32, 24]           0       
       Dropout-1     [[1, 16, 32, 24]]     [1, 16, 32, 24]           0       
       Conv2D-6      [[1, 16, 32, 24]]     [1, 32, 16, 12]         4,640     
      MaxPool2D-6    [[1, 32, 16, 12]]      [1, 32, 8, 6]            0       
       Conv2D-7       [[1, 32, 8, 6]]       [1, 32, 4, 3]          9,248     
      MaxPool2D-7     [[1, 32, 4, 3]]       [1, 32, 2, 1]            0       
       Dropout-2      [[1, 32, 2, 1]]       [1, 32, 2, 1]            0       
       Linear-1          [[1, 64]]              [1, 2]              130      
       Dropout-3          [[1, 2]]              [1, 2]               0       
       Linear-2           [[1, 2]]              [1, 2]               6       
    ===========================================================================
    Total params: 37,592
    Trainable params: 37,592
    Non-trainable params: 0
    ---------------------------------------------------------------------------
    Input size (MB): 9.00
    Forward/backward pass size (MB): 59.54
    Params size (MB): 0.14
    Estimated Total Size (MB): 68.68
    ---------------------------------------------------------------------------
    {'total_params': 37592, 'trainable_params': 37592}

    3、数据预处理

      与源代码不同的是,本项目将图像的小波分解部分集成在了数据读取部分,即改为了线上进行小波分解,而不是源代码中的线下进行小波分解并且保存图片。首先,定义小波分解的函数

    !pip install PyWavelets
    import numpy as np
    import pywt
    def splitFreqBands(img, levRows, levCols):
        halfRow = int(levRows/2)
        halfCol = int(levCols/2)
        LL = img[0:halfRow, 0:halfCol]
        LH = img[0:halfRow, halfCol:levCols]
        HL = img[halfRow:levRows, 0:halfCol]
        HH = img[halfRow:levRows, halfCol:levCols]
        return LL, LH, HL, HH
    def haarDWT1D(data, length):
        avg0 = 0.5;
        avg1 = 0.5;
        dif0 = 0.5;
        dif1 = -0.5;
        temp = np.empty_like(data)
        # temp = temp.astype(float)
        temp = temp.astype(np.uint8)
        h = int(length/2)
        for i in range(h):
            k = i*2
            temp[i] = data[k] * avg0 + data[k + 1] * avg1;
            temp[i + h] = data[k] * dif0 + data[k + 1] * dif1;
        data[:] = temp
    # computes the homography coefficients for PIL.Image.transform using point correspondences
    def fwdHaarDWT2D(img):
        img = np.array(img)
        levRows = img.shape[0];
        levCols = img.shape[1];
        # img = img.astype(float)
        img = img.astype(np.uint8)
        for i in range(levRows):
            row = img[i,:]
            haarDWT1D(row, levCols)
            img[i,:] = row
        for j in range(levCols):
            col = img[:,j]
            haarDWT1D(col, levRows)
            img[:,j] = col
        return splitFreqBands(img, levRows, levCols)
    !cd "data/data188843/" && unzip -q 'total_images.zip'
    import os 
    recapture_keys = [ 'ValidationMoire']
    original_keys = ['ValidationClear']
    def get_image_label_from_folder_name(folder_name):
        """
        :param folder_name:
        :return:
        """
        for key in original_keys:
            if key in folder_name:
                return 'original'
        for key in recapture_keys:
            if key in folder_name:
                return 'recapture'
        return 'unclear'
    label_name2label_id = {
        'original': 0,
        'recapture': 1,}
    src_image_dir = "data/data188843/total_images"
    dst_file = "data/data188843/total_images/train.txt"
    image_folder = [file for file in os.listdir(src_image_dir)]
    print(image_folder)
    image_anno_list = []
    for folder in image_folder:
        label_name = get_image_label_from_folder_name(folder)
        # label_id = label_name2label_id.get(label_name, 0)
        label_id = label_name2label_id[label_name]
        folder_path = os.path.join(src_image_dir, folder)
        image_file_list = [file for file in os.listdir(folder_path) if
                            file.endswith('.jpg') or file.endswith('.jpeg') or
                            file.endswith('.JPG') or file.endswith('.JPEG') or file.endswith('.png')]
        for image_file in image_file_list:
            # if need_root_dir:
            #     image_path = os.path.join(folder_path, image_file)
            # else:
            image_path = image_file
            image_anno_list.append(folder +"/"+image_path +"\t"+ str(label_id) + '\n')
    dst_path = os.path.dirname(src_image_dir)
    if not os.path.exists(dst_path):
        os.makedirs(dst_path)
    with open(dst_file, 'w') as fd:
        fd.writelines(image_anno_list)
    import paddle
    import numpy as np
    import pandas as pd
    import PIL.Image as Image
    from paddle.vision import transforms
    # from haar2D import fwdHaarDWT2D
    paddle.disable_static()
    # 定义数据预处理
    data_transforms = transforms.Compose([
        transforms.Resize(size=(448,448)),
        transforms.ToTensor(), # transpose操作 + (img / 255)
        # transforms.Normalize(      # 减均值 除标准差
        #     mean=[0.31169346, 0.25506335, 0.12432463],        
        #     std=[0.34042713, 0.29819837, 0.1375536])
        #计算过程:output[channel] = (input[channel] - mean[channel]) / std[channel]
    ])
    # 构建Dataset
    class MyDataset(paddle.io.Dataset):
        """
        步骤一:继承paddle.io.Dataset类
        """
        def __init__(self, train_img_list, val_img_list, train_label_list, val_label_list, mode='train', ):
            """
            步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集
            """
            super(MyDataset, self).__init__()
            self.img = []
            self.label = []
            # 借助pandas读csv的库
            self.train_images = train_img_list
            self.test_images = val_img_list
            self.train_label = train_label_list
            self.test_label = val_label_list
            if mode == 'train':
                # 读train_images的数据
                for img,la in zip(self.train_images, self.train_label):
                    self.img.append('/home/aistudio/data/data188843/total_images/'+img)
                    self.label.append(paddle.to_tensor(int(la), dtype='int64'))
            else:
                # 读test_images的数据
                for img,la in zip(self.test_images, self.test_label):
                    self.img.append('/home/aistudio/data/data188843/total_images/'+img)
                    self.label.append(paddle.to_tensor(int(la), dtype='int64'))
        def load_img(self, image_path):
            # 实际使用时使用Pillow相关库进行图片读取即可,这里我们对数据先做个模拟
            image = Image.open(image_path).convert('RGB')
            # image = data_transforms(image)
            return image
        def __getitem__(self, index):
            """
            步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
            """
            image = self.load_img(self.img[index])
            LL, LH, HL, HH = fwdHaarDWT2D(image)
            label = self.label[index]
            # print(LL.shape)
            # print(LH.shape)
            # print(HL.shape)
            # print(HH.shape)
            LL = data_transforms(LL)
            LH = data_transforms(LH)
            HL = data_transforms(HL)
            HH = data_transforms(HH)
            print(type(LL))
            print(LL.dtype)
            return LL, LH, HL, HH, np.array(label, dtype='int64')
        def __len__(self):
            """
            步骤四:实现__len__方法,返回数据集总数目
            """
            return len(self.img)
    image_file_txt = '/home/aistudio/data/data188843/total_images/train.txt'
    with open(image_file_txt) as fd:
        lines = fd.readlines()
    train_img_list = list()
    train_label_list = list()
    for line in lines:
        split_list = line.strip().split()
        image_name, label_id = split_list
        train_img_list.append(image_name)
        train_label_list.append(label_id)
    # print(train_img_list)
    # print(train_label_list)
    # 测试定义的数据集
    train_dataset = MyDataset(mode='train',train_label_list=train_label_list,  train_img_list=train_img_list, val_img_list=train_img_list, val_label_list=train_label_list)
    # test_dataset = MyDataset(mode='test')
    # 构建训练集数据加载器
    train_loader = paddle.io.DataLoader(train_dataset, batch_size=2, shuffle=True)
    # 构建测试集数据加载器
    valid_loader = paddle.io.DataLoader(train_dataset, batch_size=2, shuffle=True)
    print('=============train dataset=============')
    for LL, LH, HL, HH, label in train_dataset:
        print('label: {}'.format(label))
        break

    4、模型训练

    model2 = paddle.Model(model_res)
    model2.prepare(optimizer=paddle.optimizer.Adam(parameters=model2.parameters()),
                  loss=nn.CrossEntropyLoss(),
                  metrics=paddle.metric.Accuracy())
    model2.fit(train_loader,
            valid_loader,
            epochs=5,
            verbose=1,
            )
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。