1

背景

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

流域内正在考虑的特定区域

客观的

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

方法

通过 Python,我使用了 OpenCV 库中的各种工具和预构建函数。我在这种方法中使用的主要函数是 cv2.inpaint 函数。这个函数接收一个图像文件和一个掩码文件,并在掩码文件像素不为零的地方插入原始图像。

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

问题

我的问题是,这发生在各个方向,而我要求它仅从河流本身推断像素数据。下图显示了有缺陷的结果:inpaint 有效,但它也考虑了来自河外的数据。

修复结果

如果您愿意提供帮助,这是我的代码:

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()
4

0 回答 0