数据处理的一些方法
本人刚学习的一个小白。最近在对一些医学图像如(PET,CT)等做识别的时候,碰到了许多问题,主要就是一些如何用opencv或者图形变换对一些灰度图进行增强的方法,为了避免以后自己再去百度查一些操作,先记录下来。欢迎大家评论交流。
ImageFolder
imagefolder使用的前提是数据要按照一种特定的格式,如下图所示:
在train这个文件夹下面有AD和CN两个文件夹,这两种文件夹里面存放一类图片,且AD和CD为代表的类的类名。按这种形式存放的数据就可以用Imagefolder直接添加,实现代码:
dataset1=ImageFolder(path)
imagefolder的构造函数表现是:
ImageFolder(self, root, transform=None, target_transform=None,
loader=default_loader, is_valid_file=None)
其中:
root:表示图片的路径
transform:表示是否进行图片进行操作。image folder默认读出来的数据格式为PIL的Image对象。可以在外部写transform方法
一般的transform函数的格式:
transforms=torchvision.transforms.Compose(
[
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(mean=(0.5,),std=(0.5,))#均值和方差
]
)
target_transform:表示是否对标签进行一个转换。比如定义一个转换类名的函数之类的。
loader表示读取数据的方式
取值:
class data1(Dataset):
def __init__(self,path):
self.path=path
self.dataset=[]
self.dataset1=ImageFolder(self.path)
print(self.dataset1.class_to_idx)
for i in self.dataset1.imgs:
lujin=i[0]
leibie=str(i[1])
代码中self.dataset1.imgs取出来的其实是路径名和分类:
而self.dataset1.class_to_idx获取到的其实是设定的文件夹下的类别的名字和对应的一个类别代表数
这之后就有两种手段进行数据的处理:
1.Imagefolder加载完之后的数据就可以直接用Dataloader进行加载了,感觉挺方便的
2.不过我第一次用imagefolder,所以在获取到路径和类别名字之后重新写了一个读取数据的方法。主要就是用.os,opencv,和PIL中的Image来进行数据集的读取。
在读取数据的过程中就遇到了几个问题:
1:在对同一张灰度图进行读取的时候,用opencv的Imread读取出来的数据是ndarray类型的,并且读出来的一个形状是(168,168,3),但是用Image open读取出来在转ndarray之后是(168,168)的,所以在要获取ndarray类型数据的时候选用opencv来进行一个读取更为合适。
2:对于Image.open()函数默认真彩图像读取通道顺序为RGB,而cv2.imread()则是BGR
opencv对图像的一些操作
1.二值化操作
我对二值化的一些操作做了一个总结,有需要的可以点击这个博客:二值化操作总结
2.拉普拉斯算+透明度加强
Laplace = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32) # 定义一个滤波核
c = cv2.filter2D(c, -1, kernel=Laplace)
c = cv2.convertScaleAbs(c, alpha=2, beta=0)
这个方法主要对一些灰度图片有很好的加强效果
3.直方图自适应均值化
dst = cv2.GaussianBlur(c, ksize=(5, 5), sigmaX=0) # 先高斯,作用是模糊去噪
c = cv2.addWeighted(dst, 3, dst, -2, 0)
cv2.imshow("222", c)
这个方法和用拉普拉斯实现的效果差不多,可以选择之后再进行加强
4.灰度图+自定义二值化+否运算+闭运算+canny算法实现脑细胞的轮廓提取
c=cv2.cvtColor(c,cv2.COLOR_RGB2GRAY)
h, w = c.shape[:2]
m = np.reshape(c, [1, w * h]) # 将gray的图像(h*w)转化为[1行,w*h列]的数组
mean = m.sum() / (w * h)
ret, binary = cv2.threshold(c, mean, 255, cv2.THRESH_BINARY_INV)
c = cv2.resize(c, (600, 600))
binary = cv2.resize(binary, (600, 600))
binary = cv2.bitwise_not(binary)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (22, 22))
binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
# binary=cv2.bitwise_and(c,binary)
binary = cv2.Canny(binary, 100, 150)
能够达到这种效果:
5.图像的增样(旋转增样)
旋转增样,对原始的图像进行一个按度数旋转,旋转之后不进行裁剪,就能够达到一种随机缩放的一种效果,生成的图片的大小都是不定的。
b = -math.radians(b % 360) # 将角度化为弧度
n = np.size(image, 0)
m = np.size(image, 1)
center = (n/2.0, m/2.0)
img = np.zeros((n, m))
if not crop:
xx = []
yy = []
for x0, y0 in ((0, 0), (n, 0), (n, m), (0, m)):
x = (x0 - center[0]) * math.cos(b) + (y0 - center[1]) * math.sin(b)
y = -1*(x0 - center[0]) * math.sin(b) + (y0 - center[1]) * math.cos(b)
xx.append(x)
yy.append(y)
nn = int(math.ceil(max(xx)) - math.floor(min(xx)))
nm = int(math.ceil(max(yy)) - math.floor(min(yy)))
img = np.zeros((nn, nm))
center = (nn/2, nm/2)
for x in range(nn):
for y in range(nm):
x0 = (x-center[0])*math.cos(-b)+(y-center[1])*math.sin(-b)+center[0]
y0 = -1*(x-center[0])*math.sin(-b)+(y-center[1])*math.cos(-b)+center[1]
# 将坐标对齐
x0 = x0-(nn-n)/2
y0 = y0-(nm-m)/2
# 双线性内插值
i = int(x0)
j = int(y0)
u = x0 - i
v = y0 - j
if inmap(i, j):
f1 = (1-u)*(1-v)*image[i, j]
img[x, y] += f1
if inmap(i, j+1):
f2 = (1-u)*v*image[i, j+1]
img[x, y] += f2
if inmap(i+1, j)