基于明度和RGB通道方差的异常图片检测:筛除病理切片中的组织液、肌肉和纯色区域(深色、亮色图片检测)
问题描述
在全视野病理切片(WSI)的预处理中,将WSI切割成patch是其中非常重要的环节。最近在实验的过程中,发现生成的数据集中存在几种异常的图片。于是我抽样了少量正常图片和各类异常进行分析。
下面文件夹中中除了1030开头的,11,12,29-33,35-48之外全是异常的图片。其中150开头的图片是一些发霉的组织,编号1-10、22、23、26、28主要是组织液,2156-2161表示肌肉纤维,其余的纯黑、纯白、黑白相间、黑灰相间的图片也是异常图片。我们要做的就是:删除所有的异常切片并保留正常切片
本文介绍了一种基于明度(亮度)和RGB通道方差的异常图片检测方法,由于只在小数据集上测试,算法中的阈值设计较为粗糙。等过几天数据集生成完成之后我会在所有数据上测试并完善算法。
算法设计
观察发现,异常图像亮度与正常图像存在明显差异,除了纯色的图片外,组织液和肌肉的图片明显偏亮,发霉的组织明显偏暗。因此基于图像的亮度应该能筛除大部分的异常图片。我们知道对于HSV图像来说,v通道代表图片的明度(亮度)。因此我们可以先利用各图片v通道的数值进行筛选。
import cv2
import glob
import os
import numpy as np
path = r'/home/hongj/workshop/abnormal_img/' # 在此处改路径
def abnormal_img_detect(s_path):
paths1 = glob.glob(os.path.join(s_path, '*.tif')) # 找出所有tif文件
paths2 = glob.glob(os.path.join(s_path, '*.png')) # 找出所有tif文件
paths = paths1 + paths2
paths.sort() # 重新排序
for img_file in paths:
img = cv2.imread(img_file, cv2.IMREAD_COLOR) # 之后要针对单通道进行分析
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv_img)
(v_mean, v_std) = cv2.meanStdDev(v)
# 去掉和过亮、过暗的
if v_mean < 150 or v_mean > 200 : # 这里的阈值比较粗糙,需要进一步设计
os.remove(img_file)
print(img_file, float(v_mean))
return True
abnormal_img_detect(path)
代码运行之后,剩下下面的图片。过亮或者过暗的图片都被删除了,且没有删错正常的图片。剩下明暗相间的图片没有被删除,这种现象也是很好理解的。
彩色图像可以分为RGB三个通道,一般来说黑、灰、白等颜色的区域RGB三个通道的数值会非常接近。因此我分别提取三个通道的均值,再基于三个通道均值的方差进行判断,代码如下
import cv2
import glob
import os
import numpy as np
path = r'/home/hongj/workshop/abnormal_img/' # 在此处改路径
def abnormal_img_detect(s_path):
paths1 = glob.glob(os.path.join(s_path, '*.tif')) # 找出所有tif文件
paths2 = glob.glob(os.path.join(s_path, '*.png')) # 找出所有tif文件
paths = paths1 + paths2
paths.sort() # 重新排序
for img_file in paths:
img = cv2.imread(img_file, cv2.IMREAD_COLOR) # 之后要针对单通道进行分析
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
B, G, R = cv2.split(img)
(B_mean, B_std) = cv2.meanStdDev(B)
(G_mean, G_std) = cv2.meanStdDev(G)
(R_mean, R_std) = cv2.meanStdDev(R)
h, s, v = cv2.split(hsv_img)
(v_mean, v_std) = cv2.meanStdDev(v)
# 去掉纯色的和过亮、过暗的
if v_mean < 150 or v_mean > 200 or np.var([B_mean, G_mean, R_mean]) < 40: # 这里的阈值比较粗糙,需要进一步设计
os.remove(img_file)
print(img_file, float(v_mean))
return True
abnormal_img_detect(path)
运行结果如下,可见异常图片都被删除的同时,正常图片都得以保留
说明
- 我通过将各个图片v通道的均值,B、G、R通道均值的方差打印出来进行观察,最终确定阈值,其中有不严谨的地方,在处理更大的数据集中肯定需要对其进行调整。
- 对于病理切片数据集来说,正常组织的区域远大于肿瘤区域,正常组织的数据也远比肿瘤区域的数据充足。而上面这种异常情况大部分都出现生成正常组织patch的时候,因此我认为即使误删了一部分图片,也不会对训练造成影响
- 本方法可以推广到其它异常图片检测的工作中,具有一定的推广性。