一、边缘检测BSDS500数据集处理
数据集下载下来以后label是以.m格式保存的,需要处理成.jpg或.png格式。
代码如下:
from scipy import io
import scipy
import imageio
import os
#读取mat文件中所有数据
#mat文件里面是以字典形式存储的数据
#包括 dict_keys(['__globals__', 'groundTruth', '__header__', '__version__'])
#我们要用到'groundTruth']中的轮廓
#x['groundTruth'][0][0][0][0][1]为轮廓
#x['groundTruth'][0][0][0][0][0]为分割图
def bsds_trans(root, num_anno):
PATH = os.path.join(root, 'data\\groundTruth')
for sub_dir_name in ['train','test','val']:
sub_pth = os.path.join(PATH,sub_dir_name)
##为生成的图片新建个文件夹保存
save_pth = os.path.join(root,'data\\GT_convert_{}'.format(num_anno),sub_dir_name)
os.makedirs(save_pth,exist_ok=True)
print('开始转换'+sub_dir_name+'文件夹中内容')
for index in range(len(os.listdir(sub_pth))):
filename = os.listdir(sub_pth)[index]
data = io.loadmat(os.path.join(sub_pth,filename))
try:
if len(data['groundTruth'][0]) < num_anno+1: raise IndexError
edge_data = data['groundTruth'][0][num_anno][0][0][1]
edge_data_255 = edge_data * 255
new_img_name = filename.split('.')[0]+'.jpg'
print(new_img_name)
imageio.imsave(os.path.join(save_pth,new_img_name), edge_data_255)
except IndexError:
index = min(len(os.listdir(sub_pth))-1, index+1)
filename = os.listdir(sub_pth)[index]
if __name__ == '__main__':
#运行时需要改变root值为BSD500所在的相应根目录
root = 'D:\\桌面\\bsds500\\BSR\\BSDS500'
#选取不同标注者标注的label,范围(0,5)
num_anno = 5
bsds_trans(root, num_anno)
说明:1.这个数据集并非一人标注完成,有好几个标注者,更改函数的num_anno参数就可以得到不同标注者标注的label。
二、PR曲线
PR曲线参数的核心Matlab代码
如下:
for k = 1:K
% threshhold and thin E
E1 = double(E>=max(eps,thrs(k)));
if(thin), E1=double(bwmorph(E1,'thin',inf)); end
% compare to each ground truth in turn and accumualte
Z=zeros(size(E)); matchE=Z; matchG=Z; allG=Z;
for g = 1:n
[matchE1,matchG1] = correspondPixels(E1,G{g},maxDist);
matchE = matchE | matchE1>0;
matchG = matchG + double(matchG1>0);
allG = allG + G{g};
end
% compute recall (summed over each gt image)
cntR(k) = sum(matchG(:)); sumR(k) = sum(allG(:));
% compute precision (edges can match any gt image)
cntP(k) = nnz(matchE); sumP(k) = nnz(E1);
% optinally create visualization of matches
if(nargout<6), continue; end; cs=[1 0 0; 0 .7 0; .7 .8 1]; cs=cs-1;
FP=E1-matchE; TP=matchE; FN=(allG-matchG)/n;
for g=1:3, V(:,:,g,k)=max(0,1+FN*cs(1,g)+TP*cs(2,g)+FP*cs(3,g)); end
V(:,2:end,:,k) = min(V(:,2:end,:,k),V(:,1:end-1,:,k));
V(2:end,:,:,k) = min(V(2:end,:,:,k),V(1:end-1,:,:,k));
end
E1:所有边缘图(手工标注的真值,共6个)二值化的结果(大于阈值的为1,反之为0)
matchE:预测正确的边缘为1,否则为0(预测为边缘的点,在6个真值中存在至少一个对应点为边缘),所以TP=matchE。也就是说预测的边缘点在6个真值中的对应点有一个为边缘,就算你预测的对
matchG:你预测的边缘点在真值中的对应点也为边缘的数量(0~6),也就是说,matchE是matchG二值化的结果(非0值设为1)
allG:真值中把该点预测为边缘的数量(0~6)
cntR: cntR(k) = sum(matchG( : )) 表示对matchG中所有元素求和(即预测正确的点数,若groundTruth有多个子边界图则要把所有子边界图中预测对的求和)
sumR: sumR(k) = sum(allG( : )) 表示对allG中所有元素求和(即所有子边界图中真实边缘点的个数)
cntP: cntP(k) = nnz(matchE) 表示对matchE统计非0元素的个数(预测结果中预测正确的像素数)(nnz表示Number of nonzero,统计非0元素的个数)
sumP: sumP(k) = nnz(E1) 表示对E1统计非0元素的个数(即总边界图中真实边缘点的个数)
最后获得的有用参数为:[thrs cntR sumR cntP sumP],每张图片会在有一个[id]_evl.txt文件与之对应。有99行,分别对应99个不同阈值和相应的cntR sumR cntP sumP值
参考文章
2.边缘检测评估指标