Proceso de uso básico de SR

        Desde que estudié recientemente varios modelos de superresolución BasicSR, surgieron muchos problemas durante las pruebas de varios experimentos, aquí hay algunas soluciones a estos problemas. Por ejemplo, como el problema que encontré esta vez, ¿cómo deberíamos solucionarlo cuando los datos de la imagen de entrada son particularmente pequeños? Este artículo solo proporciona una descripción parcial de la instalación, el uso y la implementación de cierta atención al uso de BasicSR para el uso y comparación de modelos.

 1. Instalación

El tutorial de instalación se proporciona en el documento del Sr. Wang Xintao. Dado que es posible que a muchos estudiantes no les guste descargar el documento oficial para leerlo, reescribiré el proceso de instalación aquí. Y hable sobre las ventajas y desventajas de estos dos métodos de instalación.

BasicSR se desarrolla en base al marco de aprendizaje profundo de pytorch. Por lo tanto, se recomienda a aquellos estudiantes que solo hayan visto tensorflow que echen un vistazo a la documentación de la interfaz API de pytorch ( documentación de PyTorch — documentación de PyTorch 1.13 ), puede ser más conveniente leer su documentación. Si desea ejecutar en la GPU, debe configurar de antemano el entorno CUDA correspondiente en su computadora. Pero como mi computadora no tiene GPU, uso el entorno que se ha configurado en el servidor. Entonces puedes buscar en Google el tutorial para configurar CUDA, aquí no es problemático.

Instalación de código de clonación local (se recomienda para estudiantes que quieran probar varios modelos localmente y quieran estudiar y modificar el código fuente)

1. Clona el proyecto:
        git clone https://github.com/XPixelGroup/BasicSR.git

2. Instale paquetes de dependencia:

        Los requisitos de versión de los paquetes dependientes de este entorno se han compilado en requisitos.txt.

cd BasicSR
pip install -r requirements.txt

3. Instale BasicSR en el directorio raíz de BasicSR:

python setup.py develop

Si desea especificar la ruta CUDA durante la instalación, puede usar el siguiente comando: (Por supuesto, también puede especificarla manualmente mientras el programa se está ejecutando, por lo que este paso es opcional)

CUDA_HOME=/usr/local/cuda \
CUDNN_INCLUDE_DIR=/usr/local/cuda \
CUDNN_LIB_DIR=/usr/local/cuda \
python setup.py develop

Instalar a través de pip

Para instalar BasicSR usando pip, simplemente ejecute el siguiente comando en la terminal:

pip install basicsr

Si desea especificar la ruta CUDA durante la instalación, puede utilizar el siguiente comando:

CUDA_HOME=/usr/local/cuda \
CUDNN_INCLUDE_DIR=/usr/local/cuda \
CUDNN_LIB_DIR=/usr/local/cuda \
pip install basicsr

Verifique que BasicSR esté instalado correctamente

 Si no se informa ningún error en este momento, significa que BasicSR se instaló correctamente y ahora puede desarrollar en base a BasicSR ~~~

 2. Interpretación básica del catálogo.

Esta parte escrita por Wang Xintao es bastante detallada. Aquí describiré a qué todos deben prestar atención al usarlo según mi comprensión y uso en los últimos días.

El rojo indica archivos directamente relacionados con la ejecución de experimentos, es decir, los archivos con los que habitualmente tratamos más;

El azul indica otros archivos de código que están fuertemente relacionados con BasicSR;

El negro representa el perfil.

En el repositorio de BasicSR, el código principal está en la carpeta basicsr. Esta parte contiene principalmente archivos de código comúnmente utilizados en modelos de aprendizaje profundo, como estructura de red, función de pérdida y carga de datos, etc. El directorio específico es el siguiente.

Entre ellos, el rojo indica los archivos que modificamos principalmente durante el desarrollo.

 

(Cabe señalar aquí, ¿por qué? El archivo rojo mencionado anteriormente es de hecho un lugar donde podemos modificarlo, pero existen requisitos estrictos en su código para el tamaño de la imagen. ¡Por lo tanto, debe tener cuidado al modificarlo! Así que tenga cuidado Asegúrate de modificarlo . ¡Ten cuidado! ¡Así que ten cuidado al modificarlo! )

Dado que algunos scripts también son necesarios en el diseño y desarrollo de algoritmos, como el preprocesamiento de datos, el cálculo de indicadores, etc., los archivos relevantes se encuentran en los scripts y el directorio es el siguiente

 Los scripts anteriores son básicamente una preparación de datos, que pueden descargar datos y muchos modelos de datos. Pero un problema es que es posible que algunos de los modelos de datos previamente entrenados no sean accesibles en China. Necesitas superar el muro, por lo que necesitas encontrar otros recursos.

Sin embargo, puede haber muchos problemas en este script que no pueden resolver los problemas que realmente queremos abordar, por lo que podemos escribir los scripts de datos en la etapa de procesamiento nosotros mismos.

3. Preprocesamiento de datos

La imagen que usé esta vez era demasiado pequeña, por lo que hubo un problema de tamaño cuando usé su modelo de superresolución ESRGAN directamente aquí. Entonces aquí solo puedo cambiar el tamaño de mis datos actuales de tamaño pequeño.

Algunos estudiantes pueden decir: ¿El cambio de tamaño no perderá la precisión de la imagen? Sí. Yo también tuve este problema en ese momento y luego experimenté. En este punto, solo mencionaremos brevemente cómo realicé la prueba, puedes consultar mis ideas. Amplié su foto y usé

        1. Bicúbico (interpolación bicúbica) escala la imagen (¿por qué utilizar la diferencia bicúbica? Para su comodidad, a continuación enumero sus ventajas y desventajas, incluido su algoritmo de interpolación bicúbica)

        2. Utilice resize() en cv2 para escalar la imagen ampliada en 1

        3. Juzgue el efecto comparando los valores de PSNR y SSIM.

   

 

# 双三次插值算法    img:图像,dstH:目标图像的高 dstW: 目的图像的宽
def BiCubic_interpolation(img, dstH, dstW):
    scrH, scrW, _= img.shape
    retimg = np.zeros((dstH, dstW, 3), dtype=np.uint8)
    for i in range(dstH):
        for j in range(dstW):
            scrx = i*(scrH/dstH)
            scry = j*(scrW/dstW)
            x = math.floor(scrx)    # floor向下取整
            y = math.floor(scry)
            u = scrx-x
            v = scry-y
            tmp = 0
            for ii in range(-1, 2):
                for jj in range(-1, 2):
                    if x+ii < 0 or y+jj < 0 or x+ii >= scrH or y+jj >= scrW:
                        continue
                    tmp += img[x+ii, y+jj] * BiBubic(ii-u) * BiBubic(jj-v)
            retimg[i, j] = np.clip(tmp, 0, 255)
    return retimg

Aquí mencionamos brevemente qué funciona mejor y cómo lo hice. Dado que el Sr. Wang Xintao estaba escribiendo esta parte para personas u otras imágenes de alta definición, es aceptable utilizar las imágenes proporcionadas en sus ejemplos aquí o imágenes comunes. Porque el archivo de configuración que proporcionó en su modelo de configuración ESR utiliza 128 como tamaño de recorte de imagen. ¿Por qué él haría eso? Las imágenes que proporciona o las imágenes que usamos diariamente para las pruebas generalmente tienen una resolución relativamente grande. ¡El conjunto de datos proporcionado por este modelo es 2048x1024! ¿Encontraste el problema? Sí, los datos proporcionados son relativamente numerosos. Eso nos lleva a por qué quería cortarlo. Cuando entrenamos, a menudo no necesitamos ser tan grandes (los más comunes son parches de entrenamiento de 128×128 o 192×192), por lo que primero podemos recortar la imagen 2K en bloques de subimagen de 480×480 con superposición. Luego, el cargador de datos recorta aleatoriamente un parche de entrenamiento de 128 × 128 (ESR) o 192 × 192 (EDSR) de este bloque de subimagen de 480 × 480.

Es posible que tenga la misma comprensión que yo en la descripción anterior. No hay forma de comprender completamente su proceso sin realizar su experimento. Entonces déjame describirte en lengua vernácula lo que realmente quiere expresar. Su significado básico es en realidad expresar que cuando ingresamos una imagen relativamente grande, para no cargar demasiado la memoria de video, ¿qué debemos hacer? Primero podemos cortar su imagen en varias imágenes, como las piezas de un rompecabezas. Solo tratamos con una pieza cada vez. Cuando cortamos, ¿queremos decir que el largo y el ancho de la imagen pueden ser diferentes, verdad? Entonces, ¿cómo abordamos este problema? Es la superposición mencionada anteriormente. Entonces no importa si se superponen. Entonces no importa si divide su gt_size en toda la imagen. Luego usamos la misma estrategia para sus subimágenes.

En la última parte hablaré sobre el problema que estoy encontrando ahora, que es la situación que encontramos al principio, y por cierto, les daré a todos una advertencia. Si la imagen que ingresamos no tiene un tamaño de imagen común en la vida, sino que se trata de una imagen muy pequeña que ha sido segmentada, el tamaño es de solo unos pocos KB, los píxeles son solo 72x28, 36x63, etc. Por lo tanto, no podemos utilizar directamente el modelo de red ESRGAN en su modelo. De hecho, podemos ver por su nombre que el ejemplo que dio utiliza un conjunto de datos de 2K para la operación. Entonces, ¿cómo abordamos este problema? Cuando estaba haciendo esta parte, ¡lo hice con la mentalidad de mover montañas! De todos modos, si mis datos no están mal, no los cambiaré. Cambiaré su código, y luego iré a su directorio basicsr y cambiaré su modelo. Para adaptarme a mi tamaño, cambié muchas cosas. . . Pero incluso si algunos de los cambios tuvieron éxito, al final todavía quedaban algunas imágenes extremadamente pequeñas y todavía no podía lograr mi imagen más pequeña. ¡Así que me preguntaba si podría eliminar su función de recorte! Así que me apresuré de nuevo y el resultado fue obvio y falló (aunque soy relativamente bueno en eso, esta vez en realidad el TODO de su marco también decía que su escritura en esa parte no era muy buena, así que no tenía forma de hacerlo). en el corto plazo en ese momento. Dale una mejor manera de cambiarlo). Como resultado, me recostaba mucho y mi estado mental no era muy bueno. Finalmente, llegó un punto de inflexión————————Finalmente, mi mentor me dio algunas ideas y de repente me iluminó.

Solución a imágenes pequeñas: de hecho, entré en un malentendido al principio, es decir, he estado pensando en cambiar las cosas de otras personas para adaptarlas a las mías, pero en realidad es más fácil resolverlo cambiando mi forma de pensar y cambiando nuestro conjunto de datos. . Entonces modifiqué los datos de nuestra imagen al tamaño de una imagen normal, que es más grande que gt_size en el archivo de configuración de ESRGAN que proporcionó. (Este gt_size realmente no debe cambiarse casualmente, porque su entrada y convolución están codificadas en py y no se modifican dinámicamente, por lo que es muy fácil que ocurran problemas en uno de los pasos). Entonces nuestra imagen alcanzará la normalidad. tamaño Puede continuar con el siguiente paso. ¿Se pregunta si ampliar la imagen afectará la precisión de la imagen? No hay problema, se acaba de explicar arriba. Para que todos puedan usarlo con confianza después de pasar su propia prueba PSNR o SSIM. A partir de esta parte, nuestra fase de preparación de datos se completa oficialmente.

Aquí están sus scripts oficiales para procesar subarchivos y procesar imágenes pequeñas:



import cv2
import numpy as np
import os
import sys
from multiprocessing import Pool
from os import path as osp
from tqdm import tqdm

from basicsr.utils import scandir


def main():
    """A multi-thread tool to crop large images to sub-images for faster IO.
    It is used for DIV2K dataset.
    Args:
        opt (dict): Configuration dict. It contains:
        n_thread (int): Thread number.
        compression_level (int):  CV_IMWRITE_PNG_COMPRESSION from 0 to 9. A higher value means a smaller size and
            longer compression time. Use 0 for faster CPU decompression. Default: 3, same in cv2.
        input_folder (str): Path to the input folder.
        save_folder (str): Path to save folder.
        crop_size (int): Crop size.
        step (int): Step for overlapped sliding window.
        thresh_size (int): Threshold size. Patches whose size is lower than thresh_size will be dropped.
    Usage:
        For each folder, run this script.
        Typically, there are four folders to be processed for DIV2K dataset.
            * DIV2K_train_HR
            * DIV2K_train_LR_bicubic/X2
            * DIV2K_train_LR_bicubic/X3
            * DIV2K_train_LR_bicubic/X4
        After process, each sub_folder should have the same number of subimages.
        Remember to modify opt configurations according to your settings.
    """

    opt = {}
    opt['n_thread'] = 10
    opt['compression_level'] = 3

    # HR images
    opt['input_folder'] = '../../datasets/example/BSDS100'    # 数据图片的源文件
    opt['save_folder'] = '../../datasets/example/BSDS100_sub'  # 数据图片的压缩之后的文件夹
    opt['crop_size'] = 120
    opt['step'] = 240
    opt['thresh_size'] = 1
    extract_subimages(opt)




def extract_subimages(opt):
    """Crop images to subimages.
    Args:
        opt (dict): Configuration dict. It contains:
        input_folder (str): Path to the input folder.
        save_folder (str): Path to save folder.
        n_thread (int): Thread number.
    """
    input_folder = opt['input_folder']
    save_folder = opt['save_folder']
    if not osp.exists(save_folder):
        os.makedirs(save_folder)
        print(f'mkdir {save_folder} ...')
    else:
        print(f'Folder {save_folder} already exists. Exit.')
        sys.exit(1)

    img_list = list(scandir(input_folder, full_path=True))

    pbar = tqdm(total=len(img_list), unit='image', desc='Extract')
    pool = Pool(opt['n_thread'])
    for path in img_list:
        pool.apply_async(worker, args=(path, opt), callback=lambda arg: pbar.update(1))
    pool.close()
    pool.join()
    pbar.close()
    print('All processes done.')


def worker(path, opt):
    """Worker for each process.
    Args:
        path (str): Image path.
        opt (dict): Configuration dict. It contains:
        crop_size (int): Crop size.
        step (int): Step for overlapped sliding window.
        thresh_size (int): Threshold size. Patches whose size is lower than thresh_size will be dropped.
        save_folder (str): Path to save folder.
        compression_level (int): for cv2.IMWRITE_PNG_COMPRESSION.
    Returns:
        process_info (str): Process information displayed in progress bar.
    """
    crop_size = opt['crop_size']
    step = opt['step']
    thresh_size = opt['thresh_size']
    img_name, extension = osp.splitext(osp.basename(path))

    # remove the x2, x3, x4 and x8 in the filename for DIV2K
    img_name = img_name.replace('x2', '').replace('x3', '').replace('x4', '').replace('x8', '')

    img = cv2.imread(path, cv2.IMREAD_UNCHANGED)

    h, w = img.shape[0:2]
    h_space = np.arange(0, h - crop_size + 1, step)
    if h - (h_space[-1] + crop_size) > thresh_size:
        h_space = np.append(h_space, h - crop_size)
    w_space = np.arange(0, w - crop_size + 1, step)
    if w - (w_space[-1] + crop_size) > thresh_size:
        w_space = np.append(w_space, w - crop_size)

    index = 0
    for x in h_space:
        for y in w_space:
            index += 1
            cropped_img = img[x:x + crop_size, y:y + crop_size, ...]
            cropped_img = np.ascontiguousarray(cropped_img)
            cv2.imwrite(
                osp.join(opt['save_folder'], f'{img_name}_s{index:03d}{extension}'), cropped_img,
                [cv2.IMWRITE_PNG_COMPRESSION, opt['compression_level']])
    process_info = f'Processing {img_name} ...'
    return process_info


if __name__ == '__main__':
    main()

Luego proporcione el subguión para el procesamiento de archivos pequeños:

import os
from os import path as osp
import cv2


def scandir(dir_path, suffix=None, recursive=False, full_path=False):
    """Scan a directory to find the interested files.

    Args:
        dir_path (str): Path of the directory.
        suffix (str | tuple(str), optional): File suffix that we are
            interested in. Default: None.
        recursive (bool, optional): If set to True, recursively scan the
            directory. Default: False.
        full_path (bool, optional): If set to True, include the dir_path.
            Default: False.

    Returns:
        A generator for all the interested files with relative paths.
    """

    if (suffix is not None) and not isinstance(suffix, (str, tuple)):
        raise TypeError('"suffix" must be a string or tuple of strings')

    root = dir_path

    def _scandir(dir_path, suffix, recursive):
        for entry in os.scandir(dir_path):
            if not entry.name.startswith('.') and entry.is_file():
                if full_path:
                    return_path = entry.path
                else:
                    return_path = osp.relpath(entry.path, root)

                if suffix is None:
                    yield return_path
                elif return_path.endswith(suffix):
                    yield return_path
            else:
                if recursive:
                    yield from _scandir(entry.path, suffix=suffix, recursive=recursive)
                else:
                    continue

    return _scandir(dir_path, suffix=suffix, recursive=recursive )
pnglist = list(scandir("../../datasets/example/bai_hr", full_path=True))
print(pnglist)

#读取原始图像
for i in pnglist:

    img = cv2.imread(i,1)
    x, y, p = img.shape[0:3]

    #图像向下取样
    r = cv2.pyrDown(img)
    r = cv2.pyrDown(r)
    r = cv2.resize(r, [int(y/4),int(x/4)])    # 为啥是4倍呢 因为ESRGAN的配置文件有一个scale的四倍放大 当然这个地方个人可以根据实际的需求处理 此处的参数并不会影响程序运行

    cv2.imwrite("../../datasets/example/bai_hr_sub/" + str(i).split("/")[-1], r)

 4. Ejecute todo el modelo de entrenamiento.

        De hecho, para nuestro entrenamiento simple o comparación de modelos, esto es básicamente suficiente. Si no desea modificar su modelo o siente que su escritura no es lo suficientemente perfecta, desea continuar mejorando su marco. De hecho, nuestros preparativos han sido completados. A continuación podemos ejecutar nuestro modelo de entrenamiento directamente.

Necesitamos ir a nuestra carpeta para ejecutar nuestro script de entrenamiento:


cd BasicSR-master

# 已经在第一步设置了cuda的或者对于自己的gpu可以自由支配的可以使用此运行命令
python3 basicsr/train.py -opt options/train/ESRGAN/train_ESRGAN_x4.yml

# 指定我们的gpu来跑训练模型
CUDA_VISIBLE_DEVICES=2 python3 basicsr/train.py -opt options/train/ESRGAN/train_ESRGAN_x4.yml

# 如果不知道自己的gpu信息可以安装一下gpustat 然后在自己的gpu中直接输入就可以看到了
pip install gpustat

 

Cuando finalmente aparece la siguiente imagen, el entrenamiento se completa.

 Finalmente, nuestros resultados de entrenamiento se generarán bajo nuestros experimentos.

 

Finalmente, juzgamos el efecto en función de nuestra relación señal-ruido máxima, que se puede ver en el registro. Sin embargo, su PSNR puede no ser el más consistente con nuestros criterios de evaluación. Todavía es necesario considerar otras sentencias de pérdida.

¡Finalizar!

Supongo que te gusta

Origin blog.csdn.net/qq_38735174/article/details/127922798
Recomendado
Clasificación