Sourav
Sourav

Reputation: 866

Change Single Color in a Video with OpenCV Python

I have a video of a brick breaking game. Some bricks are in red color. I have to change the red color into black. I am trying to find the location of the red pixel in numpy array and assign black color on those pixels. The code I have provided below turns the red color into black. But the process is so slow that 12s video took more than 5 mins. Is there any faster way to do that?

import numpy as np
import cv2


vid = "input.mp4"
cap = cv2.VideoCapture(vid)

while(True):
    ret, frame = cap.read()
    if ret: 
        for i in zip(*np.where(frame == [0,0,255])):
            frame[i[0], i[1], 0] = 0
            frame[i[0], i[1], 1] = 0
            frame[i[0], i[1], 2] = 0
        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break
cv2.destroyAllWindows()

Upvotes: 0

Views: 6392

Answers (4)

Sourav
Sourav

Reputation: 866

Using Ha Bom's code and some parts of my code, the problem has been solved. However, it takes a little bit of time. Processing 12-second video takes around 20-25 sec. The main purpose was to convert red pixels into orange- The code is provided below -

cap = cv2.VideoCapture("input.avi")

while(True):
    ret, frame = cap.read()
    if ret:

        # hsv is better to recognize color, convert the BGR frame to HSV
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

        # in hsv red color located in two region. Create the mask for red color
        # mask the red color and get an grayscale output where red is white
        # everything else are black
        mask1 = cv2.inRange(hsv, (0,50,20), (5,255,255))
        mask2 = cv2.inRange(hsv, (175,50,20), (180,255,255))
        mask = cv2.bitwise_or(mask1, mask2)

        # get the index of the white areas and make them orange in the main frame
        for i in zip(*np.where(mask == 255)):
                frame[i[0], i[1], 0] = 0
                frame[i[0], i[1], 1] = 165
                frame[i[0], i[1], 2] = 255

        # play the new video
        cv2.imshow("res",frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break
cv2.destroyAllWindows()

Upvotes: 0

the23Effect
the23Effect

Reputation: 580

you can replace your for loop with this:

    # [b,g,r]
    color_in = [0, 0, 255]  # color you want to filter
    color_out = [0, 0, 0]   # color you want to set
    for i in range(3):
        frame[frame[:, :, i] == color_in[i]] = color_out[i]

You can use this for video frame with 3 color channels. Also, you can play around with the conditional operator(replace with >, <, etc.) for more control.

Use like this to filter color ranges:

frame[frame[:, :, i] < color_in[i]] = color_out[i]

Upvotes: 0

Ha Bom
Ha Bom

Reputation: 2917

Try this out, read comments in the code for more information.

import cv2
import numpy as np

img = cv2.imread("1.png")

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of red color in HSV
lower_red = np.array([0,50,50])
upper_red = np.array([10,255,255])
# Threshold the HSV image to get only red colors
mask = cv2.inRange(hsv, lower_red, upper_red)
red_only = cv2.bitwise_and(img,img, mask= mask)

#convert mask to 3-channel image to perform subtract
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)

res = cv2.subtract(img,mask) #negative values become 0 -> black

cv2.imshow("img",img)
cv2.imshow("mask",mask)
cv2.imshow("red_only",red_only)
cv2.imshow("res",res)
cv2.waitKey()
cv2.destroyAllWindows()

PS. And this method takes almost no time, I've tested on my machine and it takes about 3ms for an image of 1280x720

enter image description here enter image description here enter image description here enter image description here

Upvotes: 2

Martin
Martin

Reputation: 3385

This works just for gray

(you cant specify channels with color you are replacing)

color_find = [0,0,255]
indexes=np.where(frame == color_find)
frame[indexes]=0 # 0-255 creates [0,0,0] - [255,255,255]

More general attitude is like this

Here you specify RGB axis, and you can replace with any color

red = [0,0,255]
black = [0,0,0]
indexes=np.where(np.all(frame == red,axis = 2))
frame[indexes] = black

Upvotes: 0

Related Questions