├── .gitattributes ├── __pycache__ └── spxy_image.cpython-38.pyc ├── crop_image.py ├── data_aug.py ├── generate_label.py ├── merge_image.py ├── readme.md ├── split_train_val.py ├── spxy.py ├── spxy_image.py └── test.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /__pycache__/spxy_image.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/springsZ/Hyperspectral-Image-Computer-Vision-Classification-Image-Preprocessing-Toolkit/4fb03814f1156d8ebadab4d16b8e67d6dae9fc1e/__pycache__/spxy_image.cpython-38.pyc -------------------------------------------------------------------------------- /crop_image.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 使用连通域分析算法去除图像中的空白部分 3 | 并将图像变为统一大小的正方形 4 | ''' 5 | 6 | from skimage import measure 7 | import skimage 8 | import numpy as np 9 | import os 10 | import cv2 11 | 12 | current_path = os.path.abspath(__file__) 13 | # 待处理图片的路径 14 | image_father_path = current_path.split('src')[0] + 'datapath' 15 | files = os.listdir(image_father_path) 16 | # 保存处理后的图片的路径 17 | save_path = current_path.split('src')[0] + 'datapath' 18 | if not os.path.exists(save_path): 19 | os.mkdir(save_path) 20 | i=0 21 | for image in files: 22 | # if i==2: 23 | # break 24 | raw_image = cv2.imread(f'{image_father_path}\\{image}') 25 | # 1. 二值化 26 | gray_image = cv2.cvtColor(raw_image, cv2.COLOR_BGR2GRAY) 27 | ret, binary_image = cv2.threshold(gray_image, 1, 255, cv2.THRESH_BINARY) 28 | # 2. 连通域分析 29 | labels = measure.label(binary_image, connectivity=2) 30 | # 3. 找出最大的连通域 31 | properties = measure.regionprops(labels) 32 | max_area = 0 33 | i+=1 34 | print(len(properties)) 35 | for prop in properties: 36 | print(prop.bbox, prop.area) 37 | if prop.area > max_area: 38 | max_area = prop.area 39 | max_prop = prop 40 | # 4. 找出最大连通域的最小外接矩形 41 | minr, minc, maxr, maxc = max_prop.bbox 42 | print(minr, minc, maxr, maxc) 43 | # 5. 将最小外接矩形的区域保存下来 44 | crop_image = raw_image[minr:maxr, minc:maxc] 45 | 46 | # 将图片变为统一大小的正方形 47 | crop_image = cv2.resize(crop_image, (224, 224)) 48 | # 6. 保存图片 49 | cv2.imwrite(f'{save_path}\\{image.split(".")[0]}.png', crop_image) -------------------------------------------------------------------------------- /data_aug.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 对数据集进行数据扩充,这里使用了四种数据扩充方式。 3 | 还可以根据项目的具体情况进行其他的数据扩充操作,比如增加噪声、模糊、增强亮度等 4 | 这里进行了整体五倍的数据扩充以及单独对HT类进行了十倍的数据扩充,以到达数据平衡的目的,可根据需求自行更改 5 | 图像增强完成后调用generate_label函数生成对应的标签文件 6 | ''' 7 | 8 | 9 | 10 | import cv2 11 | import os 12 | import numpy as np 13 | from generate_label import generate_label 14 | 15 | 16 | def data_augmentation(image, output_path): 17 | # 在这里进行数据扩充操作 18 | # 可以使用OpenCV提供的各种图像处理函数进行旋转、平移、缩放、翻转等操作 19 | # 设置种子 20 | np.random.seed(1) 21 | # 设置一个随机数,根据随机数的值,对图像进行不同的处理 22 | random_num = np.random.randint(1, 5) 23 | if random_num == 1: 24 | # 旋转90度 25 | augmented_image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE) 26 | elif random_num == 2: 27 | # 旋转180度 28 | augmented_image = cv2.rotate(image, cv2.ROTATE_180) 29 | elif random_num == 3: 30 | # 水平翻转 31 | augmented_image = cv2.flip(image, 1) 32 | elif random_num == 4: 33 | # 随机裁剪 34 | augmented_image = image[0:200, 0:200] 35 | # 缩放 36 | augmented_image = cv2.resize(image, (224, 224)) 37 | # 保存增强后的图像 38 | cv2.imwrite(output_path, augmented_image) 39 | 40 | 41 | # 原始数据集路径 42 | current_path = os.path.abspath(__file__) 43 | sub_path = 'datapath' 44 | dataset_path = current_path.split( 45 | 'src')[0] + f'{sub_path}\\train' 46 | # 增强后的数据集保存路径 47 | output_dataset_path = current_path.split( 48 | 'src')[0] + f'{sub_path}\\augmented_image_224_train_all' 49 | if not os.path.exists(output_dataset_path): 50 | os.mkdir(output_dataset_path) 51 | 52 | # 遍历原始数据集 53 | for root, dirs, files in os.walk(dataset_path): 54 | print(root) 55 | for file in files: 56 | # if 'HT' not in file: 57 | # continue 58 | 59 | # 读取原始图像 60 | image_path = os.path.join(root, file) 61 | image = cv2.imread(image_path) 62 | output_path = os.path.join(output_dataset_path, file) 63 | cv2.imwrite(output_path, image) 64 | for i in range(5): 65 | # 定义增强后的图像路径 66 | output_path = os.path.join( 67 | output_dataset_path, str(i)+'-'+file) 68 | 69 | # 对原始图像进行数据扩充 70 | 71 | data_augmentation(image, output_path) 72 | 73 | for root, dirs, files in os.walk(dataset_path): 74 | print(root) 75 | for file in files: 76 | if 'HT' not in file: 77 | continue 78 | 79 | # 读取原始图像 80 | image_path = os.path.join(root, file) 81 | image = cv2.imread(image_path) 82 | # output_path = os.path.join(output_dataset_path,file) 83 | # cv2.imwrite(output_path, image) 84 | for i in range(10): 85 | # 定义增强后的图像路径 86 | output_path = os.path.join(output_dataset_path, str(i+5)+'-'+file) 87 | 88 | # 对原始图像进行数据扩充 89 | 90 | data_augmentation(image, output_path) 91 | 92 | generate_label(output_dataset_path, 'train') 93 | val_path = current_path.split( 94 | 'src')[0] + f'{sub_path}\\val' 95 | generate_label(val_path, 'val') 96 | -------------------------------------------------------------------------------- /generate_label.py: -------------------------------------------------------------------------------- 1 | # 在使用 DataLoader 加载数据集时,标签应该与每个数据样本相关联,并存储在数据集的相应位置。常见的做法是将标签作为数据集中每个样本的第二个元素,即(image, label) 对。 2 | 3 | # 在 PyTorch 中,可以使用 ImageFolder 数据集类来方便地组织带标签的数据集。ImageFolder 期望数据集的目录结构符合以下方式: 4 | 5 | # Copy 6 | # root/class1/image1.jpg 7 | # root/class1/image2.jpg 8 | # ... 9 | # root/class2/image1.jpg 10 | # root/class2/image2.jpg 11 | # ... 12 | # 这样,ImageFolder 将自动为每个图像分配一个类别标签,并将其存储在 data_loader 返回的数据对中。 13 | ''' 14 | 根据图片标签将图片复制到指定文件夹,生成dataloader需要的格式 15 | ''' 16 | 17 | import os 18 | import shutil 19 | 20 | 21 | def move_and_rename_image(image_path, destination_folder, new_filename): 22 | """ 23 | 将图片移动到指定文件夹,并且重命名 24 | :param image_path: 图片路径 25 | :param destination_folder: 目标文件夹 26 | :param new_filename: 新的文件名 27 | :return: 28 | """ 29 | # 提取原始文件名和扩展名 30 | original_filename, extension = os.path.splitext(image_path) 31 | if os.path.exists(destination_folder) == False: 32 | os.makedirs(destination_folder) 33 | # 构建目标路径 34 | destination_path = os.path.join( 35 | destination_folder, new_filename + extension) 36 | 37 | # 移动并重命名图片 38 | shutil.copy(image_path, destination_path) 39 | 40 | 41 | def generate_label(data_path, type='train'): 42 | 43 | # 获取当前文件的绝对路径 44 | current_file_path = os.path.abspath(__file__) 45 | print(current_file_path) 46 | image_father_path = data_path 47 | 48 | print(image_father_path) 49 | 50 | files = os.listdir(image_father_path) 51 | # 将图片复制到指定文件夹中并重命名 52 | for i in range(len(files)): 53 | target_path = f"{ current_file_path.split('src')[0]}data\\{type}" 54 | 55 | if files[i].find('HT') != -1: 56 | move_and_rename_image(image_father_path + '\\' + files[i], 57 | target_path+'\\0', str(i)) 58 | elif files[i].find('NH') != -1: 59 | print('NH', files[i]) 60 | move_and_rename_image(image_father_path + '\\' + files[i], 61 | target_path+'\\1', str(i)) 62 | elif files[i].find('PY') != -1: 63 | print('PY', files[i]) 64 | move_and_rename_image(image_father_path + '\\' + files[i], 65 | target_path+'\\2', str(i)) 66 | -------------------------------------------------------------------------------- /merge_image.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 将三个波段下的灰度图合并成伪彩图,丰富图像信息,此处的灰度图为三个通道(R G B)都是相同值的灰度图 3 | ''' 4 | 5 | 6 | import cv2 7 | import numpy as np 8 | import os 9 | 10 | def get_image(image_name): 11 | current_file_path = os.path.abspath(__file__) 12 | image_father_path = current_file_path.split('src')[0] + 'RGB\\' 13 | gray_image_path_1 = image_father_path + f'blue\\{image_name}.png' 14 | gray_image_path_2 = image_father_path + f'green\\{image_name}.png' 15 | gray_image_path_3 = image_father_path + f'red\\{image_name}.png' 16 | gray_image_1 = cv2.imread(gray_image_path_1) 17 | gray_image_2 = cv2.imread(gray_image_path_2) 18 | gray_image_3 = cv2.imread(gray_image_path_3) 19 | return gray_image_1, gray_image_2, gray_image_3 20 | 21 | 22 | current_file_path = os.path.abspath(__file__) 23 | image__dir = current_file_path.split('src')[0] + 'blue' 24 | imagelist = os.listdir(image__dir) 25 | merged_image_path = current_file_path.split('src')[0] + 'merged_image' 26 | if not os.path.exists(merged_image_path): 27 | os.mkdir(merged_image_path) 28 | for image_name in imagelist: 29 | gray_image_1, gray_image_2, gray_image_3 = get_image(image_name.split('.')[0]) 30 | # 创建具有三个通道的空白图像 31 | merged_image = np.zeros( 32 | (gray_image_1.shape[0], gray_image_1.shape[1], 3), dtype=np.uint8) 33 | 34 | # 将灰度图像复制到相应的通道 35 | merged_image[:, :, 0] = gray_image_1[:, :, 0] 36 | merged_image[:, :, 1] = gray_image_2[:, :, 0] 37 | merged_image[:, :, 2] = gray_image_3[:, :, 0] 38 | 39 | # 保存合并的图像 40 | cv2.imwrite(f'{merged_image_path}\\{image_name}.png', merged_image) 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 功能 2 | 3 | 包含了一些在进行训练之前可能会用的图像处理函数,尤其可能适用于对于高光谱类计算机视觉分类任务,目前包括了: 4 | 5 | 1. 检测原始图像的类型,是否是伪彩图或者三通道相同的灰度图 6 | 2. 指定任意三个波段合并成伪彩图图像,以丰富图像信息 7 | 3. 使用连通域分析法对伪彩图进行分割,以去除图像中的黑色背景,并重新统一图像大小 8 | 4. 数据增强,包括随机旋转、随机裁剪、随机翻转等,可根据实际情况自行增改新的数据增强方法 9 | 5. 生成 pytorch 中 dataloader 所需的数据集类型 10 | 6. 使用 spxy 算法对光谱数据划分训练集和验证集,并按照划分的索引对图像数据集进行一一对应划分 11 | 12 | # todo 13 | 14 | 1. 模型的评价指标计算 15 | 2. ...... 16 | -------------------------------------------------------------------------------- /split_train_val.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 按照7:3的比例划分训练集和验证集 3 | ''' 4 | 5 | from skimage import measure 6 | import skimage 7 | import numpy as np 8 | import os 9 | import cv2 10 | import shutil 11 | 12 | current_path = os.path.abspath(__file__) 13 | image_father_path = current_path.split('src')[0] + 'crop_image_224' 14 | files = os.listdir(image_father_path) 15 | train_save_path = current_path.split('src')[0] + 'crop_image_224\\train' 16 | val_save_path = current_path.split('src')[0] + 'crop_image_224\\val' 17 | if not os.path.exists(train_save_path): 18 | os.mkdir(train_save_path) 19 | if not os.path.exists(val_save_path): 20 | os.mkdir(val_save_path) 21 | # 设置随机种子 22 | np.random.seed(0) 23 | 24 | # 按照7:3的比例划分训练集和验证集,同时三个类别的都按照这个比例划分 25 | for image in files: 26 | if np.random.rand() < 0.8: 27 | shutil.copy(f'{image_father_path}\\{image}', f'{train_save_path}\\{image}') 28 | else: 29 | shutil.copy(f'{image_father_path}\\{image}', f'{val_save_path}\\{image}') 30 | 31 | -------------------------------------------------------------------------------- /spxy.py: -------------------------------------------------------------------------------- 1 | '''使用spxy算法对数据进行分割,分割成训练集和验证集,并保存图片对应的名称,引入spxy_image函数,将图片也分割成对应的训练集和验证集''' 2 | 3 | import numpy as np 4 | import os 5 | import pandas as pd 6 | from spxy_image import spxy_image 7 | 8 | 9 | def spxy(x, y, indexx, test_size=0.2): 10 | """ 11 | :param x: shape (n_samples, n_features) 12 | :param y: shape (n_sample, ) 13 | :param test_size: the ratio of test_size 14 | :return: spec_train :(n_samples, n_features) 15 | spec_test: (n_samples, n_features) 16 | target_train: (n_sample, ) 17 | target_test: (n_sample, ) 18 | """ 19 | x_backup = x 20 | y_backup = y 21 | # print(index) 22 | M = x.shape[0] 23 | N = round((1-test_size) * M) 24 | samples = np.arange(M) 25 | 26 | y = (y - np.mean(y))/np.std(y) 27 | D = np.zeros((M, M)) 28 | Dy = np.zeros((M, M)) 29 | 30 | for i in range(M-1): 31 | xa = x[i, :] 32 | ya = y[i] 33 | for j in range((i+1), M): 34 | xb = x[j, :] 35 | yb = y[j] 36 | D[i, j] = np.linalg.norm(xa-xb) 37 | Dy[i, j] = np.linalg.norm(ya - yb) 38 | 39 | Dmax = np.max(D) 40 | Dymax = np.max(Dy) 41 | D = D/Dmax + Dy/Dymax 42 | 43 | maxD = D.max(axis=0) 44 | index_row = D.argmax(axis=0) 45 | index_column = maxD.argmax() 46 | 47 | m = np.zeros(N) 48 | m[0] = index_row[index_column] 49 | m[1] = index_column 50 | m = m.astype(int) 51 | 52 | dminmax = np.zeros(N) 53 | dminmax[1] = D[m[0], m[1]] 54 | 55 | for i in range(2, N): 56 | pool = np.delete(samples, m[:i]) 57 | dmin = np.zeros(M-i) 58 | for j in range(M-i): 59 | indexa = pool[j] 60 | d = np.zeros(i) 61 | for k in range(i): 62 | indexb = m[k] 63 | if indexa < indexb: 64 | d[k] = D[indexa, indexb] 65 | else: 66 | d[k] = D[indexb, indexa] 67 | dmin[j] = np.min(d) 68 | dminmax[i] = np.max(dmin) 69 | index = np.argmax(dmin) 70 | m[i] = pool[index] 71 | 72 | m_complement = np.delete(np.arange(x.shape[0]), m) 73 | spec_train = x[m, :] 74 | target_train = y_backup[m] 75 | spec_test = x[m_complement, :] 76 | target_test = y_backup[m_complement] 77 | index_train = indexx[m] 78 | index_test = indexx[m_complement] 79 | 80 | return spec_train, spec_test, target_train, target_test, index_train, index_test 81 | 82 | 83 | if __name__ == '__main__': 84 | current_file_path = os.path.abspath(__file__) 85 | print(current_file_path) 86 | file_path = current_file_path.split('src')[0] + 'raw.xlsx' 87 | data = pd.read_excel(file_path) 88 | # 其中x是除了前三列的所有列,y是第三列,index记录第一列的值 89 | x = data.iloc[:, 3:].values 90 | y = data.iloc[:, 2].values 91 | indexx = data.iloc[:, 0].values 92 | spec_train, spec_test, target_train, target_test, index_train, index_test = spxy( 93 | x, y, indexx, test_size=0.2) 94 | # 拿到data的列名 95 | columns = data.columns.values.tolist() 96 | # 拿到x的列名 97 | columns_x = columns[3:] 98 | columns_y = columns[2] 99 | # print(index_train) 100 | # print(len(index_train), len(index_test)) 101 | print(spec_train) 102 | # 将训练集和验证集以及index都保存下来 103 | train = pd.DataFrame(spec_train, columns=columns_x) 104 | train[columns_y] = target_train 105 | train['index'] = index_train 106 | # 把index列放到第一列 107 | cols = train.columns.tolist() 108 | cols = cols[-1:] + cols[:-1] 109 | # 保存为xlsx文件 110 | train = train[cols] 111 | train.to_excel(current_file_path.split('src')[ 112 | 0] + '\\train.xlsx', index=False) 113 | 114 | test = pd.DataFrame(spec_test, columns=columns_x) 115 | test[columns_y] = target_test 116 | test['index'] = index_test 117 | cols = test.columns.tolist() 118 | cols = cols[-1:] + cols[:-1] 119 | test = test[cols] 120 | test.to_excel(current_file_path.split('src')[ 121 | 0] + '\\test.xlsx', index=False) 122 | 123 | spxy_image('crop_image_224', 'spxy_224') 124 | -------------------------------------------------------------------------------- /spxy_image.py: -------------------------------------------------------------------------------- 1 | '''根据spxy算法得出的训练集和测试集对应的标签对图像数据集也进行一一对应划分''' 2 | import skimage 3 | import numpy as np 4 | import os 5 | import cv2 6 | import shutil 7 | import pandas as pd 8 | # raw_path = 'crop_image_224' save_path = 'spxy_224' 9 | 10 | 11 | def spxy_image(raw_path, save_path): 12 | current_path = os.path.abspath(__file__) 13 | image_father_path = current_path.split( 14 | 'src')[0] + f'{raw_path}' 15 | files = os.listdir(image_father_path) 16 | train_save_path = current_path.split( 17 | 'src')[0] + f'{save_path}\\train' 18 | val_save_path = current_path.split( 19 | 'src')[0] + f'{save_path}\\val' 20 | if not os.path.exists(train_save_path): 21 | os.mkdir(train_save_path) 22 | if not os.path.exists(val_save_path): 23 | os.mkdir(val_save_path) 24 | 25 | df_train = pd.read_excel(current_path.split('src')[ 26 | 0] + 'train.xlsx') 27 | df_test = pd.read_excel(current_path.split('src')[ 28 | 0] + 'test.xlsx') 29 | 30 | train_index = df_train['index'].tolist() 31 | # print(train_index) 32 | test_index = df_test['index'].tolist() 33 | # print(test_index) 34 | 35 | for image in files: 36 | find_image = image.split('.')[0] + '.npy' 37 | if find_image in train_index: 38 | shutil.copy(f'{image_father_path}\\{image}', 39 | f'{train_save_path}\\{image}') 40 | elif find_image in test_index: 41 | shutil.copy(f'{image_father_path}\\{image}', 42 | f'{val_save_path}\\{image}') 43 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | '''测试某个图片三个通道数据是否相同''' 2 | 3 | import cv2 4 | import numpy as np 5 | 6 | # 读取图像 7 | image = cv2.imread('HT.png') 8 | 9 | # 分离通道 10 | channels = cv2.split(image) 11 | 12 | # 获取每个通道的最大值 13 | max_values = [] 14 | for channel in channels: 15 | max_value = np.max(channel) 16 | max_values.append(max_value) 17 | 18 | # 打印每个通道的最大值 19 | for i, max_value in enumerate(max_values): 20 | print(f"通道 {i}: 最大值为 {max_value}") 21 | 22 | if np.array_equal(channels[0], channels[1]) and np.array_equal(channels[1], channels[2]): 23 | print("三个通道内的数据相同") 24 | else: 25 | print("三个通道内的数据不相同") 26 | --------------------------------------------------------------------------------