【问题标题】:matplotlib opencv image subplotmatplotlib opencv 图像子图
【发布时间】:2017-09-08 10:14:07
【问题描述】:

在一个全局 matplotlib 图中,我想要一些 不同 大小的子图。例如,一个子图应该是从 opencv2(网络摄像头)捕获的帧的确切大小,另一个应该是从该帧获得的较小图像。

我有两个不同的问题,都是关于尺寸的:

  1. 我知道我可以指定 plt.figure 的 figSize,但是如何为每个子图 (fig.add_subplot) 设置不同的子图大小?
  2. opencv 的框架带有像素,我怎样才能使子图显示完全相同的图像(大小),特别是因为 matplotlib 使用英寸作为尺寸?

获取框架:

import cv2
import matplotlib.pyplot as plt

cap = cv2.VideoCapture(0)
ret, frame = cap.read()

构建图形和子图:

fig = plt.figure()
img = fig.add_subplot(121)
img2 = fig.add_subplot(122)

然后将框架放入子图

img.imshow(frame) #this should be the original size of captured frame
#take out a square of the frame, and plot with box dimensions
#img2.imshow(box)

干杯!

----- 编辑 ------

虽然我将使用网络摄像头拍摄图像,但我的问题的核心如下: 1.用opencv打开图片 2. 将图像绘制成一个子图,与 opencv 读取的图像具有相同的尺寸

代码:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('flower.jpg')
cv2.imshow('img',img)

fig = plt.figure()
video_plot = plt.subplot2grid((10, 10), (0, 0)) #Here I need to specify the same size as original
video = video_plot.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

cv2.waitKey(0)
cv2.destroyAllWindows()

plt.show()

原始256x256图片,用opencv打开读取

较小的图像,如果我省略 colspan 和 rowspan (=1) plt.subplot2grid((10, 10), (0, 0))

更大的图像,如果我最大化 colspan 和 rowspan: plt.subplot2grid((10, 10), (0, 0), colspan=10, rowspan=10)

所以总结一下,如何绘制相同大小的图像?

【问题讨论】:

    标签: python opencv matplotlib


    【解决方案1】:

    图形大小确实以英寸为单位。每英寸点数 (dpi) 也在 matplotlib 中指定。

    知道以英寸为单位的图形大小和 dpi 允许您通过将像素除以 dpi 和图形大小来在图形坐标(从 0 到 1)中定位轴。例如。为了将轴放置在距左下角 50 像素的位置

    fig.add_axes([50./dpi/figsize[0], 50./dpi/figsize[1], ...])
    

    宽度和高度类似地由每个方向的像素数除以dpi和以英寸为单位的图形大小确定。

    完整示例:

    import matplotlib.pyplot as plt
    import numpy as np; np.random.seed(0)
    
    ar = np.random.poisson(lam=10, size=(250,300))
    cut = ar[50:100, 200:250]; print cut.shape
    dpi=100. # dots per inch
    figsize=(5, 3.5)
    fig = plt.figure(figsize=figsize)
    
    ax = fig.add_axes([50./dpi/figsize[0],50./dpi/figsize[1],
                        ar.shape[1]/dpi/figsize[0],ar.shape[0]/dpi/figsize[1]])
    im = ax.imshow(ar)
    
    ax2 = fig.add_axes([100./dpi/figsize[0]+ar.shape[1]/dpi/figsize[0],50./dpi/figsize[1],
                        cut.shape[1]/dpi/figsize[0],cut.shape[0]/dpi/figsize[1]])
    im2 = ax2.imshow(cut)
    
    ax.axis("off")
    
    plt.show()
    

    【讨论】:

    • 谢谢,这有助于我理解在 matplotlib 中使用 dpi/pixels/inches!但是,例如,您将如何使用图像执行此操作?如果您想以原始大小打开并在子图中显示它,那么像您一样获取中心 50x50 框并将其显示在另一个子图中?
    • 在上述解决方案中ar一个(灰度)图像。所以我不确定我是否理解这里的问题。如果您有一个 3 通道彩色图像,则需要在索引中为剪辑添加另一个维度 cut = ar[50:100, 200:250, :]。是这个意思吗?
    • 这个问题与图像的大小有关,并试图在图中获得其等效大小。我已经编辑了我的原始帖子,举了一个我需要的例子。泰
    • 所以我确实在我的回答中提供了一个解决方案。如果你不使用这个解决方案,而是使用一些任意的子图网格,你当然不会得到想要的结果。我还能做些什么来帮助您?
    【解决方案2】:

    @ImportanceOfBeingErnes 的解决方案对我有用,但我很难理解它。问题在于从数组中提取 opencv 和 matplotlib 图像的宽度/高度的差异。我更喜欢使用可读的变量名来隐藏这种复杂性。

    所以这个辅助函数是获取合适坐标轴的核心:

    def addImage(fig,image,x,y):    
        dpi=fig.dpi
        fw,fh=fig.get_size_inches()[:2]
        ih,iw=image.shape[:2]
        ax = fig.add_axes([x/dpi/fw,y/dpi/fh,iw/dpi/fw,ih/dpi/fh])
        return ax  
    

    结果:

    代码: 另见https://github.com/WolfgangFahl/play-chess-with-a-webcam/blob/master/examples/matplotlib/image_show.py

    #!/usr/bin/python
    # -*- encoding: utf-8 -*-
    # part of https://github.com/WolfgangFahl/play-chess-with-a-webcam
    # see https://stackoverflow.com/questions/43372792/matplotlib-opencv-image-subplot
    import matplotlib.pyplot as plt
    import sys
    import cv2
    
    def main(argv):
        # get the square chessbord file as an example
        default_file = '../../testMedia/chessBoard011.jpg'
        filename = argv[0] if len(argv) > 0 else default_file
        image = cv2.imread(filename)
        cv2.cvtColor(ima,cv2.COLOR_BGR2RGB)
    
        # resize it to fit at the default 100 dpi
        w=320
        h=320
        x=50
        y=50
        image = cv2.resize(image,(w,h))
        # 6 x 4 inch figure
        figsize=(6, 4)
        fig = plt.figure(figsize=figsize)
    
        # add the image at position x=50, y=50 (in image coordinates)
        ax=addImage(fig,image,x,y)
        im = ax.imshow(image)
    
        subboard2x2=image[w//4:w//2,h//4:h//2,:]
        yLegendOffset=100
        ax2=addImage(fig,subboard2x2,w+yLegendOffset,h//2)
        im2=ax2.imshow(subboard2x2) 
    
        ax.axis("off")
    
        plt.show()
    
    def addImage(fig,image,x,y):    
        dpi=fig.dpi
        fw,fh=fig.get_size_inches()[:2]
        ih,iw=image.shape[:2]
        ax = fig.add_axes([x/dpi/fw,y/dpi/fh,iw/dpi/fw,ih/dpi/fh])
        return ax  
    
    if __name__ == "__main__":
        main(sys.argv[1:])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-06-11
      • 2021-03-13
      • 2020-12-19
      • 2015-10-05
      • 2017-08-30
      • 1970-01-01
      相关资源
      最近更新 更多