OpenCV子图像与标题和边框周围的空间

4
我希望在每个子图周围显示标题和边框,类似于以下这个例子(由以下stackoverflow帖子提供:OpenCV(Python)视频子图):

我想要的: enter image description here

但我只能通过改编代码来得到下面这个结果。

 import cv2
 im1 = cv2.imread('Lenna.png')
 final_frame = cv2.hconcat((im1, im1))
 cv2.imshow('lena', final_frame)

我所拥有的 enter image description here

使用OpenCV是否可以获得这个?我知道一个变通方法是将文字放在图像上,但那不是我想要的,因为那样会遮盖重要信息。

更新

我的错,我一开始没有说明:我有4个子图(因此有4个不同的图像),而不是像示例中那样只有两个。此外,由于我有视频(时间限制),我希望解决方案尽可能快。

enter image description here

3个回答

8

我有一个相当快速而简单的方案。您可以根据需要进行改善。我将解释放在代码旁边:

import cv2
import numpy as np

img1 = cv2.imread('lena.jpg')

#--- Here I am creating the border---
black = [0,0,0]     #---Color of the border---
constant=cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_CONSTANT,value=black )
cv2.imshow('constant',constant)

在此输入图片描述

你可以在这个页面找到其他不同边框的选项。

#--- Here I created a violet background to include the text ---
violet= np.zeros((100, constant.shape[1], 3), np.uint8)
violet[:] = (255, 0, 180) 

enter image description here

#--- I then concatenated it vertically to the image with the border ---

vcat = cv2.vconcat((violet, constant))
cv2.imshow('vcat', vcat)

enter image description here

#--- Now I included some text ---
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(vcat,'FRAME',(30,50), font, 2,(0,0,0), 3, 0)
cv2.imshow('Text', vcat)

enter image description here

#--- I finally concatenated both the above images horizontally---
final_img = cv2.hconcat((vcat, vcat))
cv2.imshow('Final', final_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

enter image description here


希望这个答案能够帮到你。你可以根据自己的需求进行修改。 - Jeru Luke
1
一个小建议,为什么不增加顶部边框的大小,例如 constant=cv2.copyMakeBorder(img1,100,10,10,10,cv2.BORDER_CONSTANT,value=black )。这样紫色矩形就不再必要了。我不需要任何花哨的东西,只需要快速简单的解决方案 :) - RMS
就像我说的,你总是可以修改它。你也可以调整文本的位置。 :D - Jeru Luke
希望这对你有所帮助 :) - Jeru Luke

8

创建一个新的图片,宽度增加 width += width/10 ,高度增加 height += height/20。添加标题文本,并将输入图片居中放置:

import cv2
import numpy as np


img = cv2.imread("/Users/anmoluppal/Downloads/Lenna.png")

height, width, ch = img.shape
new_width, new_height = width + width/20, height + height/8

# Crate a new canvas with new width and height.
canvas = np.ones((new_height, new_width, ch), dtype=np.uint8) * 125

# New replace the center of canvas with original image
padding_top, padding_left = 60, 10
if padding_top + height < new_height and padding_left + width < new_width:
    canvas[padding_top:padding_top + height, padding_left:padding_left + width] = img
else:
    print "The Given padding exceeds the limits."

text1 = "Sample Image 1"
text2 = "Sample Image 2"
img1 = cv2.putText(canvas.copy(), text1, (int(0.25*width), 30), cv2.FONT_HERSHEY_COMPLEX, 1, np.array([255, 0, 0]))
img2 = cv2.putText(canvas.copy(), text2, (int(0.25*width), 30), cv2.FONT_HERSHEY_COMPLEX, 1, np.array([255, 0, 0]))

final = cv2.hconcat((img1, img2))
cv2.imwrite("./debug.png", final)

enter image description here


1
嘿,这是一个更优化的解决方案。干得好伙计!!!! 我的解决方案相对比较粗糙:D - Jeru Luke
1
别担心,兄弟,你的解决方案使用了像 cv2.copyMakeBorder 这样的内置方法,而不是数学计算,这对我来说看起来很好,谢谢你的赞赏 :) - ZdaR

5
我使用其他答案创建了一个可通用的函数,可适用于任意行/列:
def cvSubplot(imgs,     # 2d np array of imgs (each img an np arrays of depth 1 or 3).
              pad=10,   # number of pixels to use for padding between images. must be even
              titles=None,  # (optional) np array of subplot titles
              win_name='CV Subplot' # name of cv2 window
              ):
    '''
    Makes cv2 based subplots. Useful to plot image in actual pixel size
    '''

    rows, cols = imgs.shape

    subplot_shapes = np.array([list(map(np.shape, x)) for x in imgs])
    sp_height, sp_width, depth = np.max(np.max(subplot_shapes, axis=0), axis=0)

    title_pad = 30
    if titles is not None:
        pad_top = pad + title_pad
    else:
        pad_top = pad

    frame = np.zeros((rows*(sp_height+pad_top), cols*(sp_width+pad), depth ))

    for r in range(rows):
        for c in range(cols):
            img = imgs[r, c]
            h, w, _ = img.shape
            y0 = r * (sp_height+pad_top) + pad_top//2
            x0 = c * (sp_width+pad) + pad//2
            frame[y0:y0+h, x0:x0+w, :] = img

            if titles is not None:
                frame = cv2.putText(frame, titles[r, c], (x0, y0-title_pad//4), cv2.FONT_HERSHEY_COMPLEX, .5, (255,255,255))

    cv2.imshow(win_name, frame)
    cv2.waitKey(0)

以下是一个使用示例:
import cv2
import numpy as np

a1 = np.random.random((40,400,1))
a2 = np.random.random((200,200,1))
a3 = np.random.random((100,100,1))
a4 = np.random.random((300,150,1))
a5 = np.random.random((100,150,1))
filler = np.zeros((0,0,1))

titles = np.array([['A', 'B', 'C'], ['D', 'E', 'Filler']])

imgs = np.array([[a1, a2, a3], [a4, a5, filler]])

cvSubplot(imgs, pad=20, titles=titles)

那个脚本会生成以下的cv2图像:

enter image description here


如果您有相同大小的图像,则必须注意numpy数组将数组的数组展平为n维数组。在这种情况下,是一个五维数组。我还没有找到强制numpy保留数组的好方法,但这个解决方法有效:a1 = np.random.random((300,300,1)) a2 = a1 imgs = np.empty([1,2], dtype=object) imgs[0,0] = a1 imgs[0,1] = a2 - D. Josefsson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接