通过Python在OpenCV中使用inpaint函数在流域中插入破碎的河流数据

时间:2016-07-02 20:48:10

标签: python opencv mask raster watershed

背景

通过LIDAR收集的栅格文件记录了分水岭的地形。为了对流域进行正确建模,河流必须连续出现,没有任何中断或中断。光栅文件中的道路看起来像是打断河流的水坝,如下图所示

Specific Area Under Consideration in the Watershed

目的

这些河流断裂是主要问题,我正在尝试但未能将它们移除。

方法

通过Python,我使用了OpenCV库中的各种工具和预构建函数。我在这种方法中使用的主要功能是cv2.inpaint函数。此功能采用图像文件蒙版文件,并在蒙版文件像素非零的任何位置插入原始图像。

这里的主要步骤是通过检测河中断处的角来确定我所做的掩模文件。掩模文件将引导inpaint函数根据周围像素中的图案填充像素。

问题

我的问题是,这种情况发生在所有方向,而我要求它只是从河流本身推断出像素数据。下面的图片显示了有缺陷的结果:inpaint工作,但它也考虑了来自河外的数据。

Inpainted Result

如果您非常友好,可以使用以下代码:

import scipy.io as sio
import numpy as np
from matplotlib import pyplot as plt
import cv2

matfile = sio.loadmat('box.mat') ## box.mat original raster file linked below
ztopo = matfile['box']

#Crop smaller section for analysis
ztopo2 = ztopo[200:500, 1400:1700]


## Step 1) Isolate river
river = ztopo2.copy()
river[ztopo2<217.5] = 0
#This will become problematic for entire watershed w/o proper slicing


## Step 2) Detect Corners
dst = cv2.cornerHarris(river,3,7,0.04)
# cornerHarris arguments adjust qualities of corner markers

# Dilate Image (unnecessary)
#dst = cv2.dilate(dst,None)  

# Threshold for an optimal value, it may vary depending on the image.
# This adjusts what defines a corner
river2 = river.copy()
river2[dst>0.01*dst.max()]=[150]


## Step 3) Remove river and keep corners

#Initiate loop to isolate detected corners
i=0
j=0
rows,columns = river2.shape
for i in np.arange(rows):
    for j in np.arange(columns):
        if river2[i,j] != 150:
            river2[i,j] = 0
        j = j + 1
    i = i + 1

# Save corners as new image for import during next step.
# Import must be via cv2 as thresholding and contour detection can only work on BGR files. Sio import in line 6 (matfile = sio.loadmat('box.mat')) imports 1 dimensional image rather than BGR.
cv2.imwrite('corners.png', river2)


## Step 4) Create mask image by defining and filling a contour around the previously detected corners

#Step 4 code retrieved from http://dsp.stackexchange.com/questions/2564/opencv-c-connect-nearby-contours-based-on-distance-between-them
#Article: OpenCV/C++ connect nearby contours based on distance between them

#Initiate function to specify features of contour connections
def find_if_close(cnt1,cnt2):
    row1,row2 = cnt1.shape[0],cnt2.shape[0]
    for i in xrange(row1):
        for j in xrange(row2):
            dist = np.linalg.norm(cnt1[i]-cnt2[j])
            if abs(dist) < 50 :
                return True
            elif i==row1-1 and j==row2-1:
                return False

#import image of corners created in step 3 so thresholding can function properly
img = cv2.imread('corners.png')

#Thresholding and Finding contours only works on grayscale image
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hier = cv2.findContours(thresh,cv2.RETR_EXTERNAL,2)

LENGTH = len(contours)
status = np.zeros((LENGTH,1))

for i,cnt1 in enumerate(contours):
    x = i    
    if i != LENGTH-1:
        for j,cnt2 in enumerate(contours[i+1:]):
            x = x+1
            dist = find_if_close(cnt1,cnt2)
            if dist == True:
                val = min(status[i],status[x])
                status[x] = status[i] = val
            else:
                if status[x]==status[i]:
                    status[x] = i+1

unified = []
maximum = int(status.max())+1
for i in xrange(maximum):
    pos = np.where(status==i)[0]
    if pos.size != 0:
        cont = np.vstack(contours[i] for i in pos)
        hull = cv2.convexHull(cont) # I don't know why/how this is used
        unified.append(hull)


cv2.drawContours(img,unified,-1,(0,255,0),1) #Last argument specifies contour width
cv2.drawContours(thresh,unified,-1,255,-1)

# Thresh is the filled contour while img is the contour itself
# The contour surrounds the corners

#cv2.imshow('pic', thresh) #Produces black and white image


## Step 5) Merge via inpaint
river = np.uint8(river)
ztopo2 = np.uint8(ztopo2)

thresh[thresh>0] = 1
#new = river.copy()
merged = cv2.inpaint(river,thresh,12,cv2.INPAINT_TELEA)

plt.imshow(merged)
plt.colorbar()
plt.show()

0 个答案:

没有答案