>  기사  >  백엔드 개발  >  Python 코드를 사용하여 이미지에서 모아레를 제거하는 방법

Python 코드를 사용하여 이미지에서 모아레를 제거하는 방법

PHPz
PHPz앞으로
2023-05-16 22:40:24992검색

1. 소개

감광 요소의 픽셀 공간 주파수가 이미지 줄무늬의 공간 주파수에 가까우면 소위 모아레 패턴이라는 새로운 물결 모양의 간섭 패턴이 생성될 수 있습니다. 센서의 격자형 질감은 그러한 패턴 중 하나를 만듭니다. 패턴의 얇은 스트립이 센서 구조와 작은 각도로 교차하면 이미지에 눈에 띄는 간섭 효과가 발생합니다. 이러한 현상은 천과 같이 미세한 질감을 지닌 패션 사진에서 매우 흔히 발생합니다. 이 모아레 패턴은 밝기나 색상을 통해 나타날 수 있습니다. 하지만 여기서는 리메이크 과정에서 생성된 모아레 이미지만 처리됩니다.

Recapture는 컴퓨터 화면에서 사진을 캡처하거나 화면을 배경으로 사진을 찍는 것입니다. 이 방법은 사진에 모아레 현상을 생성합니다

Python 코드를 사용하여 이미지에서 모아레를 제거하는 방법

종이의 주요 처리 아이디어

  • 원본 이미지는 Haar 변환을 통해 얻은 것입니다. 4개의 다운 샘플링된 특징 맵(원본 이미지 아래의 2샘플링된 cA, 수평 수평 고주파 cH, 수직 수직 고주파 cV, 대각선 경사 고주파 cD)

  • 그런 다음 4개의 독립적인 CNN을 사용하여 4개의 특징 맵 컨볼루션 및 풀링을 다운샘플링하고 특징 정보를 추출합니다

  • 원본 텍스트는 3개의 고주파 정보 컨볼루션 및 풀링 결과의 각 채널과 각 픽셀을 비교하고 최대

  • 를 가져옵니다.

    이전 단계를 완료하려면 얻은 결과와 cA 컨볼루션 풀링 후의 결과를 Cartesian product로 만듭니다

Paper address

2. 네트워크 구조의 재현

  아래 그림과 같이 프로젝트는 종이의 모아레 방식 이미지를 재현하고, 데이터 처리 부분이 수정되었으며, 네트워크 구조도 소스 코드의 구조를 참조하여 종이에 있는 3개가 아닌 이미지에 대해 4개의 다운샘플링 특징 맵이 생성되었습니다. . 구체적인 처리 방법을 참조할 수 있습니다.

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,
        )
.

위 내용은 Python 코드를 사용하여 이미지에서 모아레를 제거하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제