HY_King队 初赛排名:17/1149 复赛排名:15/30
赛题为检测并定位图像中的篡改痕迹,图像中的篡改类型分为马赛克、copy-move、remove、splcing等。鉴于本题仅将所有的篡改类型归为一类,最终只输出关于篡改区域的mask,因此我们将本题简单定义为一个对像素的二分类问题,我们将本题当作语义分割问题来做。
参考上次比赛相关讨论,由于是第一次做此类型比赛,就延续使用上次比赛参赛团队的方法以及开源Baseline,我们的使用model训练的框架是在去年Rank3的团队代码上修改的。
实验上分记录:
推理过程分为以下4步:
分割代码
def decompose(data_path):
path = data_path
flist = sorted(os.listdir(path))
size_list = [896]
path_out = 'output_dir'
for size in size_list:
rm_and_make_dir(path_out%size)
rtn_list = [[], [], [], []]
for file in tqdm(flist):
img = cv2.imread(path + file)
H, W, _ = img.shape
size_idx= 0
while size_idx <len(size_list)-1:
if H<size_list[size_idx+1] or W < size_list[size_idx+1]:
break
size_idx += 1
rtn_list[size_idx].append(file)
size = size_list[size_idx]
X, Y = H // size + 1, W // size + 1
idx = 0
for x in range(X-1):
for y in range(Y-1):
img_tmp = img[x * size: (x + 1) * size, y * size: (y + 1) * size, :]
img,msk = copy_move_offline
cv2.imwrite(path_out%size + file[:-4] + '_%03d.png' % idx, img_tmp)
idx += 1
img_tmp = img[x * size: (x + 1) * size, -size:, :]
cv2.imwrite(path_out%size + file[:-4] + '_%03d.png' % idx, img_tmp)
idx += 1
for y in range(Y - 1):
img_tmp = img[-size:, y * size: (y + 1) * size, :]
cv2.imwrite(path_out%size + file[:-4] + '_%03d.png' % idx, img_tmp)
idx += 1
img_tmp = img[-size:, -size:, :]
cv2.imwrite(path_out%size + file[:-4] + '_%03d.png' % idx, img_tmp)
idx += 1
def output(model,input,ori_size,size=512):
img = cv2.resize(input, (size, size))
input = transform(img).unsqueeze(0).cuda()
Mo = model(input)
Mo = Mo * 255.
Mo = Mo.permute(0, 2, 3, 1).cpu().detach().numpy()[0]
Mo = cv2.resize(Mo.astype(np.float32), (ori_size[1], ori_size[0]))
return Mo
with torch.no_grad():
for f_name in model_folders:
print("Loading %s"%f_name)
load_weight(model_path+f_name,model)
save_path = save_decompose_path+f_name+'/'
for img_name in tqdm(test_paths[:]): # test
img = cv2.imread(test_path+img_name)[:,:,::-1]
ori_size = img.shape
masks = []
Mo = output(model, img, ori_size,size)
Mo[Mo < 100] = 0
Mo[Mo >= 100] = 255
save_single_path = os.path.join(save_path,os.path.split(img_name)[-1].split('.')[0] + '.png')
os.makedirs(os.path.split(save_single_path)[0], exist_ok=True)
cv2.imwrite(save_single_path, Mo.astype(np.uint8))
merge(save_path,[size])
# 在上面输出目录中直接merge,同时删除分割图像
def merge(path,size_list):
test_path = 'data/test/'
# rm_and_make_dir(path)
val_lists =os.listdir(test_path)
for file in tqdm(val_lists):
img = cv2.imread(test_path + file)
H, W, _ = img.shape
size_idx =0
while size_idx <len(size_list)-1:
if H<size_list[size_idx+1] or W < size_list[size_idx+1]:
break
size_idx += 1
size = size_list[size_idx]
X, Y = H // size + 1, W // size + 1
idx = 0
rtn = np.zeros((H, W, 3), dtype=np.uint8)
for x in range(X-1):
for y in range(Y-1):
img_tmp = cv2.imread(path + file[:-4] + '_%03d.png' % idx)
os.remove(path + file[:-4] + '_%03d.png' % idx)
rtn[x * size: (x + 1) * size, y * size: (y + 1) * size, :] += img_tmp
idx += 1
img_tmp = cv2.imread(path + file[:-4] + '_%03d.png' % idx)
os.remove(path + file[:-4] + '_%03d.png' % idx)
rtn[x * size: (x + 1) * size, -size:, :] += img_tmp
idx += 1
for y in range(Y - 1):
img_tmp = cv2.imread(path + file[:-4] + '_%03d.png' % idx)
os.remove(path + file[:-4] + '_%03d.png' % idx)
rtn[-size:, y * size: (y + 1) * size, :] += img_tmp
idx += 1
img_tmp = cv2.imread(path + file[:-4] + '_%03d.png' % idx)
os.remove(path + file[:-4] + '_%03d.png' % idx)
rtn[-size:, -size:, :] += img_tmp
idx += 1
# 因为是uint8类型,这里做个判断
rtn[rtn>=200]=255
cv2.imwrite(path + file[:-4] + '.png', rtn)
投票代码:
def vote(save_path,model_folders,test_img):
masks=[]
#不同model输出的保存在save_path下
for name in model_folders:
mask = cv2.imread(os.path.join(save_decompose_path, name, test_img))
mask[mask >= 100] = 255
mask[mask < 100] = 0
masks.append(mask)
mask = np.zeros_like(mask,dtype=np.uint8)
for m in masks:
mask = mask+m/255
return mask
mask[mask >= 3] = 255 # 投票>=3 选中
mask[mask < 3] = 0
由于复赛阶段一时想不到什么上分策略了,就在已训练好的方案上为finetune,分数也是不升反降…最终排名15。
参考rank1和rank5的大佬,再反观自己的方法,感觉在每一步上都差了,那么在一些方法上继续推进就跑过去试其他的方。第一次尝试图像分割类比赛,经验还是很欠缺的,学到就是赚到。
数据选择对比(增强手段):
loss选择对比:我们在比赛过程中也考虑到了正负样本不均衡问题,就加入了focal loss(第一次用,不知道用的对与否),而两团队都采用了lovasz-loss(据说这是kaggle一个神器),自动平衡训练过程中样本权重,保证对每张图片的正样本都有足够的学习能力。
训练过程对比:两团队都采用了预训练过程,都是逐步训练
推理过程对比:rank1团队通过mmseg的slide推理模式(具体是什么还是要了解一下mmseg这个框架),rank5团队采用了大尺度推理(甚至达到到了1536推理,我们团队最高得分是在869,没有试过1024或者更高)。
Rank 1经验分享:https://github.com/CarnoZhao/mmsegmentation/tree/tianchi_tamper
Rank 5经验分享:https://mp.weixin.qq.com/s/zsKE1sz8gqtzmwsP4CZGkg