matplotlib opencv图像子图

时间:2017-04-12 14:43:17

标签: python opencv matplotlib

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

我有两个不同的问题,都涉及到尺寸调整:

  1. 我知道我可以指出plt.figure的figSize,但是如何为每个子图设置不同的子图大小(fig.add_subplot)?
  2. opencv中的帧是带像素的,如何让子图显示完全相同的图像(大小),特别是因为matplotlib使用英寸来表示尺寸?
  3. 获取框架:

    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打开读取

    enter image description here

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

    enter image description here

    更大的图像,如果我最大限度地使用colspan和rowspan:     plt.subplot2grid((10,10),(0,0),colspan = 10,rowspan = 10)

    enter image description here

    总而言之,我如何绘制相同的图像尺寸?

2 个答案:

答案 0 :(得分:0)

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

知道以英寸为单位的图形尺寸和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()

enter image description here

答案 1 :(得分:0)

@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  

结果: ChessBoard Example

代码: 另请参见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:])