不管是无人机影像或者其它方式摄取的图像,由于光照,难免会存在阴影,笔者这篇文章介绍检测阴影一种简单的方式。
参考论文:
1、Damaged Building Detection in Aerial Images using Shadow Information
2、Linearized Vegetation Indices Based on aFormal Statistical Framework
主要原理:(以NDVI算法举一反三,ndvi(归一化植被指数)
NDVI=nir-red/(nir+red)
第一步:读入图像,通道分离,并对各通道中值滤波,滤波核大小可以不一样,自行调试。
第一步:计算如下值,注意的时,计算的时候一定要数据类型转换,将b和g的uint8 格式转为double 或者float ,否则计算的结果有问题!!!!!!
第二步:构造mask, 上式大于某一阈值的为1,反之为0,笔者这幅Image 用的0.2。
第三步:本来用matlab中bwareopen 这个函数,这个函数是移除指定面积大小小于某一个阈值的像素,因为在opencv中没有这个函数,要不然自己写,要不然继续去挖掘python 其它图像处理包,本人是懒人,所以在skimage 找的函数:
remove_small_objects。自己写的话,步骤如下:
1、二值化图像,找轮廓
2、筛选轮廓,轮廓面积小于某个阈值的,保存
3、将满足2的轮廓中像素值全部赋值0
# -*- coding: utf-8 -*-
import numpy as np
import cv2
from skimage.morphology import remove_small_objects
im1=cv2.imread(r'C:\Users\Y\Desktop\im1.jpg')
b,g,r=np.double(cv2.split(im1))
shadow_ratio = (4/np.pi)*np.arctan2((b-g),(b+g)) #mutiply 4/pi is to ensure value[0,1]
shadow_mask=shadow_ratio>0.2
#cv2.imshow("shadow_mask",np.uint8(shadow_mask*255))
shadow_mask[:5,:]=0
shadow_mask[-5:,:]=0
shadow_mask[:,:5]=0
shadow_mask[:,-5:]=0#边界上的值=0
#cv2.imshow("shadow_mask1",np.uint8(shadow_mask*255))
shadow_mask=remove_small_objects(shadow_mask, min_size=100, connectivity=3)
# opencv 中没有matlab 中类似bwareaopen的函数,二值图像面积开运算
cv2.imshow("shadow_mask1",np.uint8(shadow_mask*255))
kernel=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
kernel[1,0]=0
kernel[3,0]=0
kernel[1,4]=0
kernel[3,4]=0
shadow_mask1=np.uint8(shadow_mask*1)
mask=cv2.dilate(shadow_mask1,kernel)-shadow_mask1
#cv2.imshow("boundary",np.uint8(mask*255))
#substarct shadow_mask is to get boundary
#get boundary
[row,col]=np.where(mask==1)
#for i in range(len(row)-1):
# cv2.line(im1,(col[i],row[i]),(col[i+1],row[i+1]),(0,0,255),1)
im1[row,col,:]=im1[40,40,:]
cv2.imshow("original-shadow",im1)
cv2.waitKey(0)