OpenCV subplots images with titles and space around borders

Related searches

I am looking to display some images in OpenCV Python with titles and borders around the each subplot. something like this (courtesy of the following stackoverflow post: OpenCV (Python) video subplots):

WHAT I WANT:

But I only manage to get this with that code adapted.

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

WHAT I HAVE

Is it possible to obtain this using OpenCV? I know a workaround would be to put text on the images, but that's not what I want because it will cover important information that way.

UPDATE

My bad, I didn't specify initially: I have 4 subplots (so 4 different images) and not two like in the example. Also, I want the solution to be as fast as possible since I have video (time restrictions)

I have a pretty quick and dirty solution. You can refine it to suit your needs. I have the explanation alongside the code as well:

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)

You can find many other options for different borders ON THIS PAGE

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

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

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

#--- 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)

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

Basic Operations on Images, If you want to create a border around an image, something like a photo frame, you can use cv. But it has more applications for convolution operation, zero padding etc. plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL'). OpenCV subframe images with titles and space around borders I am looking to display some images in OpenCV Python with titles and borders around the each subplot. something like this (courtesy of the following stackoverflow post: OpenCV (Python) video subplots): WHAT I WANT: But I only manage to get this with

The general idea would be to create a new image with width += width/10 and height += height/20. Write some text as heading and place the input image along the center as:

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)

Smoothing Images, Blur images with various low pass filters; Apply custom-made filters to images (​2D convolution) plt.subplot(122),plt.imshow(dst),plt.title('Averaging') This Gaussian filter is a function of space alone, that is, nearby pixels are considered while  Making Borders for Images (Padding) If you want to create a border around an image, something like a photo frame, you can use cv.copyMakeBorder(). But it has more applications for convolution operation, zero padding etc. This function takes following arguments: src - input image

I used the other answers to make a generalizable function which works for arbitrary row/columns:

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)

Below is an example usage:

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)

That script produces the following cv2 image:

Basic Operations on Images, For BGR image, it returns an array of Blue, Green, Red values. If you want to create a border around the image, something like a photo frame, you can use cv2​. But it has more applications for convolution operation, zero padding etc. plt.​subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL') plt.subplot(232)  We know that cv2.imshow() only shows 1 image at a time. Displaying images side by side helps greatly in analyzing the result. Unlike Matlab, there is no direct function for creating subplots. But since OpenCV reads images as arrays, we can concatenate arrays using the inbuilt cv2.hconcat() and cv2.vconcat() functions.

OpenCV Basic Operation On images, OpenCV Basic Operation On images with What is OpenCV, History, Installation, copyMakeBorder() function to create a border around the image, something like a photo frame. plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('​REPLICATE') The cvtColor is used to convert an image from one color space to another. The frame from opencv is with pixels, how can I make a subplot show the exact same image (in size), especially since matplotlib uses inches for dimensions? Getting frame: import cv2 import matplotlib.pyplot as plt cap = cv2.VideoCapture(0) ret, frame = cap.read()

OpenCV: Basic Operations on Images, Access pixel values and modify them; Access image properties; Setting Region of If you want to create a border around the image, something like a photo frame, you can use cv2. But it has more applications for convolution operation, zero padding etc. 15 plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL'). Show image like its shows in full screen but in small size. from backend we select the image size and we have to show this image without any title bar and border. only image will appear. i try lot of methods, but didn't get success. is there any way to do this ? if any body knows, please help, i stuck in this from many days

Displaying images side by side helps greatly in analyzing the result. Unlike Matlab, there is no direct function for creating subplots. But since OpenCV reads images as arrays, we can concatenate arrays using the inbuilt cv2.hconcat() and cv2.vconcat() functions. After that, we display this concatenated image using cv2.imshow().

Comments
  • Hope This answer helps. You can modify it to suit your requirement.
  • one minor comment. why don't you increase the size of the border on top in, e.g. constant=cv2.copyMakeBorder(img1,100,10,10,10,cv2.BORDER_CONSTANT,value=black ) . that way the violet rectangle is not necessary anymore. I am not looking for anything fancy, but for something fast& simple :)
  • As I said you can always modify it. You can also adjust the position of the text. :D
  • I hope this helped you :)
  • Hey this is a more optimal solution. Great work mate !!!! Mine was rather quick and dirty :D
  • No Worries, Dude, Your solution is using inbuilt methods like cv2.copyMakeBorder instead of maths, which seems good to me , Thanks for appreciating :)
  • If you have images of the same size, you have to be wary of the numpy array flattens the array of arrays to a n-dimensional array. In this case a five dimensional array. I haven't found a good way to force numpy to keep the array of arrays, but this workaround is working: a1 = np.random.random((300,300,1)) a2 = a1 imgs = np.empty([1,2], dtype=object) imgs[0,0] = a1 imgs[0,1] = a2