读论文系列:The TNO Multiband Image Data Collection(含 dataset)

读论文系列:The TNO Multiband Image Data Collection

1️⃣ 资料

  1. 说明:非常老牌的红外可见光融合数据集,值得一看
  2. 官方仓库:https://figshare.com/articles/dataset/TNO_Image_Fusion_Dataset/1008029
  3. 大佬笔记:https://blog.csdn.net/qq_43249953/article/details/139769505

2️⃣ 文章翻译

摘要

Despite of the ongoing interest in the fusion of multi-band images for surveillance applications and a steady stream of publications in this area, there is only a very small number of static registered multi-band test images (and a total lack of dynamic image sequences) publicly available for the development and evaluation of image fusion algorithms. To fill this gap, the TNO Multiband Image Collection provides intensified visual (390–700 nm), nearinfrared (700–1000 nm), and longwave infrared (8–12 μm) nighttime imagery of different military and surveillance scenarios, showing different objects and targets (e.g., people, vehicles) in a range of different (e.g., rural, urban) backgrounds. The dataset will be useful for the development of static and dynamic image fusion algorithms, color fusion algorithms, multispectral target detection and recognition algorithms, and dim target detection algorithms.

尽管人们对用于监控应用的多波段图像融合持续感兴趣,并且该领域的出版物源源不断,但只有极少数静态注册的多波段测试图像(完全缺乏动态图像序列)可供公开用于图像融合算法的开发和评估。为了填补这一空白,TNO多波段图像集提供了不同军事和监视场景的增强视觉(390-700nm)、近红外(700-1000nm)和长波红外(8-12μm)夜间图像,显示了不同背景(如农村、城市)中的不同物体和目标(如人、车辆)。该数据集将有助于开发静态和动态图像融合算法、颜色融合算法、多光谱目标检测和识别算法以及弱目标检测算法。

Specifications Table 规格表

标题内容
Subject areaDigital image processing - Image fusion
Type of dataVisual, near-infrared (NIR) and longwave infrared (LWIR) digital images representing different nighttime military and surveillance scenarios.
How data was acquiredThe images were acquired with different multiband camera systems. 这些图像是用不同的多波段相机系统采集的。
Data formatBMP, TIF, MP4
Experimental factorsThe images have been geometrically warped and registered so that corresponding image pairs have pixelwise correspondence. 图像已经过几何扭曲和配准,使得相应的图像对具有像素对应关系。
Experimental featuresThe imagery was collected in (semi-)darkness during several outdoor field trials in both rural and urban areas. 这些图像是在农村和城市地区的几次户外田间试验中在(半)黑暗中收集的。
Data source locationThe imagery was collected at different sites in the Netherlands. 这些图像是在荷兰的不同地点收集的。
Data accessibilityhttps://doi.org/10.6084/m9.figshare.c.3860689.v1
[1]A. Toet, J.K. IJspeert, A.M. Waxman, M. Aguilar, Fusion of visible and thermal imagery improves situational awareness, Displays 18 (2) (1997) 85–95. http://dx.doi.org/10.1016/S0141-9382(97)00014-0.
[2]A. Toet, Detection of dim point targets in cluttered maritime backgrounds through multisensor image fusion, in: W. R. Watkins, D. Clement, W.R. Reynolds (Eds.), Targets and Backgrounds: Characterization and Representation VIII, The International Society for Optical Engineering, Bellingham, WA, http://dx.doi.org/10.1117/12.478798.
[3]A. Toet, M.A. Hogervorst, A.R. Pinkus, The TRICLOBS dynamic multi-band image data set for the development and evaluation of image fusion methods, PLoS One 11 (12) (2016) e0165016. http://dx.doi.org/10.1371/journal.pone.0165016.

Value of the Data 数据的价值

The dataset will be useful for the development of

  • static and dynamic image fusion algorithms, 静态和动态图像融合算法
  • color fusion algorithms, 颜色融合算法
  • multispectral target detection and recognition algorithms, 多光谱目标检测和识别算法
  • dim target detection algorithms. 弱小目标检测算法

Data 数据

The TNO Multiband Image Collection currently consists of three individual image sets:

  • The TNO Image Fusion Dataset
  • The Kayak Image Fusion Sequence (parts I and II)
  • The TRICLOBS Dynamic Multiband Image Dataset

The TNO Image Fusion Dataset [1] contains intensified visual (390–700 nm), near-infrared (7001000 nm), and longwave infrared (8–12 μm) nighttime imagery of different military and surveillance scenarios, showing different objects and targets (e.g., people, vehicles) in different (e.g., rural, urban) backgrounds.

TNO图像融合数据集[1]包含不同军事和监视场景的增强视觉(390-700nm)、近红外(7001000nm)和长波红外(8-12μm)夜间图像,显示了不同背景(如农村、城市)中的不同物体和目标(如人、车辆)。

The multimodal Kayak Image Fusion Sequence [2] contains registered visual, near-infrared and longwave infrared image sequences showing three approaching kayaks in a cluttered maritime background. Because of the variation in distance the targets (kayaks) vary from dim point targets to easily distinguishable objects.

多模式皮划艇图像融合序列[2]包含注册的视觉、近红外和长波红外图像序列,显示了三艘正在接近的皮划艇在杂乱的海上背景中。由于距离的变化,目标(皮划艇)从暗淡的点目标到易于区分的物体各不相同。

The TRICLOBS Dynamic Multiband Image Dataset [3] contains registered visual (400–700 nm), near-infrared (NIR, 700–1000 nm) and longwave infrared (LWIR, 8–14 μm) motion sequences of dynamic surveillance scenarios in an urban environment. To enable the development or realistic color remapping procedures, the dataset also contains color photographs of each of the three scenes. This dataset was collected during several field trials at three different locations and contains 16 motion sequences representing different military and civilian surveillance scenarios.

TRICLOBS动态多波段图像数据集[3]包含城市环境中动态监控场景的注册视觉(400-700nm)、近红外(NIR,700-1000nm)和长波红外(LWIR,8-14μm)运动序列。为了实现开发或逼真的颜色重映射过程,数据集还包含三个场景中每个场景的彩色照片。该数据集是在三个不同地点的几次现场试验中收集的,包含代表不同军事和民用监视场景的16个运动序列。

All three datasets include publications describing the registration conditions and the used camera systems in full detail. The data collection will be incrementally extended with new imagery when this becomes available. The images in this data collection can freely be used for research purposes, and may be used in publications without prior notice, provided this paper is properly referenced.

所有三个数据集都包括详细描述注册条件和使用的相机系统的出版物。当新的图像可用时,数据收集将逐步扩展。本数据集中的图像可自由用于研究目的,并可在不事先通知的情况下用于出版物,前提是正确引用本文。

Experimental design, materials, and methods

The original sensor signals were warped and subsampled to achieve pixelwise image registration.
原始传感器信号被扭曲和二次采样,以实现像素图像配准。

3️⃣ 我的笔记

目录结构

我感觉有必要分别列举一下目录结构。因为其一是TNO 中包含了三个数据集,内容混乱,其二是本身图片并不多,一一列举是实际的。
在这里插入图片描述
可见,并不是 TNO、Kayak、TRICLOBS 三个文件夹,而是一堆杂乱的结构。

TRICLOOBS

TRICLOBS子数据集对应着 Triclobs_images文件夹。

(base) kimshan@MacBook-Pro Triclobs_images % ls
Balls			Marne_06		Reek
Bosnia			Marne_07		Veluwe
Farm			Marne_09		Vlasakkers
House			Marne_11		barbed_wire_1
Kaptein_01		Marne_15		barbed_wire_2
Kaptein_1123		Marne_24		houses_with_3_men
Kaptein_1654		Movie_01		jeep_in_smoke
Kaptein_19		Movie_12		pancake_house
Marne_01		Movie_14		soldier_behind_smoke
Marne_02		Movie_18		soldiers_with_jeep
Marne_03		Movie_24		square_with_houses
Marne_04		REFRENCES

总结一下,

场景可见光近红外远红外其他
Balls
屋外的黑色铁球
VIS.bmpNIR.bmpphoto.bmp
barbed_wire_1
人跑过铁丝网
R_Vis.tifG_NIR.tifB_LWIR.tifRGB.tif
barbed_wire_2
人跑过铁丝网
a_VIS-MarnehNew
_24RGB_1110.tif
b_NIR-MarnehNew
_24RGB_1110.tif
c_LWIR-MarnehNew
_24RGB_1110.tif
Bosnia
草地上的房子
VIS_R.bmpNIR_G.bmpLWIR_B.bmpdaylight_image.bmp
Farm
草地上的房子
Farm_Vis.bmpFarm_II.bmpFarm_IR.bmpphoto.bmp
House
灯热影响红外
VIS.bmpNIR.bmpphoto.bmp
houses_with_3_men
房子和三个人
VIS.bmpNIR.bmpLWIR.bmp
jeep_in_smoke
雾中的吉普
VIS_R.bmpNIR_G.bmpLWIR_B.bmp
Kaptein_01
黑夜中的门
Vis01.bmpNIR01.bmpIR01.bmpphoto.bmp
Kaptein_19
黑夜中的帐篷
Vis19.bmpNIR19.bmpIR19.bmpphoto.bmp
Kaptein_1123
黑夜中的门和人
Kaptein_
1123_Vis.bmp
Kaptein_
1123_II.bmp
Kaptein_
1123_IR.bmp
photo.bmp
Kaptein_1654
黑夜中的帐篷和人
Kaptein_
1654_Vis.bmp
Kaptein_
1654_II.bmp
Kaptein_
1654_IR.bmp
Kaptein_1654_
ref_with_man.bmp,
Kaptein_
1654_REF.bmp
Marne_01
白天的房子
Marne_01_Vis.bmpMarne_01_II.bmpMarne_01_IR.bmpMarne_01_REF.bmp
Marne_02
白天的房子
Marne_02_Vis.bmpMarne_02_II.bmpMarne_02_IR.bmpMarne_02_REF.bmp
Marne_03
白天的房子
Marne_03_Vis.bmpMarne_03_II.bmpMarne_03_IR.bmpMarne_03_REF.bmp
Marne_04
著名的吉普
Marne_04_Vis.bmpMarne_04_II.bmpMarne_04_IR.bmpMarne_04_REF.bmp
Marne_06
白天的房子
Marne_06_Vis.bmpMarne_06_II.bmpMarne_06_IR.bmpMarne_06_REF.bmp
Marne_07
白天的房子
Marne_07_Vis.bmpMarne_07_II.bmpMarne_07_IR.bmpMarne_07_REF.bmp
Marne_08
白天的房子
Marne_08_Vis.bmpMarne_08_II.bmpMarne_08_IR.bmpMarne_08_REF.bmp
Marne_09
白天的房子
Marne_09_Vis.bmpMarne_09_II.bmpMarne_09_IR.bmpMarne_09_REF.bmp
Marne_11
白天的房子
Marne_11_Vis.bmpMarne_11_II.bmpMarne_11_IR.bmp
Marne_15
白天的房子
Marne_15_Vis.bmpMarne_15_II.bmpMarne_15_IR.bmp
Marne_24
铁丝和奔跑的人
Marne_15_Vis.bmpMarne_15_II.bmpMarne_15_IR.bmp
Movie_01
白天的街道
Movie_01_Vis.bmpMovie_01_II.bmpMovie_01_IR.bmpMovie_01_REF.bmp
Movie_12
房子
Movie_12_Vis.bmpMovie_12_II.bmpMovie_12_IR.bmpMovie_12_REF.bmp
Movie_14
房子和人
Movie_14_Vis.bmpMovie_14_II.bmpMovie_14_IR.bmpMovie_14_REF.bmp
Movie_18
房子和人和车
Movie_18_Vis.bmpMovie_18_II.bmpMovie_18_IR.bmpMovie_18_REF.bmp
Movie_24
房子
Movie_24_Vis.bmpMovie_24_II.bmpMovie_24_IR.bmp
pancake_house
白天的街道
VIS.tifNIR.tifphoto.tif
Reek
白天的房子
Reek_Vis.bmpReek_II.bmpReek_IR.bmpReek_REF.bmp
soldier_behind_smoke
雾中的士兵
VIS-MarnehNew_
15RGB_603.tif
NIR-MarnehNew_
15RGB_603.tif
LWIR-MarnehNew_
15RGB_603.tif
RGB-MarnehNew_
15RGB_603.tif
soldiers_with_jeep
士兵和吉普
Jeep_Vis.bmpJeep_II.bmpJeep_IR.bmp
square_with_houses
房子和方框
VIS.bmpNIR.bmpLWIR.bmp
Veluwe
望远镜中的房子
VIS.bmpNIR.bmpphoto.bmp
Vlasakkers
房子
VIS.tifNIR.tifphoto.tif

TNO

在Athena_imagesz合格文件夹中的REFRENCES里边,有这样的 pdf:Report_TNO-DV-2007-A329.pdf。所以我认为这个文件夹里边都是 TNO 下的TNO的。

(base) kimshan@MacBook-Pro Athena_images % ls
2_men_in_front_of_house	helicopter
APC_1			lake
APC_2			man_in_doorway
APC_3			soldier_behind_smoke_1
APC_4			soldier_behind_smoke_2
REFRENCES		soldier_behind_smoke_3
airplane_in_trees	soldier_in_trench_1
bunker			soldier_in_trench_2
heather

还是整理一下:

场景可见光近红外远红外其他
2_men_in_front
_of_house
房子和两个人
VIS_meting003_r.bmpIR_meting003_g.bmpmeting003_rg.bmp
airplane_in_trees
树中的飞机
vis.bmpir.bmp
APC_1/view_1
装甲车
VIS_fk_06_005.bmpIR_fk_06_005.bmpfk_06_005_rg.bmp
APC_1/view_2
装甲车和人
VIS_fk_ref_01_005.bmpIR_fk_ref_01_005.bmpfk_ref_01_005_rg.bmp
APC_1/view_3
装甲车
VIS_fk_ref_02_005.bmpIR_fk_ref_02_005.bmpfk_ref_02_005_rg.bmp
APC_2/view_1
装甲车
1_fk_ge_03_005.bmp2_fk_ge_03_005.bmpfk_ge_03_005_rg.bmp
APC_2/view_2
装甲车
1_fk_ge_04_005.bmp2_fk_ge_04_005.bmpfk_ge_04_005_rg.bmp
APC_2/view_3
装甲车
1_fk_ge_06_005.bmp2_fk_ge_06_005.bmpfk_ge_06_005_rg.bmp
APC_3view_1
装甲车
VIS_fk_bar_06_005.bmpIR_fk_bar_06_005.bmpfk_bar_06_005_rg.bmp
APC_3view_2
装甲车
VIS_fk_bar_01_005.bmpIR_fk_bar_01_005.bmpfk_bar_01_005_rg.bmp
APC_3view_3
装甲车
VIS_fk_bar_05_005.bmpIR_fk_bar_05_005.bmpfk_bar_05_005_rg.bmp
APC_4
装甲车
VIS_fennek01_005.bmpIR_fennek01_005.bmpfennek01_005_rg.bmp
bunker
树中建筑
bunker_r.bmpIR_bunker_g.bmpVIS_bunker-rg.bmp
heather
树中道路
VIS_hei_vis_r.bmpIR_hei_vis_g.bmphei_vis-rg.bmp
helicopter
直升机
VIS_helib_011.bmpIR_helib_011.bmphelib_011_rg.bmp
lake
VIS_lake_r.bmpIR_lake_g.bmplake_rg.bmp
man_in_doorway
男人在门口
VIS_maninhuis_r.bmpIR_maninhuis_g.bmpmaninhuis_rg.bmp
soldier_behind_smoke_1
烟中狙击手
VIS_meting012-1200_r.bmpIR_meting012-1200_g.bmpmeting012-1200_rg.bmp
soldier_behind_smoke_2
烟中狙击手
VIS_meting012-1500_r.bmpIR_meting012-1500_g.bmpmeting012-1500_rg.bmp
soldier_behind_smoke_3
烟中狙击手
VIS_meting012-1700_r.bmpIR_meting012-1700_g.bmpmeting012-1700_rg.bmp
soldier_in_trench_1
桥里的男人
VIS_meting016_r.bmpIR_meting016_g.bmpmeting016_rg.bmp
soldier_in_trench_2
桥里的男人
VIS_meting055_r.bmpIR_meting055_g.bmpmeting055_rg.bmp

Kayak

那我就认为剩下的都属于Kayak子集。那这就又很杂乱了。我还是分两部分:

  • 第一部分是Kayak的特色,一些序列,
  • 第二部分是剩下的杂项。
第一部分
  • Introduction
    • Intensified visual images have the extensions VIS and/or R
    • Near Infrared images have the extensions NIR and/or G
    • Thermal images have the extensions IR , RAD and/or B
    • DHV images are false color (R,G,0) images corresponding to (VIS,NIR,0)
  • Datasets
    • DHV_images/Fire_sequence
    • FEL_images/Duine_sequence
    • FEL_images/Nato_camp_sequence
    • FEL_images/Tree_sequence

总结

名称介绍VISDHVThermal/RAD
DHV_images/Fire_sequence/Part1烟火DHV2.bmp ~ HDV29.bmpRAD2.bmp ~ RAD29.bmp
DHV_images/Fire_sequence/Part2烟火DHVheli0.bmp ~ DHVheli16.bmpRADheli0.bmp ~ RADheli16.bmp
DHV_images/Fire_sequence/Part3烟火DHVheli20.bmp ~ DHVheli80.bmpRADheli20.bmp ~ RADheli80.bmp
FEL_images/Duine_sequence路上人7400v.bmp ~ 7422v.bmp7400i.bmp ~ 7422i.bmp
FEL_images/Nato_camp_sequence路上人1800v.bmp ~ 1831v.bmp1800i.bmp ~ 1831i.bmp
FEL_images/Tree_sequence林中人4900v.bmp ~ 4918i.bmp4900i.bmp ~ 4918i.bmp
第二部分
场景与路径可见光近红外远红外其他
tank
著名的坦克
Vis.tifLWIR.tif
DHV_images/bench
河边人
VIS_37dhvR.bmpNIR_37dhvG.bmpIR_37rad.bmp
DHV_images/sandpath
林中人
VIS_18dhvR.bmpNIR_18dhvG.bmpIR_18rad.bmp
DHV_images/wall
VIS_163dhvR.BMPNIR_163dhvG.BMPIR_163rad.bmp

我的总结

  1. TNO其实是一个散装的数据集,里边包含了三个小数据集。
  2. TNO/TNO,TNO/TRICLOOBS 以及 TNO/Kayak 的一部分,结构比较简单,就是可见光,近红外,远红外,照片或者 fask color 组成。其中会有缺省的内容。
  3. TNO/Kayak的另一部分都是连续视频的截图,包含了好几个序列。这里边的“烟火”序列,他的可见光和近红外分别组成了 R 通道和 G 通道的 fake color 图片,需要再解析一下。
  4. TNO 数据集中文件的命名很随意,有的是 VIS,IR 这样的,其他大部分也加入了场景描述以及序列 id,并且文件夹嵌套混乱,通过程序自动读入比较困难,需要手工挑选图片。

模仿torchvision风格的 dateset

下面是我写的 dataset

  1. 它可以直接支持指定位置自动下载,省的大家去自己从网上下载了。
  2. 我把所有的图片都写进程序了,如果有哪个图片不想要,你就把对应的 valid 改成 False,省的大家筛选图片容易把数据集弄乱。
  3. 这个 TNO包含零散的图像对和图像序列,调用的时候可以通过mode参数来指定需要什么。(我已经在文档字符串里边写好说明了)
  4. 这个 TNO 数据集的红外有中波和远红外两种,调用的时候可以通过img_type参数指定需要什么,我也写在文档字符串了。
  5. 这个dataset 我写了两天,也通过了测试,如果大家想直接借鉴,希望可以别把我的 github 链接删掉👍,直接把下边的文件保存成你的文件就行。
  6. 2025.2.25更新一下:直接下载的数据集有一些有问题的图片,比如 ir 用 RGB 保存了,或者一些图片尺寸不对。我已经修改了 download 函数,对这些图片处理。
  7. 2025.2.25,本次还新增的功能:为了应对 matlab 的一些算法。写了一个“导出”函数(export),把 TNO 复杂的文件夹里边的图片“展开”,这样方便 matlab的算法去融合或者去计算指标。

首先是 dataset 文件

# https://github.com/CharlesShan-hub/clib/blob/master/src/clib/datasets/collection/tno.py
from typing import Callable, Optional, Union
from torchvision.datasets.vision import VisionDataset
from torchvision.datasets.utils import download_and_extract_archive
from pathlib import Path
from PIL import Image

__all__ = ['TNO']

class TNO(VisionDataset):
    """ TNO dataset for image fusion.

    The TNO dataset is a collection of LWIR, NIR, and visible images for image fusion tasks.
    It includes both paired and sequential images for different scenarios. 
    Details: https://figshare.com/articles/dataset/TNO_Image_Fusion_Dataset/1008029

    Args:
        root (str): Root directory of the dataset where ``TNO_Image_Fusion_Dataset`` exists.
        transform (callable, optional): E.g, ``transforms.ToTensor``
        download (bool, optional): If true, downloads the dataset from the internet and
            puts it in root directory. If dataset is already downloaded, it is not
            downloaded again.
        mode (str, optional): Mode of the dataset to use. It can be 'both', 'pairs', or 'sequence'.
            'both' includes both pairs and sequence data, 'pairs' includes only paired data,
            and 'sequence' includes only sequential data.
        img_type (str, optional): Image type to use. It can be 'both', 'lwir', or 'nir'.
            'both' includes LWIR and NIR images, 'lwir' includes only LWIR images,
            and 'nir' includes only NIR images.
    """
    file = {
        'pairs':{
            'tank':{
                'lwir': 'tank/LWIR.tif',
                'vis': 'tank/Vis.tif',
                'valid': True
            },
            '2_men_in_front_of_house':{
                'lwir': 'Athena_images/2_men_in_front_of_house/IR_meting003_g.bmp',
                'vis': 'Athena_images/2_men_in_front_of_house/VIS_meting003_r.bmp',
                'valid': True
            },
            'airplane_in_trees':{
                'lwir': 'Athena_images/airplane_in_trees/ir.bmp',
                'vis': 'Athena_images/airplane_in_trees/vis.bmp',
                'valid': True
            },
            'APC_1_1':{
                'lwir': 'Athena_images/APC_1/view_1/IR_fk_06_005.bmp',
                'vis': 'Athena_images/APC_1/view_1/VIS_fk_06_005.bmp',
                'valid': True
            },
            'APC_1_2':{
                'lwir': 'Athena_images/APC_1/view_2/IR_fk_ref_01_005.bmp',
                'vis': 'Athena_images/APC_1/view_2/VIS_fk_ref_01_005.bmp',
                'valid': True
            },
            'APC_1_3':{
                'lwir': 'Athena_images/APC_1/view_3/IR_fk_ref_02_005.bmp',
                'vis': 'Athena_images/APC_1/view_3/VIS_fk_ref_02_005.bmp',
                'valid': True
            },
            'APC_2_1':{
                'lwir': 'Athena_images/APC_2/view_1/2_fk_ge_03_005.bmp',
                'vis': 'Athena_images/APC_2/view_1/1_fk_ge_03_005.bmp',
                'valid': True
            },
            'APC_2_2':{
                'lwir': 'Athena_images/APC_2/view_2/2_fk_ge_04_005.bmp',
                'vis': 'Athena_images/APC_2/view_2/1_fk_ge_04_005.bmp',
                'valid': True
            },
            'APC_2_3':{
                'lwir': 'Athena_images/APC_2/view_3/2_fk_ge_06_005.bmp',
                'vis': 'Athena_images/APC_2/view_3/1_fk_ge_06_005.bmp',
                'valid': True
            },
            'APC_3_1':{
                'lwir': 'Athena_images/APC_3/view_1/IR_fk_bar_06_005.bmp',
                'vis': 'Athena_images/APC_3/view_1/VIS_fk_bar_06_005.bmp',
                'valid': True
            },
            'APC_3_2':{
                'lwir': 'Athena_images/APC_3/view_2/IR_fk_NL_01_005.bmp',
                'vis': 'Athena_images/APC_3/view_2/VIS_fk_NL_01_005.bmp',
                'valid': True
            },
            'APC_3_3':{
                'lwir': 'Athena_images/APC_3/view_3/IR_fk_NL_05_005.bmp',
                'vis': 'Athena_images/APC_3/view_3/VIS_fk_NL_05_005.bmp',
                'valid': True
            },
            'APC_4':{
                'lwir': 'Athena_images/APC_4/IR_fennek01_005.bmp',
                'vis': 'Athena_images/APC_4/VIS_fennek01_005.bmp',
                'valid': True
            },
            'bunker':{
                'lwir': 'Athena_images/bunker/IR_bunker_g.bmp',
                'vis': 'Athena_images/bunker/bunker_r.bmp',
                'valid': True
            },
            'heather':{
                'lwir': 'Athena_images/heather/IR_hei_vis_g.bmp',
                'vis': 'Athena_images/heather/VIS_hei_vis_r.bmp',
                'valid': True
            },
            'helicopter':{
                'lwir': 'Athena_images/helicopter/IR_helib_011.bmp',
                'vis': 'Athena_images/helicopter/VIS_helib_011.bmp',
                'valid': True
            },
            'lake':{
                'lwir': 'Athena_images/lake/IR_lake_g.bmp',
                'vis': 'Athena_images/lake/VIS_lake_r.bmp',
                'valid': True
            },
            'man_in_doorway':{
                'lwir': 'Athena_images/man_in_doorway/IR_maninhuis_g.bmp',
                'vis': 'Athena_images/man_in_doorway/VIS_maninhuis_r.bmp',
                'valid': True
            },
            'soldier_behind_smoke_1':{
                'lwir': 'Athena_images/soldier_behind_smoke_1/IR_meting012-1200_g.bmp',
                'vis': 'Athena_images/soldier_behind_smoke_1/VIS_meting012-1200_r.bmp',
                'valid': True
            },
            'soldier_behind_smoke_2':{
                'lwir': 'Athena_images/soldier_behind_smoke_2/IR_meting012-1500_g.bmp',
                'vis': 'Athena_images/soldier_behind_smoke_2/VIS_meting012-1500_r.bmp',
                'valid': True
            },
            'soldier_behind_smoke_3':{
                'lwir': 'Athena_images/soldier_behind_smoke_3/IR_meting012-1700_g.bmp',
                'vis': 'Athena_images/soldier_behind_smoke_3/VIS_meting012-1700_r.bmp',
                'valid': True
            },
            'soldier_in_trench_1':{
                'lwir': 'Athena_images/soldier_in_trench_1/IR_meting016_g.bmp',
                'vis': 'Athena_images/soldier_in_trench_1/VIS_meting016_r.bmp',
                'valid': True
            },
            'soldier_in_trench_2':{
                'lwir': 'Athena_images/soldier_in_trench_2/IR_meting055_g.bmp',
                'vis': 'Athena_images/soldier_in_trench_2/VIS_meting055_r.bmp',
                'valid': True
            },
            'Balls':{
                'nir': 'Triclobs_images/Balls/NIR.bmp',
                'vis': 'Triclobs_images/Balls/VIS.bmp',
                'valid': True
            },
            'barbed_wire_1':{
                'nir': 'Triclobs_images/barbed_wire_1/G_NIR.tif',
                'lwir': 'Triclobs_images/barbed_wire_1/B_LWIR.tif',
                'vis': 'Triclobs_images/barbed_wire_1/R_Vis.tif',
                'valid': True
            },
            'barbed_wire_2':{
                'nir': 'Triclobs_images/barbed_wire_2/b_NIR-MarnehNew_24RGB_1110.tif',
                'lwir': 'Triclobs_images/barbed_wire_2/c_LWIR-MarnehNew_24RGB_1110.tif',
                'vis': 'Triclobs_images/barbed_wire_2/a_VIS-MarnehNew_24RGB_1110.tif',
                'valid': True
            },
            'Bosnia':{
                'nir': 'Triclobs_images/Bosnia/NIR_G.bmp',
                'lwir': 'Triclobs_images/Bosnia/LWIR_B.bmp',
                'vis': 'Triclobs_images/Bosnia/VIS_R.bmp',
                'valid': True
            },
            'Farm':{
                'nir': 'Triclobs_images/Farm/Farm_II.bmp',
                'lwir': 'Triclobs_images/Farm/Farm_IR.bmp',
                'vis': 'Triclobs_images/Farm/Farm_Vis.bmp',
                'valid': True
            },
            'House':{
                'nir': 'Triclobs_images/House/NIR.bmp',
                'vis': 'Triclobs_images/House/VIS.bmp',
                'valid': True
            },
            'houses_with_3_men':{
                'nir': 'Triclobs_images/houses_with_3_men/NIR.bmp',
                'lwir': 'Triclobs_images/houses_with_3_men/LWIR.bmp',
                'vis': 'Triclobs_images/houses_with_3_men/VIS.bmp',
                'valid': True
            },
            'jeep_in_smoke':{
                'nir': 'Triclobs_images/jeep_in_smoke/NIR_G.bmp',
                'lwir': 'Triclobs_images/jeep_in_smoke/LWIR_B.bmp',
                'vis': 'Triclobs_images/jeep_in_smoke/VIS_R.bmp',
                'valid': True
            },
            'Kaptein_01':{
                'nir': 'Triclobs_images/Kaptein_01/NIR01.bmp',
                'lwir': 'Triclobs_images/Kaptein_01/IR01.bmp',
                'vis': 'Triclobs_images/Kaptein_01/Vis01.bmp',
                'valid': True
            },
            'Kaptein_19':{
                'nir': 'Triclobs_images/Kaptein_19/NIR19.bmp',
                'lwir': 'Triclobs_images/Kaptein_19/IR19.bmp',
                'vis': 'Triclobs_images/Kaptein_19/Vis19.bmp',
                'valid': True
            },
            'Kaptein_1123':{
                'nir': 'Triclobs_images/Kaptein_1123/Kaptein_1123_II.bmp',
                'lwir': 'Triclobs_images/Kaptein_1123/Kaptein_1123_IR.bmp',
                'vis': 'Triclobs_images/Kaptein_1123/Kaptein_1123_Vis.bmp',
                'valid': True
            },
            'Kaptein_1654':{
                'nir': 'Triclobs_images/Kaptein_1654/Kaptein_1654_II.bmp',
                'lwir': 'Triclobs_images/Kaptein_1654/Kaptein_1654_IR.bmp',
                'vis': 'Triclobs_images/Kaptein_1654/Kaptein_1654_Vis.bmp',
                'valid': True
            },
            'Marne_01':{
                'nir': 'Triclobs_images/Marne_01/Marne_01_II.bmp',
                'lwir': 'Triclobs_images/Marne_01/Marne_01_IR.bmp',
                'vis': 'Triclobs_images/Marne_01/Marne_01_Vis.bmp',
                'valid': True
            },
            'Marne_02':{
                'nir': 'Triclobs_images/Marne_02/Marne_02_II.bmp',
                'lwir': 'Triclobs_images/Marne_02/Marne_02_IR.bmp',
                'vis': 'Triclobs_images/Marne_02/Marne_02_Vis.bmp',
                'valid': True
            },
            'Marne_03':{
                'nir': 'Triclobs_images/Marne_03/Marne_03_II.bmp',
                'lwir': 'Triclobs_images/Marne_03/Marne_03_IR.bmp',
                'vis': 'Triclobs_images/Marne_03/Marne_03_Vis.bmp',
                'valid': True
            },
            'Marne_04':{
                'nir': 'Triclobs_images/Marne_04/Marne_04_II.bmp',
                'lwir': 'Triclobs_images/Marne_04/Marne_04_IR.bmp',
                'vis': 'Triclobs_images/Marne_04/Marne_04_Vis.bmp',
                'valid': True
            },
            'Marne_06':{
                'nir': 'Triclobs_images/Marne_06/Marne_06_II.bmp',
                'lwir': 'Triclobs_images/Marne_06/Marne_06_IR.bmp',
                'vis': 'Triclobs_images/Marne_06/Marne_06_Vis.bmp',
                'valid': True
            },
            'Marne_07':{
                'nir': 'Triclobs_images/Marne_07/Marne_07_II.bmp',
                'lwir': 'Triclobs_images/Marne_07/Marne_07_IR.bmp',
                'vis': 'Triclobs_images/Marne_07/Marne_07_Vis.bmp',
                'valid': True
            },
            'Marne_09':{
                'nir': 'Triclobs_images/Marne_09/Marne_09_II.bmp',
                'lwir': 'Triclobs_images/Marne_09/Marne_09_IR.bmp',
                'vis': 'Triclobs_images/Marne_09/Marne_09_Vis.bmp',
                'valid': True
            },
            'Marne_11':{
                'nir': 'Triclobs_images/Marne_11/Marne_11_II.bmp',
                'lwir': 'Triclobs_images/Marne_11/Marne_11_IR.bmp',
                'vis': 'Triclobs_images/Marne_11/Marne_11_Vis.bmp',
                'valid': True
            },
            'Marne_15':{
                'nir': 'Triclobs_images/Marne_15/Marne_15_II.bmp',
                'lwir': 'Triclobs_images/Marne_15/Marne_15_IR.bmp',
                'vis': 'Triclobs_images/Marne_15/Marne_15_Vis.bmp',
                'valid': True
            },
            'Marne_24':{
                'nir': 'Triclobs_images/Marne_24/Marne_24_II.bmp',
                'lwir': 'Triclobs_images/Marne_24/Marne_24_IR.bmp',
                'vis': 'Triclobs_images/Marne_24/Marne_24_Vis.bmp',
                'valid': True
            },
            'Movie_01':{
                'nir': 'Triclobs_images/Movie_01/Movie_01_II.bmp',
                'lwir': 'Triclobs_images/Movie_01/Movie_01_IR.bmp',
                'vis': 'Triclobs_images/Movie_01/Movie_01_Vis.bmp',
                'valid': True
            },
            'Movie_12':{
                'nir': 'Triclobs_images/Movie_12/Movie_12_II.bmp',
                'lwir': 'Triclobs_images/Movie_12/Movie_12_IR.bmp',
                'vis': 'Triclobs_images/Movie_12/Movie_12_Vis.bmp',
                'valid': True
            },
            'Movie_14':{
                'nir': 'Triclobs_images/Movie_14/Movie_14_II.bmp',
                'lwir': 'Triclobs_images/Movie_14/Movie_14_IR.bmp',
                'vis': 'Triclobs_images/Movie_14/Movie_14_Vis.bmp',
                'valid': True
            },
            'Movie_18':{
                'nir': 'Triclobs_images/Movie_18/Movie_18_II.bmp',
                'lwir': 'Triclobs_images/Movie_18/Movie_18_IR.bmp',
                'vis': 'Triclobs_images/Movie_18/Movie_18_Vis.bmp',
                'valid': True
            },
            'Movie_24':{
                'nir': 'Triclobs_images/Movie_24/Movie_24_II.bmp',
                'lwir': 'Triclobs_images/Movie_24/Movie_24_IR.bmp',
                'vis': 'Triclobs_images/Movie_24/Movie_24_Vis.bmp',
                'valid': True
            },
            'pancake_house':{
                'nir': 'Triclobs_images/pancake_house/NIR.tif',
                'vis': 'Triclobs_images/pancake_house/VIS.tif',
                'valid': True
            },
            'Reek':{
                'nir': 'Triclobs_images/Reek/Reek_II.bmp',
                'lwir': 'Triclobs_images/Reek/Reek_IR.bmp',
                'vis': 'Triclobs_images/Reek/Reek_Vis.bmp',
                'valid': True
            },
            'soldier_behind_smoke':{
                'nir': 'Triclobs_images/soldier_behind_smoke/NIR-MarnehNew_15RGB_603.tif',
                'lwir': 'Triclobs_images/soldier_behind_smoke/LWIR-MarnehNew_15RGB_603.tif',
                'vis': 'Triclobs_images/soldier_behind_smoke/VIS-MarnehNew_15RGB_603.tif',
                'valid': True
            },
            'soldiers_with_jeep':{
                'nir': 'Triclobs_images/soldiers_with_jeep/Jeep_II.bmp',
                'lwir': 'Triclobs_images/soldiers_with_jeep/Jeep_IR.bmp',
                'vis': 'Triclobs_images/soldiers_with_jeep/Jeep_Vis.bmp',
                'valid': True
            },
            'square_with_houses':{
                'nir': 'Triclobs_images/square_with_houses/NIR.bmp',
                'lwir': 'Triclobs_images/square_with_houses/LWIR.bmp',
                'vis': 'Triclobs_images/square_with_houses/VIS.bmp',
                'valid': True
            },
            'Veluwe':{
                'nir': 'Triclobs_images/Veluwe/NIR.bmp',
                'vis': 'Triclobs_images/Veluwe/VIS.bmp',
                'valid': True
            },
            'Vlasakkers':{
                'nir': 'Triclobs_images/Vlasakkers/NIR.tif',
                'vis': 'Triclobs_images/Vlasakkers/VIS.tif',
                'valid': True
            },
            'bench':{
                'nir': 'DHV_images/bench/NIR_37dhvG.bmp',
                'lwir': 'DHV_images/bench/IR_37rad.bmp',
                'vis': 'DHV_images/bench/VIS_37dhvR.bmp',
                'valid': True
            },
            'sandpath':{
                'nir': 'DHV_images/sandpath/NIR_18dhvG.bmp',
                'lwir': 'DHV_images/sandpath/IR_18rad.bmp',
                'vis': 'DHV_images/sandpath/VIS_18dhvR.bmp',
                'valid': True
            },
            'wall':{
                'nir': 'DHV_images/wall/NIR_163dhvG.BMP',
                'lwir': 'DHV_images/wall/IR_163rad.bmp',
                'vis': 'DHV_images/wall/VIS_163dhvR.BMP',
                'valid': True
            },
        },
        'sequence':{
            'Fire1':{
                'lwir': {
                    'base': 'DHV_images/Fire_sequence/part_1/thermal',
                    'content': [
                        'RAD2.bmp', 'RAD3.bmp', 'RAD4.bmp', 'RAD5.bmp', 
                        'RAD6.bmp', 'RAD7.bmp', 'RAD8.bmp', 'RAD9.bmp', 
                        'RAD10.bmp', 'RAD11.bmp', 'RAD12.bmp', 'RAD13.bmp', 
                        'RAD14.bmp', 'RAD15.bmp', 'RAD16.bmp', 'RAD17.bmp', 
                        'RAD18.bmp', 'RAD19.bmp', 'RAD20.bmp', 'RAD21.bmp', 
                        'RAD22.bmp', 'RAD23.bmp', 'RAD24.bmp', 'RAD25.bmp', 
                        'RAD26.bmp', 'RAD27.bmp', 'RAD28.bmp', 'RAD29.bmp'
                    ]
                },
                'vis': {
                    'base': 'DHV_images/Fire_sequence/part_1/dhv',
                    'content': [
                        'DHV2.bmp', 'DHV3.bmp', 'DHV4.bmp', 'DHV5.bmp', 
                        'DHV6.bmp', 'DHV7.bmp', 'DHV8.bmp', 'DHV9.bmp', 
                        'DHV10.bmp', 'DHV11.bmp', 'DHV12.bmp', 'DHV13.bmp', 
                        'DHV14.bmp', 'DHV15.bmp', 'DHV16.bmp', 'DHV17.bmp', 
                        'DHV18.bmp', 'DHV19.bmp', 'DHV20.bmp', 'DHV21.bmp', 
                        'DHV22.bmp', 'DHV23.bmp', 'DHV24.bmp', 'DHV25.bmp', 
                        'DHV26.bmp', 'DHV27.bmp', 'DHV28.bmp', 'DHV29.bmp'
                    ]
                },
                'valid': True
            },
            'Fire2':{
                'lwir': {
                    'base': 'DHV_images/Fire_sequence/part_2/rad',
                    'content': [
                        'RADheli0.bmp','RADheli1.bmp','RADheli2.bmp','RADheli3.bmp','RADheli4.bmp',
                        'RADheli5.bmp','RADheli6.bmp','RADheli7.bmp','RADheli8.bmp',
                        'RADheli9.bmp','RADheli10.bmp','RADheli11.bmp','RADheli12.bmp',
                        'RADheli13.bmp','RADheli14.bmp','RADheli15.bmp','RADheli16.bmp'
                    ]
                },
                'vis': {
                    'base': 'DHV_images/Fire_sequence/part_2/dhv',
                    'content': [
                        'DHVheli0.bmp','DHVheli1.bmp','DHVheli2.bmp','DHVheli3.bmp','DHVheli4.bmp',
                        'DHVheli5.bmp','DHVheli6.bmp','DHVheli7.bmp','DHVheli8.bmp',
                        'DHVheli9.bmp','DHVheli10.bmp','DHVheli11.bmp','DHVheli12.bmp',
                        'DHVheli13.bmp','DHVheli14.bmp','DHVheli15.bmp','DHVheli16.bmp'
                    ]
                },
                'valid': True
            },
            'Fire3':{
                'lwir': {
                    'base': 'DHV_images/Fire_sequence/part_3/rad',
                    'content': [
                        'RADheli20.bmp','RADheli21.bmp','RADheli22.bmp','RADheli23.bmp','RADheli24.bmp',
                        'RADheli25.bmp','RADheli26.bmp','RADheli27.bmp','RADheli28.bmp','RADheli29.bmp',
                        'RADheli30.bmp','RADheli31.bmp','RADheli32.bmp','RADheli33.bmp','RADheli34.bmp',
                        'RADheli35.bmp','RADheli36.bmp','RADheli37.bmp','RADheli38.bmp','RADheli39.bmp',
                        'RADheli40.bmp','RADheli41.bmp','RADheli42.bmp','RADheli43.bmp','RADheli44.bmp',
                        'RADheli45.bmp','RADheli46.bmp','RADheli47.bmp','RADheli48.bmp','RADheli49.bmp',
                        'RADheli50.bmp','RADheli51.bmp','RADheli52.bmp','RADheli53.bmp','RADheli54.bmp',
                        'RADheli55.bmp','RADheli56.bmp','RADheli57.bmp','RADheli58.bmp','RADheli59.bmp',
                        'RADheli60.bmp','RADheli61.bmp','RADheli62.bmp','RADheli63.bmp','RADheli64.bmp',
                        'RADheli65.bmp','RADheli66.bmp','RADheli67.bmp','RADheli68.bmp','RADheli69.bmp',
                        'RADheli70.bmp','RADheli71.bmp','RADheli72.bmp','RADheli73.bmp','RADheli74.bmp',
                        'RADheli75.bmp','RADheli76.bmp','RADheli77.bmp','RADheli78.bmp','RADheli79.bmp',
                        'RADheli80.bmp'
                    ]
                },
                'vis': {
                    'base': 'DHV_images/Fire_sequence/part_3/dhv',
                    'content': [
                        'DHVheli20.bmp','DHVheli21.bmp','DHVheli22.bmp','DHVheli23.bmp','DHVheli24.bmp',
                        'DHVheli25.bmp','DHVheli26.bmp','DHVheli27.bmp','DHVheli28.bmp','DHVheli29.bmp',
                        'DHVheli30.bmp','DHVheli31.bmp','DHVheli32.bmp','DHVheli33.bmp','DHVheli34.bmp',
                        'DHVheli35.bmp','DHVheli36.bmp','DHVheli37.bmp','DHVheli38.bmp','DHVheli39.bmp',
                        'DHVheli40.bmp','DHVheli41.bmp','DHVheli42.bmp','DHVheli43.bmp','DHVheli44.bmp',
                        'DHVheli45.bmp','DHVheli46.bmp','DHVheli47.bmp','DHVheli48.bmp','DHVheli49.bmp',
                        'DHVheli50.bmp','DHVheli51.bmp','DHVheli52.bmp','DHVheli53.bmp','DHVheli54.bmp',
                        'DHVheli55.bmp','DHVheli56.bmp','DHVheli57.bmp','DHVheli58.bmp','DHVheli59.bmp',
                        'DHVheli60.bmp','DHVheli61.bmp','DHVheli62.bmp','DHVheli63.bmp','DHVheli64.bmp',
                        'DHVheli65.bmp','DHVheli66.bmp','DHVheli67.bmp','DHVheli68.bmp','DHVheli69.bmp',
                        'DHVheli70.bmp','DHVheli71.bmp','DHVheli72.bmp','DHVheli73.bmp','DHVheli74.bmp',
                        'DHVheli75.bmp','DHVheli76.bmp','DHVheli77.bmp','DHVheli78.bmp','DHVheli79.bmp',
                        'DHVheli80.bmp'
                    ]
                },
                'valid': True
            },
            'Duine':{
                'lwir': {
                    'base': 'FEL_images/Duine_sequence/thermal',
                    'content': [
                        '7400i.bmp','7401i.bmp','7402i.bmp','7403i.bmp','7404i.bmp',
                        '7405i.bmp','7406i.bmp','7407i.bmp','7408i.bmp','7409i.bmp',
                        '7410i.bmp','7411i.bmp','7412i.bmp','7413i.bmp','7414i.bmp',
                        '7415i.bmp','7416i.bmp','7417i.bmp','7418i.bmp','7419i.bmp',
                        '7420i.bmp','7421i.bmp','7422i.bmp'
                    ]
                },
                'vis': {
                    'base': 'FEL_images/Duine_sequence/visual',
                    'content': [
                        '7400v.bmp','7401v.bmp','7402v.bmp','7403v.bmp','7404v.bmp',
                        '7405v.bmp','7406v.bmp','7407v.bmp','7408v.bmp','7409v.bmp',
                        '7410v.bmp','7411v.bmp','7412v.bmp','7413v.bmp','7414v.bmp',
                        '7415v.bmp','7416v.bmp','7417v.bmp','7418v.bmp','7419v.bmp',
                        '7420v.bmp','7421v.bmp','7422v.bmp'
                    ]
                },
                'valid': True
            },
            'Nato_camp':{
                'lwir': {
                    'base': 'FEL_images/Nato_camp_sequence/thermal',
                    'content': [
                        '1800i.bmp','1801i.bmp','1802i.bmp','1803i.bmp','1804i.bmp',
                        '1805i.bmp','1806i.bmp','1807i.bmp','1808i.bmp','1809i.bmp',
                        '1810i.bmp','1811i.bmp','1812i.bmp','1813i.bmp','1814i.bmp',
                        '1815i.bmp','1816i.bmp','1817i.bmp','1818i.bmp','1819i.bmp',
                        '1820i.bmp','1821i.bmp','1822i.bmp','1823i.bmp','1824i.bmp',
                        '1825i.bmp','1826i.bmp','1827i.bmp','1828i.bmp','1829i.bmp',
                        '1830i.bmp','1831i.bmp',
                    ]
                },
                'vis': {
                    'base': 'FEL_images/Nato_camp_sequence/visual',
                    'content': [
                        '1800v.bmp','1801v.bmp','1802v.bmp','1803v.bmp','1804v.bmp',
                        '1805v.bmp','1806v.bmp','1807v.bmp','1808v.bmp','1809v.bmp',
                        '1810v.bmp','1811v.bmp','1812v.bmp','1813v.bmp','1814v.bmp',
                        '1815v.bmp','1816v.bmp','1817v.bmp','1818v.bmp','1819v.bmp',
                        '1820v.bmp','1821v.bmp','1822v.bmp','1823v.bmp','1824v.bmp',
                        '1825v.bmp','1826v.bmp','1827v.bmp','1828v.bmp','1829v.bmp',
                        '1830v.bmp','1831v.bmp',
                    ]
                },
                'valid': True
            },
            'Tree':{
                'lwir': {
                    'base': 'FEL_images/Tree_sequence/thermal',
                    'content': [
                        '4900i.bmp','4901i.bmp','4902i.bmp','4903i.bmp','4904i.bmp',
                        '4905i.bmp','4906i.bmp','4907i.bmp','4908i.bmp','4909i.bmp',
                        '4910i.bmp','4911i.bmp','4912i.bmp','4913i.bmp','4914i.bmp',
                        '4915i.bmp','4916i.bmp','4917i.bmp','4918i.bmp'
                    ]
                },
                'vis': {
                    'base': 'FEL_images/Tree_sequence/visual',
                    'content': [
                        '4900v.bmp','4901v.bmp','4902v.bmp','4903v.bmp','4904v.bmp',
                        '4905v.bmp','4906v.bmp','4907v.bmp','4908v.bmp','4909v.bmp',
                        '4910v.bmp','4911v.bmp','4912v.bmp','4913v.bmp','4914v.bmp',
                        '4915v.bmp','4916v.bmp','4917v.bmp','4918v.bmp'
                    ]
                },
                'valid': True
            }
        }
    }
    url = "https://figshare.com/ndownloader/files/1475454"
    md5 = "1ab9ce3b84dd3e5894630c13abd20953"

    def __init__(
        self,
        root: Union[str, Path],
        transform: Optional[Callable] = None,
        download: bool = True,
        mode: Optional[str] = ['both', 'pairs', 'sequence'][0],
        img_type: Optional[str] = ['both', 'lwir', 'nir'][1],
        fusion: bool = False, 
        fusion_path: Union[Path, str] = '',
        fused_extension: Optional[str] = 'png',
        export_root: Optional[Union[str,Path]] = None,
        exported: bool = False,
        export_lwir_dir: str = 'lwir',
        export_nir_dir: str = 'nir',
        export_vis_dir: str = 'vis',
        dataloader: bool = True,
    ) -> None:
        super().__init__(root, transform=transform)
        self.folder = 'TNO_Image_Fusion_Dataset'
        self._base_folder = Path(self.root) / "tno"
        assert mode in ['both', 'pairs', 'sequence']
        self.mode = mode
        assert img_type in ['both', 'lwir', 'nir']
        self.img_type = img_type
        self.fusion = fusion
        self.fusion_path = fusion_path
        self.fused_extension = fused_extension
        if self.fusion:
            assert self.fusion_path != ''
            self.fusion_path = Path(self.fusion_path)
        self.dataloader = dataloader
        if export_root is None:
            self.export_root = Path(self.root) / 'tno' / 'tno'
        else:
            self.export_root = Path(export_root)
        self.export_lwir_dir = export_lwir_dir
        self.export_nir_dir = export_nir_dir
        self.export_vis_dir = export_vis_dir
        self.exported = exported
        if self.exported:
            self.build_exported()
        else:
            self.build_origin()

        if download:
            self.download()
    
    def _load_image(self, path):
        img = Image.open(path).convert("L")
        return self.transform(img) if self.transform else img

    def __getitem__(self, idx: int):
        res = {'vis': self._load_image(self.data[idx]['vis'])}
        if not self.dataloader:
            res.update({'vis_path': self.data[idx]['vis']})
        if 'lwir' in self.data[idx]:
            if not self.dataloader:
                res.update({'lwir_path': self.data[idx]['lwir']})
            res.update({'lwir': self._load_image(self.data[idx]['lwir'])})
        if 'nir' in self.data[idx]:
            if not self.dataloader:
                res.update({'nir_path': self.data[idx]['nir']})
            res.update({'nir': self._load_image(self.data[idx]['nir'])})
        if self.fusion:
            if not self.dataloader:
                res.update({'fused_path': Path(self.fusion_path) / f"{self.data[idx]['vis'].stem}.{self.fused_extension}"})
            res.update({'fused': self._load_image(Path(self.fusion_path) / f"{self.data[idx]['vis'].stem}.{self.fused_extension}")})
        return res
    
    def __len__(self):
        return len(self.data)
    
    def build_exported(self):
        self.data = []
        vis_list = [i.name for i in (self.export_root / self.export_vis_dir).iterdir()]
        lwir_list = [i.name for i in (self.export_root / self.export_lwir_dir).iterdir()]
        nir_list = [i.name for i in (self.export_root / self.export_nir_dir).iterdir()]
        if self.img_type == 'lwir':
            for i in lwir_list:
                assert i in vis_list
                self.data.append({
                    'lwir': self.export_root / self.export_lwir_dir / i,
                    'vis': self.export_root / self.export_vis_dir / i,
                })
        if self.img_type == 'nir':
            for i in nir_list:
                assert i in vis_list
                self.data.append({
                    'nir': self.export_root / self.export_nir_dir / i,
                    'vis': self.export_root / self.export_vis_dir / i,
                })
        if self.img_type == 'both':
            for i in nir_list:
                if i not in lwir_list:
                    continue
                assert i in vis_list
                self.data.append({
                    'lwir': self.export_root / self.export_lwir_dir / i,
                    'nir': self.export_root / self.export_nir_dir / i,
                    'vis': self.export_root / self.export_vis_dir / i,
                })
        
    def build_origin(self):
        self.data = []
        if self.mode in ['both', 'pairs']:
            for _,v in self.file['pairs'].items():
                if v['valid'] == False:
                    continue
                if self.img_type == 'lwir':
                    if 'lwir' not in v:
                        continue
                    self.data.append({
                        'lwir': self._base_folder / self.folder / v['lwir'],
                        'vis': self._base_folder / self.folder / v['vis']
                    })
                if self.img_type == 'nir':
                    if 'nir' not in v:
                        continue
                    self.data.append({
                        'nir': self._base_folder / self.folder / v['nir'],
                        'vis': self._base_folder / self.folder / v['vis']
                    })
                if self.img_type == 'both':
                    if ('lwir' not in v) or ('nir' not in v) :
                        continue
                    self.data.append({
                        'lwir': self._base_folder / self.folder / v['lwir'],
                        'nir': self._base_folder / self.folder / v['nir'],
                        'vis': self._base_folder / self.folder / v['vis']
                    })
        if self.mode in ['both', 'sequence']:
            for _,v in self.file['sequence'].items():
                if v['valid'] == False:
                    continue
                if self.img_type == 'lwir':
                    if 'lwir' not in v:
                        continue
                    for i,j in zip(v['lwir']['content'], v['vis']['content']):
                        self.data.append({
                            'lwir': self._base_folder / self.folder / v['lwir']['base'] / i,
                            'vis': self._base_folder / self.folder / v['vis']['base'] / j
                        })
                if self.img_type == 'nir':
                    if 'nir' not in v:
                        continue
                    for i,j in zip(v['nir']['content'], v['vis']['content']):
                        self.data.append({
                            'nir': self._base_folder / self.folder / v['nir']['base'] / i,
                            'vis': self._base_folder / self.folder / v['vis']['base'] / j
                        })
                if self.img_type == 'both':
                    if ('lwir' not in v) or ('nir' not in v) :
                        continue
                    for i,j,k in zip(v['lwir']['content'], v['nir']['content'], v['vis']['content']):
                        self.data.append({
                            'lwir': self._base_folder / self.folder / v['lwir']['base'] / i,
                            'nir': self._base_folder / self.folder / v['nir']['base'] / j,
                            'vis': self._base_folder / self.folder / v['vis']['base'] / k
                        })
    
    def _scale_bad_image(self,bad_scale_img_dir):
        bad_scale_img = Image.open(bad_scale_img_dir)
        width, height = bad_scale_img.size
        cropped_image = bad_scale_img.crop((0, 10, width, height))
        cropped_image.save(bad_scale_img_dir)
    
    def _resize_bad_image(self,bad_size_img_dir):
        bad_img = Image.open(bad_size_img_dir)
        resized_image = bad_img.resize((640,480), resample=1) # Resampling.LANCZOS
        resized_image.save(bad_size_img_dir)
    
    def _rgb_to_gray(self,bad_color_image_dir):
        bad_img = Image.open(bad_color_image_dir)
        gray_image = bad_img.convert('L')
        gray_image.save(bad_color_image_dir)

    def download(self):
        valid = True
        for d in self.data:
            for _,v in d.items():
                if not v.exists():
                    valid = False
        if valid == False:
            download_and_extract_archive(
                        url=self.url,
                        download_root=self._base_folder,
                        extract_root=self._base_folder,
                        filename="tno_temp.zip",
                        md5=self.md5,
                        remove_finished=False
                    )
            self._scale_bad_image(self._base_folder / self.folder / 'Triclobs_images' / 'Marne_15' / 'Marne_15_IR.bmp')
            self._scale_bad_image(self._base_folder / self.folder / 'Triclobs_images' / 'Marne_15' / 'Marne_15_II.bmp')
            self._resize_bad_image(self._base_folder / self.folder / 'Triclobs_images' / 'Movie_24' / 'Movie_24_IR.bmp')
            self._rgb_to_gray(self._base_folder / self.folder / 'DHV_images' / 'bench' / 'IR_37rad.bmp')
            self._rgb_to_gray(self._base_folder / self.folder / 'DHV_images' / 'wall' / 'IR_163rad.bmp')
            
            if (self._base_folder / 'tno').exists() == False:
                (self._base_folder / 'tno').mkdir() # export default dir
    
    def export(self, dest_dir = None):
        '''
        Export TNO dataset to a folder for operation with matlab.
        
        MATLAB Usage Example:
        
        # %% Read JSON config file
        # filename = 'config.json';
        # fileID = fopen(filename, 'r', 'n', 'utf8');
        # jsonData = fread(fileID, inf, 'uint8');
        # jsonData = char(jsonData');
        # fclose(fileID);
        # 
        # %% Parse JSON data
        # config = jsondecode(jsonData);
        # disp(config);
        # 
        # %% Access specific fields
        # visJson = config.vis_json;
        # nirJson = config.nir_json;
        # lwirJson = config.lwir_json;
        # visNirPairs = config.vis_nir_pairs;
        # visLwirPairs = config.vis_lwir_pairs;
        # visNirLwirPairs = config.vis_nir_lwir_pairs;
        # 
        # %% Example: Access vis_json content
        # disp(visJson);
        '''
        assert self.exported == False
        # make dir
        if dest_dir is None:
            dest_dir = Path(self.root) / 'tno' / 'tno'
        dest_dir = Path(dest_dir)
        assert dest_dir.exists()
        dest_vis_dir = dest_dir / self.export_vis_dir
        dest_lwir_dir = dest_dir / self.export_lwir_dir
        dest_nir_dir = dest_dir / self.export_nir_dir
        if dest_vis_dir.exists() == False:
            dest_vis_dir.mkdir()
        if dest_lwir_dir.exists() == False:
            dest_lwir_dir.mkdir()
        if dest_nir_dir.exists() == False:
            dest_nir_dir.mkdir()
        export_list = []
        index_counter = 1
        
        # pair images
        for _,v in self.file['pairs'].items():
            d = {
                'id': index_counter,
                'vis': self._base_folder / self.folder / v['vis']
            }
            if 'lwir' in v:
                d['lwir'] = self._base_folder / self.folder / v['lwir']
            if 'nir' in v:
                d['nir'] = self._base_folder / self.folder / v['nir']
            export_list.append(d)
            index_counter = index_counter + 1
        
        # sequence images
        for _,v in self.file['sequence'].items(): # all sequence are lwir and vis
            for i,j in zip(v['lwir']['content'], v['vis']['content']):
                export_list.append({
                    'id': index_counter,
                    'lwir': self._base_folder / self.folder / v['lwir']['base'] / i,
                    'vis': self._base_folder / self.folder / v['vis']['base'] / j
                })
                index_counter = index_counter + 1

        # copy images
        import shutil
        for d in export_list:
            shutil.copy(d['vis'],dest_vis_dir / f'{d['id']}.{d['vis'].name.split(".")[-1].lower()}')
            if 'nir' in d:
                shutil.copy(d['nir'],dest_nir_dir / f'{d['id']}.{d['nir'].name.split(".")[-1].lower()}')
            if 'lwir' in d:
                shutil.copy(d['lwir'],dest_lwir_dir / f'{d['id']}.{d['lwir'].name.split(".")[-1].lower()}')

        # save config file
        import json
        vis_json = {}            # Mapping vis id to origin path
        nir_json = {}            # Mapping nir id to origin path
        lwir_json = {}           # Mapping lwir id to origin path
        vis_nir = []             # id of vis and nir pairs
        vis_lwir = []            # id of vis and lwir pairs
        vis_nir_lwir = []        # id of vis nir and lwir pairs
        for d in export_list:
            vis_json[str(d['id'])] = str(d['vis'])
            if 'nir' in d:
                nir_json[str(d['id'])] = str(d['nir'])
            if 'lwir' in d:
                lwir_json[str(d['id'])] = str(d['lwir'])
            if 'nir' in d and 'lwir' in d:
                vis_nir_lwir.append(d['id'])
            if 'nir' in d:
                vis_nir.append(d['id'])
            if 'lwir' in d:
                vis_lwir.append(d['id'])
        config_data = {
            "vis": vis_json,
            "nir": nir_json,
            "lwir": lwir_json,
            "vis_nir_pairs": vis_nir,
            "vis_lwir_pairs": vis_lwir,
            "vis_nir_lwir_pairs": vis_nir_lwir
        }
        dest_config_dir = dest_dir / "config.json"
        with open(dest_config_dir, 'w') as json_file:
            json.dump(config_data, json_file, indent=4)

然后是我写的使用案例

import click
from pathlib import Path
from cslib.datasets.fusion import TNO

def demo_auto_download(root_dir):
    TNO(root = root_dir,download = True)

def demo_wave_length(root_dir):
    dataset_nir_lwir = TNO(root_dir, img_type = 'both')
    dataset_nir = TNO(root_dir, img_type = 'nir')
    dataset_lwir = TNO(root_dir, img_type = 'lwir') # Default
    print(f"Length of the 'nir_lwir' dataset: {len(dataset_nir_lwir)}") # 32
    print(f"Length of the 'nir' dataset: {len(dataset_nir)}") # 37
    print(f"Length of the 'lwir' dataset: {len(dataset_lwir)}") # 235

def demo_set(root_dir):
    dataset_both = TNO(root_dir, img_type = 'lwir',mode = 'both') # Default
    dataset_seq = TNO(root_dir, img_type = 'lwir',mode ='sequence')
    dataset_pairs = TNO(root_dir, img_type = 'lwir',mode = 'pairs')

    print(f"Length of the 'both' dataset: {len(dataset_both)}") # 235
    print(f"Length of the'sequence' dataset: {len(dataset_seq)}") # 180
    print(f"Length of the 'pairs' dataset: {len(dataset_pairs)}") # 55

def demo_export(root_dir):
    dataset_both_lwir_nir = TNO(
        root_dir, 
        export_lwir_dir = 'lwir',  # default
        export_nir_dir = 'nir',  # default
        export_vis_dir = 'vis',  # default
    )
    dataset_both_lwir_nir.export(Path(root_dir)/'tno'/'export')

def demo_dataloader(root_dir):
    # Dataloader Mode (Default) 
    dataset_both_lwir_nir = TNO(root_dir, img_type = 'both',mode = 'both')  
    for key in dataset_both_lwir_nir[0]:
        print(f"{key}: {type(dataset_both_lwir_nir[0][key])}")
    # vis: <class 'PIL.Image.Image'>
    # lwir: <class 'PIL.Image.Image'>
    # nir: <class 'PIL.Image.Image'>

    # Without Dataloader Mode
    dataset_both_lwir_nir = TNO(root_dir, img_type = 'both',mode = 'both', dataloader = False) 
    for key in dataset_both_lwir_nir[0]:
        print(f"{key}: {type(dataset_both_lwir_nir[0][key])}")  
    # vis: <class 'PIL.Image.Image'>
    # vis_path: <class 'pathlib.PosixPath'>
    # lwir_path: <class 'pathlib.PosixPath'>
    # lwir: <class 'PIL.Image.Image'>
    # nir_path: <class 'pathlib.PosixPath'>
    # nir: <class 'PIL.Image.Image'>

def demo_load_exported(root_dir):
    dataset = TNO(
        root_dir,
        dataloader = False, # To show this is from exported directory
        export_lwir_dir = 'lwir',  # default
        export_nir_dir = 'nir',  # default
        export_vis_dir = 'vis',  # default
        exported = True,
        export_root = Path(root_dir)/'tno'/'export',
    )
    for key in dataset[0]:
        print(f"{key}: {dataset[0][key]}")
    # vis: <PIL.Image.Image image mode=L size=461x381 at 0x16A332B40>
    # vis_path: /Volumes/Charles/data/vision/torchvision/tno/export/vis/127.bmp
    # lwir_path: /Volumes/Charles/data/vision/torchvision/tno/export/lwir/127.bmp
    # lwir: <PIL.Image.Image image mode=L size=461x381 at 0x169E30350>
    
def demo_fusion(root_dir):
    # You need to manually input the fusion images first
    dataset_fuse = TNO(
        root_dir,
        export_lwir_dir = 'lwir',  # default
        export_nir_dir = 'nir',  # default
        export_vis_dir = 'vis',  # default
        export_root = Path(root_dir)/'tno'/'export',
        exported = True,
        fusion_path = Path(root_dir)/'tno'/'export'/'fused'/'fusiongan',
        fused_extension = 'png', # Default
        fusion = True,
    )
    for key in dataset_fuse[0]:
        print(f"{key}: {type(dataset_fuse[0][key])}")
    # vis: <class 'PIL.Image.Image'>
    # lwir: <class 'PIL.Image.Image'>
    # fused: <class 'PIL.Image.Image'>

@click.command()
@click.option('--root_dir', type=click.Path(exists=True), default='/Volumes/Charles/data/vision/torchvision', help='Path to torchvision root directory')
def main(root_dir):
    ''' Auto Download '''
    # demo_auto_download(root_dir) # Download the dataset if it does not exist in the root directory

    ''' Load Different Wavelength Images'''
    # demo_wave_length(root_dir) # nir | lwir | both
    
    ''' Load Different Sets '''
    # demo_set(root_dir) # both | sequence | pairs

    ''' Dataloader Mode '''
    # demo_dataloader(root_dir)  # show image path or not

    ''' Export '''
    # demo_export(root_dir)

    ''' Load from exported '''
    # demo_load_exported(root_dir)

    ''' Fusion Mode (For computing Metrics) '''
    # demo_fusion(root_dir) # Can only load from exported path

if __name__ == '__main__':
    main()
### 关于TNO数据集的引用与使用 如果需要正确引用TNO数据集,应遵循其官方提供的引用指南。对于TNO图像融合数据集,推荐的引用格式如下[^3]: > Toet A. TNO Image fusion dataset. 此数据集主要用于图像序列处理研究,因此在实际应用中需注明该数据源。 关于TNO数据集的具体使用方法,虽然未提供详细的文档描述,但从其他类似数据集的操作流程来看,通常涉及以下几个方面的内容(基于一般数据库操作逻辑扩展而来): #### 数据加载与初始化 假设已获取到完整的TNO数据集文件包,在加载前可能需要解压并整理好目录结构。例如通过Python脚本取其中的部分图像序列: ```python import os from PIL import Image def load_tno_dataset(dataset_dir): sequences = [] for root, dirs, files in os.walk(dataset_dir): for file in files: if file.endswith(('.png', '.jpg')): img_path = os.path.join(root, file) image = Image.open(img_path) sequences.append(image) return sequences ``` 上述代码片段展示了如何遍历指定路径下的所有图片资源,并逐一打开存储至内存中的列表变量`sequences`里待后续分析调用[^1]。 #### 批量导入与管理 当面对大规模的数据记录时,则可考虑采用SQL语句来构建相应的表格模型以便更好地管理和查询这些资料信息。比如创建一张用于保存每张照片元数据的新表: ```sql CREATE TABLE IF NOT EXISTS tno_images ( id INTEGER PRIMARY KEY AUTOINCREMENT, filename TEXT UNIQUE NOT NULL, filepath TEXT NOT NULL, width INT DEFAULT 0, height INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` 接着利用 `INSERT INTO ... VALUES (...)` 的形式逐条写入对应的字段值完成整个集合的录入工作过程。 #### 注意事项 值得注意的是,由于不同版本之间可能存在差异性调整或者新增功能特性等原因影响最终效果表现;另外考虑到版权保护等因素限制也可能会对部分素材施加额外条件约束等情况发生,请务必仔细阅随附版权声明及相关协议条款后再做决定是否适合当前项目需求场景适用范围之内[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值