【问题标题】:Matplotlib contour plot does not extract exact contoursMatplotlib 等高线图不提取精确的等高线
【发布时间】:2022-08-19 05:03:00
【问题描述】:

我在提取以下数据的确切轮廓时遇到了困难:(您只需查看数据就可以看到轮廓)

data = np.array(
      [[ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277]])

如果我绘制它:

plt.imshow(data)

但是,当我尝试使用以下方法提取轮廓时:

plt.contour(data, levels = np.unique(data))

如您所见,轮廓不遵循实际数据的尖角。如果我覆盖两个图:

这是完整的代码:

import numpy as np
import matplotlib.pyplot as plt

data = np.array([[ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277]])

plt.imshow(data)
plt.show()
plt.contour(data, levels=np.unique(data), cmap=\"jet\")
plt.colorbar()
  • 如果您将轮廓级别设置为与您的数据完全相同,那么对于给定像素将位于边界的哪一侧,这是一个舍入错误。如果您希望轮廓沿着边界,请设置您的唯一值之间的级别。
  • @JodyKlymak 嗯,你会怎么做?您所说的“在您的独特价值观之间”是什么意思?

标签: python matplotlib


【解决方案1】:

使用marching squares algorithm 绘制轮廓来计算轮廓位置,它在网格点之间进行插值。

也许您正在寻找离散区域边界:可以像这样检索这些边界:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

data = np.array([[ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277]])


def region_borders(data, value, color, **kwargs):
    v = np.argwhere(np.diff((data == value).T, axis=0))
    vlines = np.array(list(zip(v + [.5, -.5], v + [.5, .5])))
    
    h = np.argwhere(np.diff((data == value).T, axis=1))
    hlines = np.array(list(zip(h + [-.5, .5], h + [.5, .5])))
    
    if len(vlines) and len(hlines):
        lines = np.vstack((vlines, hlines))
    elif len(vlines):
        lines = vlines
    else:
        lines = hlines
    return mpl.collections.LineCollection(lines, colors=color, **kwargs)


contours = np.unique(data)

fig, ax = plt.subplots(ncols=len(contours)+1, sharex=True, sharey=True, layout='constrained')
im = ax[0].matshow(data, cmap='jet', aspect='auto')
fig.colorbar(im, ax=ax[-1])

norm = mpl.colors.Normalize(data.min(), data.max())
for i, value in enumerate(contours, 1):
    ax[i].add_collection(region_borders(data, value, mpl.cm.jet(norm(value)), lw=2))
    ax[i].set_title(value)

【讨论】:

  • 非常感谢您的回答。虽然令人印象深刻,但我担心这不是一个通用的解决方案,因为如果我的轮廓不是直线,我认为它可能不起作用。在这种情况下我们该如何解决?
【解决方案2】:

这是我解决它的方法(轮廓和颜色之间仍然有轻微的偏移)

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

import cv2

def change_into_int(data):
    unique = np.unique(data)
    int_data = np.zeros_like(data)
    for i, unique_value in enumerate(unique):
        int_data[data == unique_value] = i+1
    
    return int_data.astype(np.uint8)


def find_contours(int_data):
    
    # For every "color" in the dataset find the contour
    # by eliminating all the other colors one after each other and finding the 
    # individual contours
    contours = []
    
    
    for color in np.unique(int_data):
      
        # Create temporary canvas, and 
        # set all entries equal to 1 that have the same postion as the 
        # original color
        
        mask = np.zeros_like(int_data)
        mask[int_data == color] = 1 # white object on black background
        
    
        c, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
        contours.append(c)
    
    return contours

data = np.array([
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277]])



## Main
int_data = change_into_int(data)
contours = find_contours(int_data)

## Draw 
canvas = np.zeros_like(int_data)

for contour in contours:
    coords = np.reshape(contour[0].flatten(), (-1,2))
    x = list(coords[:,0])
    x.append(x[0])
    
    y = list(coords[:,1])
    y.append(y[0])
    plt.plot(x,y)


plt.imshow(data, origin="lower")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    相关资源
    最近更新 更多