Reputation: 866
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
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
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
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
Upvotes: 2
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