目录
背景
相比采用表格化数据定量分析,可视化是分割任务定性分析的主要手段。
在多类别图像分割任务中,往往会涉及两种及以上的颜色,一种常用的方法就是使用RGB色彩填充分割target。
最简单的实现方法就是两次for循环遍历图像,逐个像素进行填充,但这种方式耗时较长,采用np.where()等numpy高级函数可以有效加速,缩短程序运行时间。
方法
以腹部器官数据集Synapse为例,其中包含除去背景一类的8类器官(aorta、gallbladder、liver......),这种情况下,可视化就需要八种颜色来分别表示8类器官,所以先定义对应的颜色:
blue = [30,144,255] # aorta
green = [0,255,0] # gallbladder
red = [255,0,0] # left kidney
cyan = [0,255,255] # right kidney
pink = [255,0,255] # liver
yellow = [255,255,0] # pancreas
purple = [128,0,255] # spleen
orange = [255,128,0] # stomach
这里选取了几种对比较为鲜明的颜色。
接下来需要处理一下原始图像以及预测结果,一般来说作为模型的输入,原始图像一般会经过归一化操作,所以乘以255恢复原始像素值,在转换为uint8格式以使用opencv处理。此外,原始图像若是灰度图还需转换为3通道的RGB格式。分割结果默认是非one-hot的一维格式(通过torch.argmax转换得到),所以也需要转换为RGB三维格式:
original_img = original_img * 255.0
original_img = original_img.astype(np.uint8)
original_img = cv2.cvtColor(original_img,cv2.COLOR_GRAY2BGR)
pred = cv2.cvtColor(pred,cv2.COLOR_GRAY2BGR)
接下来是核心部分,以其中一类为例:
original_img = np.where(pred==1, np.full_like(original_img, blue), original_img)
np.where(condition, x, y) 函数定义如下:满足条件(condition),输出x,不满足输出y,具体可参考点击跳转。此处的条件是判断预测结果的某一像素点是否为"1"类别,若是则使用定义好的"blue"RGB值填充(np.full_like的作用是创建一个等于原图大小的全蓝色图像,多余的蓝色区域可以被pred掩膜过滤掉),若不是则输出原始图像的像素值。分别对8类处理完后保存即可,最终可视化结果如图(左:原图,右:分割结果):
完整代码如下,输入分别为原图,预测结果,可视化结果保存路径:
def vis_save(original_img, pred, save_path):
blue = [30,144,255] # aorta
green = [0,255,0] # gallbladder
red = [255,0,0] # left kidney
cyan = [0,255,255] # right kidney
pink = [255,0,255] # liver
yellow = [255,255,0] # pancreas
purple = [128,0,255] # spleen
orange = [255,128,0] # stomach
original_img = original_img * 255.0
original_img = original_img.astype(np.uint8)
original_img = cv2.cvtColor(original_img,cv2.COLOR_GRAY2BGR)
pred = cv2.cvtColor(pred,cv2.COLOR_GRAY2BGR)
original_img = np.where(pred==1, np.full_like(original_img, blue ), original_img)
original_img = np.where(pred==2, np.full_like(original_img, green ), original_img)
original_img = np.where(pred==3, np.full_like(original_img, red ), original_img)
original_img = np.where(pred==4, np.full_like(original_img, cyan ), original_img)
original_img = np.where(pred==5, np.full_like(original_img, pink ), original_img)
original_img = np.where(pred==6, np.full_like(original_img, yellow), original_img)
original_img = np.where(pred==7, np.full_like(original_img, purple), original_img)
original_img = np.where(pred==8, np.full_like(original_img, orange), original_img)
original_img = cv2.cvtColor(original_img,cv2.COLOR_BGR2RGB)
cv2.imwrite(save_path, original_img)
实测结果表明,使用np.where()函数实现可比双for循环遍历快6倍左右。
Original: https://blog.csdn.net/qq_40475568/article/details/122012164
Author: McGregorWwww
Title: 【图像分割】使用np.where()实现多类别图像分割可视化
相关阅读1
Title: 19.高通滤波
上一节为低通滤波,最主要的作用是去噪
高斯滤波去除高斯噪声
中值滤波去除椒盐噪声
双边噪声用于美颜
高通滤波最主要的作用是用于检测边缘
常见的高通滤波:
- Sobel(索贝尔)(高斯),对噪声适应性强,很多算法均以索贝尔卷积核为基础
- Scharr(沙尔), 卷积核不会改变,3*3大小,如果Sobel(索贝尔)的size设为-1,则自动使用的则为沙尔滤波,所以一般情况下均使用索贝尔算法。
对于3*3的卷积核,Sobel(索贝尔)没有Scharr(沙尔)好,因为Scharr(沙尔)可以检测出更细的边缘线。Sobel(索贝尔)比较粗糙
缺点:计算边缘时,只能求一个方向,要么是横轴,要么是纵轴,最后再相加的出最终结果
- Laplacian(拉普拉斯),优点不需要单独求x或y的边缘,可以直接将横轴和纵轴的边缘全部检测出来。
缺点:对噪声比较敏感,在其内部没有降噪的功能,因此在使用前,需要进行降噪处理。
Sobel算子
- 先对X方向求导
- 再对Y方向求导
- 最终结果进行累加
- 注:不能两个方向同时求
Sobel API
Sobel(src, ddepth, dx, dy, ksize = 3,scale = 1,delte = 0,borderType = BORDER_DEFAULT)
ddepth 输出的位深,64位或32位
卷积核大小默认为3,可以改为5,7,若为-1则变为为沙尔算法
import cv2
import numpy as np
img = cv2.imread('E:\\112.png')
#索贝尔算子Y方向边缘
dst1 = cv2.Sobel(img,cv2.CV_64F,1,0)
#索贝尔算子X方向边缘
dst2 = cv2.Sobel(img,cv2.CV_64F,0,1)
#两个方向进行合并
dst3 = dst1 + dst2
#dst3 = cv2.add(d1,d2) 这种方法效率更高
cv2.imshow('img',img)
cv2.imshow('dst1',dst1)
cv2.imshow('dst2',dst2)
cv2.imshow('dst3',dst3)
cv2.waitKey(0)
Scharr(沙尔)算子
与Sobel类似,只不过使用的kernel值不同,只支持3*3的卷积核
Scharr(沙尔)只能求x方向或y方向的边缘,重点还是索贝尔算子
简单修改即为沙尔算子,沙尔可以检测出更小的边缘
拉普拉斯算子
- 可以同时求两个方向的边缘
- 缺点:对噪声比较敏感,一般需要先进行去噪再调用拉普拉斯算子
对应API
Laplacian(img, ddepth, ksize =1, scale = 1,borderType = BORDER_DEFAULT)
#拉普拉斯算子
dst4 = cv2.Laplacian(img, cv2.CV_64F,ksize=5)
cv2.imshow('dst4',dst4)
cv2.waitKey(0)
边缘检测 Canny
边缘检测效果最好,主要有以下步骤
- 使用5*5高斯滤波消除噪声
- 计算图像梯度的方向(0°/45°/90°/135°)共四个方向
- 在四个方向上取局部最大值
- 取出最大值后进行阈值计算
AC是边缘,B不是边缘,小于阈值不认为是边缘,大于阈值认为是边缘
Canny API
重要的是前3个参数
Canny(img, minVAL, maxVal,....)
import cv2
import numpy as np
img = cv2.imread('E:\\112.png')
dst = cv2.Canny(img,100,200)
cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.waitKey(0)
具体的边缘跟设定的阈值有关
Original: https://blog.csdn.net/qq_45355603/article/details/125261353
Author: 稚子
Title: 19.高通滤波
相关阅读2
Title: arm64/x64/x86/macos安装tensorflow c语言版本
请认真阅读以下内容:
本人应该把能踩过的坑全部都踩了(2days)
我把所有坑和解决方案都记录下来(纯文字)
建议先看完某一个大步骤以及了解踩坑原因再执行对应的命令能够有效避免踩坑
本文包括:
(1)官方编译好的动态库(x86,x64)以及我编译好的动态库(arm64)
(2)安装树莓派64位系统
(3)安装bazel(编译tensorflow工具):脚本和编译两个方式
(4)安装tensorflow:编译和直接下载使用两个方式
直接下载(推荐方式):
x86和x64可以直接下载官方编译好的动态链接库,然后跳到安装tensorflow编译完成:
Linux(仅支持 CPU) https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-linux-x86_64-2.6.0.tar.gz
Linux(支持 GPU) https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-gpu-linux-x86_64-2.6.0.tar.gz
macOS(仅支持 CPU) https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-darwin-x86_64-2.6.0.tar.gz
Windows(仅支持 CPU) https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-windows-x86_64-2.6.0.zip
Windows(仅支持 GPU) https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-gpu-windows-x86_64-2.6.0.zip
我编译的树莓派arm64版本:
下载完直接跳到安装步骤
编译安装(不建议方式):
观前提醒(背景):
1.
编译过程十分漫长,你可能需要一天的时间来搞,建议看剧消磨时间
影视推荐:猎魔人,纸牌屋,洛基
2.
如果想要尝试,建议树莓派4B(64位)配置:4G内存+32Gtf卡
编译过程十分耗资源,当然,内存2G应该也行,就是要慢一点(我会有提示,请注意)
我就是4+32,,重装了树莓派64位系统后直接下载编译tensorflow过程中
tf卡占用如下:
Filesystem Size Used Avail Use% Mounted on
/dev/root 29G 14G 15G 49% /
devtmpfs 1.7G 0 1.7G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 1.9G 492K 1.9G 1% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/mmcblk0p1 253M 30M 223M 12% /boot
tmpfs 380M 0 380M 0% /run/user/1000
编译时某一时刻内存占用如下:
total used free shared buff/cache available
Mem: 3.7Gi 3.6Gi 34Mi 0.0Ki 104Mi 63Mi
Swap: 4.0Gi 933Mi 3.1Gi
以及
total used free shared buff/cache available
Mem: 3.7Gi 3.5Gi 43Mi 0.0Ki 137Mi 105Mi
Swap: 4.0Gi 1.1Gi 2.9Gi
大部分时候内存占用基本情况(具有一定代表性):
total used free shared buff/cache available
Mem: 3.7Gi 1.9Gi 1.6Gi 0.0Ki 263Mi 1.8Gi
Swap: 4.0Gi 597Mi 3.4Gi
以及
total used free shared buff/cache available
Mem: 3.7Gi 2.7Gi 786Mi 0.0Ki 215Mi 925Mi
Swap: 4.0Gi 420Mi 3.6Gi
3.
我的环境:
- 系统64位,没超频
- 内核:Linux raspberrypi 5.10.63-v8+ #1496 SMP PREEMPT Wed Dec 1 15:59:46 GMT 2021 aarch64 GNU/Linux
- 硬件 :4+32
Original: https://blog.csdn.net/qq_44113911/article/details/122603588
Author: 在退学边缘疯狂试探
Title: arm64/x64/x86/macos安装tensorflow c语言版本
相关阅读3
Title: TensorFlow读书笔记
1.TensorFlow基础知识:
Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算.数据流图中的图就是我们所说的有向图,我们知道,在图这种数据结构中包含两种基本元素:节点和边.这两种元素在数据流图中有自己各自的作用.节点用来表示要进行的数学操作,另外,任何一种操作都有输入/输出,因此它也可以表示数据的输入的起点/输出的终点.边表示节点与节点之间的输入/输出关系,一种特殊类型的数据沿着这些边传递.这种特殊类型的数据在TensorFlow被称之为tensor,即张量,所谓的张量通俗点说就是多维数组.当我们向这种图中输入张量后,节点所代表的操作就会被分配到计算设备完成计算.
TensorFlowd的四个特性:
灵活性
可移植性
多语言支持
高效性
Graph:要组装的结构,由许多操作组成,其中的每个连接点代表一种操作
op:接受(流入)零个或多个输入(液体),返回(流出)零个或多个输出
2.实验:
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt
fashion_mnist=keras.datasets.fashion_mnist
(train_images,train_labels),(test_images,test_labels)=fashion_mnist.load_data()
class_names=['T-shirt/top','Trouser','Pullover','Dress','Coat','Sandal','Shirt','Sneaker','Bag','Ankle boot']
train_labels
train_images.shape
len(train_labels)
test_images.shape
len(test_labels)
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()
train_images=train_images/255.0
test_images=test_images/255.0
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i],cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
plt.show()
model=keras.Sequential([
keras.layers.Flatten(input_shape=(28,28)),
keras.layers.Dense(128,activation='relu'),
keras.layers.Dense(10)])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(train_images,train_labels,epochs=10)
test_loss,test_acc=model.evaluate(test_images,test_labels,verbose=2)
print('\nTest accuracy:',test_acc)
probability_model=tf.keras.Sequential([model,
tf.keras.layers.Softmax()])
predictions=probability_model.predict(test_images)
predictions[0]
np.argmax(predictions[0])
test_labels[0]
def plot_image(i,predictions_array,true_label,img):
predictions_array, true_label, img=predictions_array, true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array, true_label[i]
plt.grid(False)
plt.xticks(range(10))
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)
thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i,predictions[i],test_labels)
plt.show()
Plot the first X test images, their predicted labels, and the true labels.
Color correct predictions in blue and incorrect predictions in red.
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
plt.subplot(num_rows,2*num_cols,2*i+1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()
#测试部分
img=test_images[1]
print(img.shape)
img=(np.expand_dims(img,0))
print(img.shape)
predictions_single=probability_model.predict(img)
print(predictions_single)
plot_value_array(1,predictions_single[0],test_labels)
_ =plt.xticks(range(10),class_names,rotation=45)
np.argmax(predictions_single[0])
课后习题:
(1)局部连接:层间神经只有局部范围内的连接,在这个范围内采用全连接的方式,超过这个范围的神经元则没有连接;连接与连接之间独立参数,相比于去全连接减少了感受域外的连接,有效减少参数规模。
全连接:层间神经元完全连接,每个输出神经元可以获取到所有神经元的信息,有利于信息汇总,常置于网络末尾;连接与连接之间独立参数,大量的连接大大增加模型的参数规模。
(2)卷积运算原理,最基本的就是单通道对应一个输出通道,那就用一个二维矩阵对输入图像进行运算,提取图像特征。但是单通道输入得到多通道(k个通道)输出,就需要k个滤波器,每个滤波器是就是一个二维的33矩阵,也就是每个滤波器包含一个卷积核。但是当输入是多通道(t)得到多通道(k个通道)输出,那这次卷积就包括k个滤波器,每个滤波器就是一个3维矩阵,33t,每个滤波器就包含t个卷积核。上面输出通道是k,那就得到了k个特征图,每个输出通道就是一个特征图。
(3)池化的目的:对输入的特征图进行压缩,一方面使特征图变小,简化网络计算复杂度;一方面进行特征压缩,提取主要特征。
激活函数的作用:如果不用激励函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合。如果使用的话,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。
(4).归一化有助于快速收敛;. 2.对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。
(5)寻找损失函数的最低点,就像我们在山谷里行走,希望找到山谷里最低的地方。那么如何寻找损失函数的最低点呢?在这里,我们使用了微积分里导数,通过求出函数导数的值,从而找到函数下降的方向或者是最低点(极值点)。损失函数里一般有两种参数,一种是控输入信号量的权重,另一种是调整函数与真实值距离的偏差。我们所要做的工作,就是通过梯度下降方法,不断地调整权重 和偏差b,使得损失函数的值变得越来越小。
Original: https://blog.csdn.net/weixin_58565789/article/details/124389375
Author: weixin_58565789
Title: TensorFlow读书笔记