数据爬取
在一些项目中,数据是非常重要的,而数据的获取方式就成为了一个问题。通常数据的来源有以下三种:第一种是专用数据集,通常是一些知名的数据集和一些比赛的数据集;第二种是网上下载,通常是手动下载或者是网站购买;第三种就是在符合规定的情况下利用爬虫工具进行数据是手机。这三种方式中,利用爬虫工具是最快捷最方便的一种方式。以下就是利用爬虫工具获取的一些车的照片,总共100张,展示如下:
数据筛选
但是往往获取到的数据中会有一些异常数据,比如图片文件大小不符、分辨率太低、亮度过亮或过暗、对比度较低等问题,需要进行数据的筛选,而数据筛选有低级特征筛选和高级特征筛选两种方式。
低级特征筛选主要是对文件信息、颜色特征和纹理特征进行筛选;
高级特征筛选这里主要是通过神经网络提取图像深层特征获取每张图片的均值和方差,为防止数据信息过多的丢失,采取非线性降维方法将特征进行降维,然后进行聚类,分析数据的平衡性。
- **低级特征筛选:**这里主要是对图片进行文件大小、分辨率、图像梯度、亮度、对比度的分析,当文件大小小于10KB、分辨率小于256、图像梯度小于50、亮度过亮或者过暗、对比度低时,判断为异常数据,具体代码如下:
# 文件大小、分辨率、图像梯度
def check_img(img_path):
'''
从文件大小、分辨率、梯度三个方面进行检测
:param img_path:
:return:
'''
img = cv2.imread(img_path, flags=cv2.IMREAD_COLOR)
# file info:文件大小、分辨率、长宽比
file_size = os.path.getsize(img_path) # 获取文件大小
img_height, img_width = img.shape[:2] # 获取图片分辨率
if file_size < 10 * 1024 or img_width < 256 or img_height < 256:
return False
# image basic feature:图像颜色和纹理信息:纹理图像梯度
img_dy = img[:img_height-1] - img[1:]
img_dx = img[:, :img_width-1] - img[:, 1:]
img_gradient = np.mean(np.abs(img_dx)) + np.mean(np.abs(img_dy))
print(img_path, "img_gradient =", img_gradient)
if img_gradient < 50:
return False
return True
# 判断亮度
def bright_check(img_path):
'''
从亮度进行检测
:param img_path:图片路径
:return:bool值
'''
# 把图片转换为单通道的灰度图
img = cv2.imread(img_path, flags=cv2.IMREAD_COLOR)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 获取形状以及长宽
img_shape = gray_img.shape
height, width = img_shape[0], img_shape[1]
size = gray_img.size
# 灰度图的直方图
hist = cv2.calcHist([gray_img], [0], None, [256], [0, 256])
# 计算灰度图像素点偏离均值(128)程序
a = 0
ma = 0
reduce_matrix = np.full((height, width), 128)
shift_value = gray_img - reduce_matrix
shift_sum = sum(map(sum, shift_value))
da = shift_sum / size
# 计算偏离128的平均偏差
for i in range(256):
ma += (abs(i - 128 - da) * hist[i])
m = abs(ma / size)
# 亮度系数
k = abs(da) / m
if k[0] > 1:
# 过亮
# if da > 0:
# print("过亮")
# else:
# print("过暗")
return False
else:
# print("亮度正常")
return True
# 对比度判断
def check_contrast(img_path):
'''
从对比度方面进行检测
:param img_path:图片路径
:return:是否对比度低的bool值
'''
from skimage import data, exposure, io
img = cv2.imread(img_path, flags=cv2.IMREAD_COLOR)
result = exposure.is_low_contrast(img)
return result
- 主代码如下:
if __name__ == '__main__':
root_dir = "../Image-Downloader-master/download_images/car"
file_suffix = "jpeg|jpg|png|bmp"
remove_dir = root_dir + "/remove"
if not os.path.exists(remove_dir):
os.makedirs(remove_dir)
for img_name in os.listdir(root_dir):
# 对处理文件的类型进行过滤
if re.search(file_suffix, img_name) is None:
continue
img_path = root_dir + "/" + img_name
if not check_img(img_path) or not bright_check(img_path) or check_contrast(img_path):
output_path = remove_dir + "/" + img_name
shutil.move(img_path, output_path)
筛选结果:经过低级特征筛选之后,筛选出异常数据21张,如下:
- **高级特征筛选:**这里主要是利用ResNet50网络进行高级特征筛选,获取特征提取层的深层特征,提取出相应的深层特征图的均值和方差,然后分别利用tsne方法和umap方法进行特征降维,再进行异常数据分析,对于一些离群数据判别为异常数据。
- ResNet网络代码如下:
import torch
import torch.nn as nn
from torchvision import models
import torch.nn.functional as F
def global_std_pool2d(x):
"""2D global standard variation pooling"""
return torch.std(x.view(x.size()[0], x.size()[1], -1, 1), dim=2, keepdim=True)
class ResNet50(torch.nn.Module):
"""Modified ResNet50 for feature extraction"""
def __init__(self):
super(ResNet50, self).__init__()
self.features = nn.Sequential(*list(models.resnet50(pretrained=True).children())[:-2])
# 冻结模型
for p in self.features.parameters():
p.requires_grad = False
# 检测是否有GPU
if torch.cuda.is_available():
self.device = torch.device("cuda")
else:
self.device = torch.device("cpu")
self.to(self.device)
def forward(self, x):
# features@: 7->res5c
for ii, model in enumerate(self.features):
x = model(x)
if ii == 7:
features_mean = nn.functional.adaptive_avg_pool2d(x, 1)
features_std = global_std_pool2d(x)
return features_mean, features_std
# 提取图像特征
def get_img_feature(model, img_path):
img = cv2.imread(img_path, flags=cv2.IMREAD_COLOR)
img = torch.from_numpy(img)
img = img.to(model.device).float()
img = torch.unsqueeze(img, 0) # batch size 1
img = img.permute(0, 3, 1, 2)
feature = model(img)
return feature
- 特征降维代码如下:
# UMAP降维
def do_umap(features, channel=2, random_state=None):
model = umap.UMAP(n_components=channel, random_state=random_state)
return model.fit_transform(features), model
# t-SNE降维
def do_tsne(data, random_state=0):
tsne = TSNE(n_components=2, init='pca', random_state=random_state)
tsne_array = tsne.fit_transform(data)
tsne_df = pd.DataFrame(data=tsne_array) # 转换数据格式 , index=data.index
return tsne_array, tsne_df, tsne
- 绘制图像
# 绘制数据图像
def plot_embedding(data, type=None, text=None, title="", colors=None):
if type is None:
type = np.zeros_like(data[:, 0])
x_min, x_max = np.min(data, 0), np.max(data, 0)
data = (data - x_min) / (x_max - x_min)
fig = plt.figure()
ax = plt.subplot(111)
for i in range(data.shape[0]):
if text is not None:
plt.text(data[i, 0], data[i, 1], str(text[i]),
color=plt.cm.Set1((type[i] + 1) / 10.) if colors is None else colors[type[i]],
fontdict={'weight': 'bold', 'size': 8})
else:
plt.scatter(data[i, 0], data[i, 1], s=3,
color=plt.cm.Set1((type[i] + 1) / 10.) if colors is None else colors[type[i]])
plt.xticks([])
plt.yticks([])
plt.title(title)
plt.show()
return fig
- 主代码
if __name__ == '__main__':
root_dir = "../Image-Downloader-master/download_images/car"
file_suffix = "jpeg|jpg|png"
remove_dir = root_dir + "/remove1"
if not os.path.exists(remove_dir):
os.makedirs(remove_dir)
# 模型初始化
model = ResNet50()
# 提取图像特征
feature_list = []
name_list = []
for img_name in os.listdir(root_dir)[:]:
# 对处理文件的类型进行过滤
if re.search(file_suffix, img_name) is None:
continue
img_path = root_dir + "/" + img_name
# 获取图像深层特征
mean, std = get_img_feature(model, img_path)
mean = mean.to('cpu').numpy().reshape(-1)
std = std.to('cpu').numpy().reshape(-1)
feature = np.concatenate((mean, std), 0)
print(feature.shape)
feature_list.append(feature)
name_list.append(img_name[7:9])
# 特征绘图
feature_list = np.array(feature_list)
name_list = np.array(name_list)
feature_list_tsne, tsne_df, _ = do_tsne(feature_list)
plot_embedding(feature_list_tsne, text=name_list)
feature_list_umap, _ = do_umap(feature_list)
plot_embedding(feature_list_umap, text=name_list)
cv2.waitKey()
- 获得的特征降维之后的图为:
- tsne图:
从tsne特征降维图可知,数据分布较为均衡,接近一个椭圆,但是也存在一些离群点,如99; - umap特征降维方法:
从umap特征提取方法可知,数据分布较为混乱,类别很多,但是每一种类别之间较为集中,较为不错。
两种降维方法,不能通过数据分布判别为谁好谁坏,需要根据最后的效果而定。