Search code examples
pythonimageopencvmatplotlibrectangles

Draw image in rectangle python


I have plotted a rectangle using matplotlib and would like to place an image in it as shown in the image below. Does anyone have an idea how I can achieve this in python?

Click here for image of problem


Solution

  • Here is one way using Python/OpenCV/Numpy. Do a perspective warp of the panda image using its 4 corners and the 4 corners of the rectangle. Then make a mask of the excess regions, which are black in the warped image. Finally, blend the warped image and background image using the mask.

    Input:

    enter image description here

    Graph Image:

    enter image description here

    import numpy as np
    import cv2
    import math
    
    # read image to be processed
    img = cv2.imread("panda.png")
    hh, ww = img.shape[:2]
    
    # read background image
    bck = cv2.imread("rectangle_graph.png")
    hhh, www = bck.shape[:2]
    
    # specify coordinates for corners of img in order TL, TR, BR, BL as x,y pairs
    img_pts = np.float32([[0,0], [ww-1,0], [ww-1,hh-1], [0,hh-1]])
    
    # manually pick coordinates of corners of rectangle in background image
    bck_pts = np.float32([[221,245], [333,26], [503,111], [390,331]])
    
    # compute perspective matrix
    matrix = cv2.getPerspectiveTransform(img_pts,bck_pts)
    #print(matrix)
    
    # change black and near-black to graylevel 1 in each channel so that no values 
    # inside panda image will be black in the subsequent mask
    img[np.where((img<=[5,5,5]).all(axis=2))] = [1,1,1]
    
    # do perspective transformation setting area outside input to black
    img_warped = cv2.warpPerspective(img, matrix, (www,hhh), cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=(0,0,0))
    
    # make mask for area outside the warped region
    # (black in image stays black and rest becomes white)
    mask = cv2.cvtColor(img_warped, cv2.COLOR_BGR2GRAY)
    mask = cv2.threshold(mask, 0, 255, cv2.THRESH_BINARY)[1]
    mask = cv2.merge([mask,mask,mask])
    mask_inv = 255 - mask
    
    # use mask to blend between img_warped and bck
    result = ( 255 * (bck * mask_inv + img_warped * mask) ).clip(0, 255).astype(np.uint8)
    
    # save images
    cv2.imwrite("panda_warped.png", img_warped)
    cv2.imwrite("panda_warped_mask.png", mask)
    cv2.imwrite("panda_in_graph.png", result)
    
    # show the result
    cv2.imshow("warped", img_warped)
    cv2.imshow("mask", mask)
    cv2.imshow("result", result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    Warped Input:

    enter image description here

    Mask:

    enter image description here

    Result:

    enter image description here