目标:
- 将多分类的mask中的细胞核与细胞质分别提取并将背景二值化
- 生成灰度直方图
- 根据灰度直方图拟合曲线找到峰谷值,分段计算占比核质的比例
材料:
-
淋巴细胞原图img -
淋巴细胞图对应的mask
代码实现
- 背景纯黑
import os
import cv2
import numpy as np
def add_mask2image_binary(images_path, masks_path, masked_path):
for img_item in os.listdir(images_path):
print(img_item)
img_path = os.path.join(images_path, img_item)
img = cv2.imread(img_path)
mask_path = os.path.join(masks_path, img_item[:-4]+'.png')
mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
masked = cv2.add(img, np.zeros(np.shape(img), dtype=np.uint8), mask=mask)
cv2.imwrite(os.path.join(masked_path, img_item), masked)
images_path = '20220116/img/'
masks_path = '20220116/img_out'
masked_path = '20220302/BlackBG/'
add_mask2image_binary(images_path, masks_path, masked_path)
效果 但没有实现核质分离,但是通过mask的灰度去手动获得核与质的灰度,即可分别得到核质与全黑背景
import os
import cv2
import numpy as np
def add_mask2image_binary(images_path, masks_path, masked1_path, masked2_path):
for img_item in os.listdir(images_path):
print(img_item)
img_path = os.path.join(images_path, img_item)
img = cv2.imread(img_path)
mask_path = os.path.join(masks_path, img_item[:-4]+'.png')
mask = cv2.imread(mask_path, 0)
upper1 = mask <= 80
lower1= mask >= 70
thresh1 = (np.multiply(upper1,lower1).astype(np.float32)*255).astype(np.uint8)
masked1 = cv2.add(img, np.zeros(np.shape(img), dtype=np.uint8), mask = thresh1)
upper2 = mask <= 40
lower2 = mask >= 30
thresh2 = (np.multiply(upper2,lower2).astype(np.float32)*255).astype(np.uint8)
masked2 = cv2.add(img, np.zeros(np.shape(img), dtype=np.uint8), mask = thresh2)
cv2.imwrite(os.path.join(masked1_path, img_item), masked1)
cv2.imwrite(os.path.join(masked2_path, img_item), masked2)
images_path = '20220116/img/'
masks_path = '20220116/img_out'
masked1_path = '20220302/test/1'
masked2_path = '20220302/test/2'
add_mask2image_binary(images_path, masks_path, masked1_path, masked2_path)
可视化
使用opencv的colormap函数将灰度转换成伪彩图
import cv2, csv, os
import numpy as np
imgsrc = '20220302/test/1/'
out_dir = '20220302/test/'
img_lst = []
filelist = os.listdir(imgsrc)
evaluate = []
for file in filelist:
filename = os.path.splitext(file)[0]
img = cv2.imread(imgsrc + '{}.jpg'.format(filename), 0)
img_color = cv2.applyColorMap(img, cv2.COLORMAP_JET)
theme = 'jet'
cv2.imwrite(out_dir + '{}/{}.png'.format(theme,filename), img_color)
means, dev = cv2.meanStdDev(img)
print('means: {} \n dev: {}'.format(means[0,0], dev[0,0]))
hist = cv2.calcHist([img],[0],None,[256],[0,255])
means_25 ,devs_25 = 0, 0
for x in range(0,64):
means_25 += hist[x][0]
devs_25 += hist[x][0]**2
mean_25 = means_25/64
dev_25 = devs_25/64-mean_25**2
print(mean_25, dev_25)
means_50 ,devs_50 = 0, 0
for x in range(0,128):
means_50 += hist[x][0]
devs_50 += hist[x][0]**2
mean_50 = means_50/128
dev_50 = devs_50/128-mean_50**2
print(mean_50, dev_50)
means_75 ,devs_75 = 0, 0
for x in range(0,192):
means_75 += hist[x][0]
devs_75 += hist[x][0]**2
mean_75 = means_75/192
dev_75 = devs_75/192-mean_75**2
print(mean_75, dev_75)
evaluate.append((mean_25, mean_50, mean_75, means[0,0], dev_25, dev_50, dev_75, dev[0,0]))
header1 = ['means', '', '', '', 'dev' , '', '', '']
header2 = ['25%', '50%', '75%', '100%']
with open(out_dir + '{}/{}.csv'.format(theme, theme),'w') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(header1)
writer.writerow(header2*2)
writer.writerows(evaluate)
核质分离计算占比面积
多项式拟合灰度曲线,利用倒数来确定曲线的极值点。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal
import cv2
from lmfit import Model
imgsrc = 'test/bd/Snipaste_2022-03-07_12-16-36.png'
img = cv2.imread(imgsrc, 0)
rows,cols = img.shape
hist = cv2.calcHist([img],[0],None,[256],[0,255])
CellArea = rows * cols - hist[0][0]
y = []
for value in hist:
y.append(int(value[0]))
y.pop(0)
y.pop(0)
x = np.arange(0, 254, 1)
n = 7
z1 = np.polyfit(x, y, n)
p1 = np.poly1d(z1)
yd = np.polyder(p1,1)
d = []
for i in yd.r:
d.insert(0, np.round(i))
print(d)
print(y[0], hist[0], hist[1])
yvals=p1(x)
plt.plot(x, y, '.',label='original values')
plt.plot(x, yvals, 'r',label='polyfit values')
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.legend(loc=4)
plt.title('polyfitting {}'.format(n))
plt.show()
输出的极值点的横轴值
[23.0, 89.0, 115.0, 175.0, 214.0, 242.0]
添加一下代码计算分段区间占比 步骤:
- 拟合曲线找到极值点
- 取两极值点x轴的中点
- 统计各区段像素个数
- 计算占比大小
x_subsection = []
x_subsection.append(round(d[0]/2))
for d1 in range(0, len(d) - 1, 1):
x_subsection.append(round((d[d1] + d[d1+1])/2))
print(x_subsection)
SegmentPixelStatistics= []
for w in range(0, len(x_subsection) - 1, 1):
SegmentPixel = 0
for q in range(x_subsection[w], x_subsection[w+1]):
SegmentPixel += int(hist[q])
SegmentPixelStatistics.append(SegmentPixel)
print(SegmentPixelStatistics)
proportion = []
for p in SegmentPixelStatistics:
q = float(p/CellArea)
b = "%.2f%%" % (q * 100)
proportion.append(b)
print(proportion)
section = []
for s1 in range(len(x_subsection) - 1):
section.append('{}-{}'.format(x_subsection[s1], x_subsection[s1+1]))
single_dic = dict(zip(section, proportion))
print(single_dic)
plt.figure()
yvals=p1(x)
plt.plot(x, y, '.',label='original values')
plt.plot(x, yvals, 'r',label='polyfit values')
plt.xlabel('x axis')
plt.ylabel('y axis')
plt.legend(loc=4)
plt.title('{} polyfitting {}'.format(filename, n))
plt.show()
with open(out_dir + 'nucleus.csv','a') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([filelist[num],'','','',''])
writer.writerow(section)
writer.writerow(proportion)
num += 1
|