赞
踩
根据自己的理解写的,不对的地方请指正!
本篇文章主要讨论的是染色归一化技术,
涉及两篇论文:
《Structure-Preserving Color Normalization and Sparse Stain Separation for Histological Images》和《Fast GPU-Enabled Color Normalization for Digital Pathology》
第一篇就是经典的SPCN 染色归一化技术,主要学习其中的基础理论知识和数学公式的推导。
第二篇是在第一篇的基础上做了一些改进,并加入了GPU加速。
后面会贴复现的代码和两者的对比。
本文截图均来自论文
大致来说就是以下几点:
所以,使用染色归一化技术 可以增加模型的性能。
structure-preserving color normalization,SPCN 指的是结构保留式的染色归一化技术。
首先,我们先理解论文中出现的几个专业名词。
1. 染色分离 stain separation
原文中是这么说的,Thus, estimation of stain density maps and color appearances i.e., stain separation is central to many color normalization techniques including the proposed techniques presented here, which transforms the RGB channels of a histological image into an absorption or density map for each stain.
我理解的大概意思就是可以把RGB图像拆解成 染色基础矩阵 和 染色密度图。
2. 比尔- 朗伯定律 Beer-Lambert law
原文,Stained tissue attenuates light in a certain spectrum depending on the type and amount of stain it has absorbed.
大概意思就是 染色的组织会衰减特定光谱中的光,具体取决于其吸收的染色剂的类型和数量。
对于一张病理切片,其每个像素的RGB值可以称为整张图像的强度,用 符号表示。
使用仪器扫描制作切片时,使用的光照强度 ,假设为255。
所以其 相对光密度矩阵(观察矩阵)
然后将 进行染色分离,分为染色基础矩阵 和染色密度图 ,其中 的形状是m*r,的形状是r*n,m是通道数 (RGB 三个通道),n是像素的个数,r是染色剂的数量
整合公式,染色后的图像 就可以有以下公式得到
染色基础矩阵 是通过无监督的稀疏字典学习 得到的,
染色密度图 是通过稀疏非负矩阵分解(sparse non-negative matrix factorization, SNMF)得到,
上面是用到的一些基本公式,下面我们说一下SPCN。
SPCN是一种结构保留式的染色归一化技术,结构保留 就体现在染色密度上,
具体思路是 先选一张染色效果标准的图像,计算得出对应的 和,称为目标 target
然后将你需要染色归一化的图像 计算其对应的 和 ,称为源 source
为了将源图像的颜色向目标图像的颜色靠拢,先利用 对 进行正则化,其中 RM表示99%分位点。
然后,保留了源图像的染色密度,相当于保留了源图像的结构,只更换了染色基础矩阵。
注意:这里是
最后,将染色后的光密度图 恢复
具体流程图如下:
1. SPCN 在颜色基础估计中偶尔会出现错误,会给WSI的背景提供彩色色调
具有显著背景部分的图像,这在极端情况下导致标准化后背景中的强烈色调。
2. 提取染色颜色原型的不一致:当由于少数非常暗的细胞核或大比例的浅色背景导致一种染色缺乏密度变化时。
在一种染色占主导地位的情况下,SPCN 会导致中间空白处出现颜色。
3. 无意的染色交换:得到的染色密度Hs在两种颜色基础W中交换。
由于两种染色中都存在显著的蓝色成分,SPCN显示出染色颜色基础的交换。
第二篇论文是改进了一些SPCN的缺点,并使用了GPU加速
具体操作如下:
1. 修改i0,取大于每个通道220像素的前100,000个,并取80%位置的值
2. SPCN是对每个patch独立处理,采用全部非白区域(小于220)的方差,并取非白区域的99%位置的值
3. SPCN使用蓝色通道的中值作为W,改进后利用红色和蓝色两个通道的差异来选选取W
4. 找最多20个非白区域代替整体,提升效率
5. 少量加速,纵向读patch
6. 使用所有patch 99%位置值的中位数
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # @File : SPCN.py
- # @Time : 2023/8/7
- # @Author : gzz
- # @Description : 提取染色参数
-
- import numpy as np
- import pickle
- from multiprocessing import Pool
- import spams
- import cv2
- import os
- import openslide
-
-
- def intensity_norm(img_array, p=None):
- """
- 亮度归一化,图片95%亮度位置拉伸到255
- :param img_array: 需要亮度拉伸的图片
- :param p: 拉伸阈值
- :return: 亮度拉伸后的图片
- """
- if p:
- img_array = np.clip(img_array * 255.0 / p, 0, 255).astype(np.uint8)
- else:
- p = np.percentile(img_array, 95)
- img_array = np.clip(img_array * 255.0 / p, 0, 255).astype(np.uint8)
-
- return img_array
-
-
- def getParameter(img, mask=None):
- V = getV(img, mask)
- W = getW(V)
- H = getH(V, W)
-
- return W, H
-
-
- def getV(img, mask=None):
- if mask is not None:
- V0 = img[mask == 255].T
- V0[V0 == 0] = 1
- V0 = np.log(255 / V0)
- else:
- I0 = img.reshape((-1, 3)).T
- I0[I0 == 0] = 1
- V0 = np.log(255 / I0)
-
- return V0
-
-
- def getW(V):
- W = spams.trainDL(np.asfortranarray(V), K=2, lambda1=0.01, iter=5000, mode=2,
- modeD=0, posAlpha=True, posD=True, verbose=False, numThreads=1)
- W = W / np.linalg.norm(W, axis=0)[None, :]
- if W[0, 0] < W[0, 1]:
- W = W[:, [1, 0]]
- return W
-
-
- def getH(V, W):
- H = spams.lasso(np.asfortranarray(V), np.asfortranarray(W), mode=2, lambda1=0.03, pos=True,
- verbose=False, numThreads=1).toarray()
- return H
-
-
-
- if __name__ == '__main__':
- img_ds32=cv2.imread(path)
- img_ds32 = cv2.cvtColor(img_ds32, cv2.COLOR_BGR2RGB)
- img_lashen = intensity_norm(img_ds32)
- Ws, Hs = getParameter(img_lashen)
GPU加速的代码 大家自己想想怎么改,我懒的写了,以后补上
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。