1

I am trying to crop the live video diagonally. With the help of cv.line, I have mentioned the dimensions and my goal is to display the video of the lower side of the line I have drawn and the upper video should be cropped, As a beginner, I was just able to draw a line using the following code:

import cv2

cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)

if vc.isOpened(): # try to get the first frame
    rval, frame = vc.read()
else:
    rval = False

while rval:
    cv2.imshow("preview", frame)
    rval, frame = vc.read()
    key = cv2.waitKey(20)
    if key == 27: # exit on ESC
        break
    else:
        cv2.line(img=frame, pt1=(700,5), pt2=(5, 450), color=(255, 0, 0), thickness=1, lineType=8, shift=0)

vc.release()
cv2.destroyWindow("preview")

Output: enter image description here

Suggestion on this will be very helpful

varul jain
  • 334
  • 8
  • 23
  • There isn't any software that handles triangular, or non-rectangular, images. You'll need to make the top-left transparent (or solid black or white) rather than cropped. – Mark Setchell Apr 26 '19 at 07:25
  • can you please share the code which helps me in making the top left transparent? – varul jain Apr 26 '19 at 07:28
  • 1
    Before you do that, be aware that AFAIK, `imshow()` doesn't handle transparency but any PNG files you save will honour the transparency. – Mark Setchell Apr 26 '19 at 08:03
  • To add transparency, use `RGBAframe = cv2.cvtColor(frame, cv2.COLOR_RGB2RGBA)` then draw a white triangle on a black background in `RGBAframe[:,:,3]` – Mark Setchell Apr 26 '19 at 08:05
  • Code for drawing filled triangle here... https://stackoverflow.com/a/51876455/2836621 – Mark Setchell Apr 26 '19 at 08:07

2 Answers2

2

Here's the code that'll mask out the points above the line. I've added comments here so you can follow what's going on. There are faster ways to do this, but I wanted something that would be easily readable.

import cv2
import matplotlib.pyplot as plt
import numpy as np

path = r"path\to\img"

img = cv2.imread(path)

#plt.imshow(img)
#plt.show()
pt1 = (86, 0) #ensure this point exists within the image
pt2 = (0, 101) #ensure this point exists within the image
cv2.line(img, pt1, pt2, (255, 255, 255))

#plt.imshow(img)
#plt.show()
#slope of line
m = float(pt2[1] - pt1[1])/float(pt2[0] - pt1[0])
c = pt1[1] - m*pt1[0]
#create mask image
mask1 = np.zeros(img.shape, np.uint8)
#for every point in the image
for x in np.arange(0, 87):
    for y in np.arange(0, 102):
        #test if point exists above the line, 
        if y > m*x + c:
            mask1[y][x] = (255, 255, 255)


#plt.imshow(mask1)
#plt.show()
fin_img = cv2.merge((img[:, :, 0], img[:, :, 1], img[:, :, 2], mask1[:,:, 0]))
#plt.imshow(fin_img)
#plt.show()

cv2.imwrite('output.png', fin_img)
Shawn Mathew
  • 2,198
  • 1
  • 14
  • 31
  • Just to note: for loop in OpenCV is a pretty inefficient operation. It is fine with 100*100 images or so, but beyond that, I would highly recommend using opencv functions rather than for loops. – smttsp Nov 09 '20 at 19:54
1

To crop images, I use a mask and cv2.bitwise_and().

Source Image:

source image

The mask:

# Create a mask image with a triangle on it
y,x,_ = img.shape
mask = np.zeros((y,x), np.uint8)
triangle_cnt = np.array( [(x,y), (x,0), (0,y)] )
cv2.drawContours(mask, [triangle_cnt], 0, 255, -1)

mask image

The output:

img = cv2.bitwise_and(img, img, mask=mask)

output

Stephen Meschke
  • 2,820
  • 1
  • 13
  • 25