从图像中提取矢量线段

问题描述 投票:0回答:1

我正在尝试寻找卫星图像的边缘。虽然我尝试使用精明的边缘检测,但通过将图像传递给结构化随机森林模型,我发现了更好的结果,从而产生了下面的灰度图像。

问题是我需要一个线向量作为最终输出(geojson、shp 等)。我找到了这个工具:https://pypi.org/project/ridge-detection/。它似乎给出了我想要的结果,但到目前为止,我只能获得图像作为带有红线的输出,我试图提取嵌入图像中的红线。附件是我尝试使用脊检测包获取结果的代码。该包的结果作为第二张图片附在后面。

那么有没有办法从灰度图像中提取线条信息作为向量段呢?

image_path = "/content/drive/MyDrive/Edges_Test_Landsat.jpg"

from IPython.display import Image, display
import matplotlib.pyplot as plt
from ridge_detection.lineDetector import LineDetector
from ridge_detection.params import Params
from ridge_detection.helper import displayContours, save_to_disk
from datetime import datetime
from PIL import Image
from mrcfile import open as mrcfile_open


# Parameters for using the ridge-detection package
params_dict = {
    "path_to_file": image_path,
    "mandatory_parameters": {
        "Sigma": 3.39,
        "Lower_Threshold": 0.5,
        "Upper_Threshold": 1.02,
        "Maximum_Line_Length": 0,
        "Minimum_Line_Length": 150,
        "Darkline": "LIGHT",
        "Overlap_resolution": "NONE"
    },
    "optional_parameters": {
        "Line_width": 10.0,
        "High_contrast": 200,
        "Low_contrast": 80
    },
    "further_options": {
        "Correct_position": True,
        "Estimate_width": True,
        "doExtendLine": True,
        "Show_junction_points": False,
        "Show_IDs": False,
        "Display_results": False,
        "Preview": False,
        "Make_Binary": True,
        "save_on_disk": False
    }
}
params = Params(params_dict)
try:
    img = mrcfile_open(params_dict["path_to_file"]).data
except ValueError:
    img = Image.open(params_dict["path_to_file"])

# Create LineDetector instance
detect = LineDetector(params=params)

# Run ridge detection on the image
result = detect.detectLines(img)
resultJunction = detect.junctions

# Display contours (I think this is where it's taking the line segments and attaching them back into an image)
out_img, img_only_lines = displayContours(params, result, resultJunction)

#Plot the display
plt.figure(figsize=(15, 15))
plt.imshow(img_only_lines)
plt.axis('off')
plt.title('Detected Lines')
plt.show()

python image-processing gis vector-graphics edge-detection
1个回答
0
投票

正如我在评论中提到的,Rahm-Puecker-Douglas 算法可能会在您的工作中发挥作用。 Rahm-Puecker-Douglas 采用一系列点(又称分段线性曲线、折线等)并简化它们。该算法的维基百科条目有一个漂亮的动画图形,显示了算法的工作>

https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm

对于可能超过一个像素宽的山脊,或者对于蜿蜒的像素串,您可能需要执行如下操作:

  1. 使用形态学操作(例如变形接近)来确保相邻边缘/脊像素连接,但不增加脊的厚度。
  2. 扫描图像中超过一定边缘强度的边缘像素。如果您想单独使用红色像素,请查找 RGB 颜色值的红色分量超过阈值(例如红色 > 8)的像素。当您找到边缘像素时,将其设计为“种子”并进入下一步。
  3. 使用边缘跟踪算法将其他边缘像素与种子像素相关联。 (也许类似于这里的内容:https://homepages.inf.ed.ac.uk/rbf/BOOKS/BANDB/LIB/bandb4_4.pdf
  4. 将边缘像素添加到与种子像素相同的序列时,将这些像素标记为已访问过。然后,在搜索图像中的下一个种子像素时,您的算法将不会重新访问已经访问过的像素。
  5. 运行 Rahm-Puecker-Douglas 算法将像素序列渲染为一系列连接的边到边线段。落在一条线上的像素将被简化为仅具有起点和边缘点的线段。
  6. 从线段生成所需数据类型的向量。

寻脊结果图像中的红色像素是否令人满意?如果您想找到图像中的所有边缘,那么可能需要对参数进行某种处理。

一个潜在的问题是,陆地和水域之间的边缘可能需要一组寻找山脊的参数,而寻找陆地内的边缘可能需要一组不同的参数。我注意到山脊探测器会为陆地/水域边缘产生明亮(强)的像素。

洪水填充算法是寻找陆地和水域之间边缘的另一种方法。寻找山脊的算法看起来运行得相当好,但值得了解洪水填充。

https://en.wikipedia.org/wiki/Flood_fill

在 Photoshop 或 GIMP 等图像编辑软件中,洪水填充可以实现为“桶填充”或“绘画”或类似的名称。

例如,使用 GIMP 中的“桶填充”功能,并在查找相似颜色时接受默认阈值 15,如果我单击任意选择的某个像素以红色填充水区域,那么我会得到以下图像:

如果我增加阈值,我会得到稍微不同的图像:

我用鼠标点击的点就是种子点。如果我在海岸线附近的浅色边框蓝色区域(大概是浅水区)内单击,那么该区域将被填充。

图像编辑问题是一种快速测试洪水填充是否会产生足够准确的区域以满足您的目的的方法。

填充区域有一个边界,其中的像素可以通过边缘跟踪算法进行排序。一旦您订购了像素,您就可以应用 Rahm-Puecker-Douglas 来简化边缘,如上所述。

© www.soinside.com 2019 - 2024. All rights reserved.