OpenCV & Python:快速将遮罩叠加在图像上而不会溢出
OpenCV & Python: quickly superimpose mask over image without overflow
我想在彩色图像上叠加一个二进制蒙版,这样蒙版为 "on" 的地方,像素值的变化量我可以设置。结果应如下所示:
我正在使用 OpenCV 2.4 和 Python 2.7.6。我有一种方法效果很好,但速度很慢,另一种方法速度很快,但存在上溢和下溢问题。这是更快代码的结果,带有 overflow/underflow 个工件:
这是我的代码,显示了快速版本和慢速版本:
def superimpose_mask_on_image(mask, image, color_delta = [20, -20, -20], slow = False):
# superimpose mask on image, the color change being controlled by color_delta
# TODO: currently only works on 3-channel, 8 bit images and 1-channel, 8 bit masks
# fast, but can't handle overflows
if not slow:
image[:,:,0] = image[:,:,0] + color_delta[0] * (mask[:,:,0] / 255)
image[:,:,1] = image[:,:,1] + color_delta[1] * (mask[:,:,0] / 255)
image[:,:,2] = image[:,:,2] + color_delta[2] * (mask[:,:,0] / 255)
# slower, but no issues with overflows
else:
rows, cols = image.shape[:2]
for row in xrange(rows):
for col in xrange(cols):
if mask[row, col, 0] > 0:
image[row, col, 0] = min(255, max(0, image[row, col, 0] + color_delta[0]))
image[row, col, 1] = min(255, max(0, image[row, col, 1] + color_delta[1]))
image[row, col, 2] = min(255, max(0, image[row, col, 2] + color_delta[2]))
return
有没有一种快速的方法(可能使用一些 numpy 的函数)来获得我的慢速代码当前产生的相同结果?
可能有更好的方法将着色蒙版应用到图像,但如果您想按照您建议的方式进行操作,那么这个简单的剪辑就可以满足您的要求:
import numpy as np
image[:, :, 0] = np.clip(image[:, :, 0] + color_delta[0] * (mask[:, :, 0] / 255), 0, 255)
image[:, :, 1] = np.clip(image[:, :, 1] + color_delta[1] * (mask[:, :, 0] / 255), 0, 255)
image[:, :, 2] = np.clip(image[:, :, 2] + color_delta[2] * (mask[:, :, 0] / 255), 0, 255)
结果是:
如果您的目标是将颜色应用到某个区域,另一种方法是简单地修改 hue/saturation。例如:
mask = np.zeros((image.shape[0], image.shape[1]), dtype=np.bool)
mask[100:200, 100:500] = True
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
image[mask, 0] = 80
image[mask, 1] = 255
image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR)
import numpy as np
# Get clipped values after broadcasted summing of image and color_delta
clipvals = np.clip(image + color_delta,0,255)
# Mask of image elements to be changed
mask1 = mask[:,:,0]>0
# Extract clipped values for TRUE values in mask1, otherwise keep image
out = np.einsum('ijk,ij->ijk',clipvals,mask1) + np.einsum('ijk,ij->ijk',image,~mask1)
运行时测试
In [282]: # Setup inputs
...: M = 1000; N = 1000
...: image = np.random.randint(-255,255,(M,N,3))
...: imagecp = image.copy()
...: mask = np.random.randint(0,10,(M,N,3))
...: color_delta = np.random.randint(-255,255,(3))
...:
In [283]: def clip_einsum(image,color_delta,mask):
...: clipvals = np.clip(imagecp + color_delta,0,255)
...: mask1 = mask[:,:,0]>0
...: return np.einsum('ijk,ij->ijk',clipvals,mask1) +
np.einsum('ijk,ij->ijk',image,~mask1)
...:
In [284]: def org_approach(image,color_delta,mask):
...: rows, cols = image.shape[:2]
...: #out = image.copy()
...: for row in range(rows):
...: for col in range(cols):
...: if mask[row, col, 0] > 0:
...: image[row, col, 0] = min(255, max(0,
image[row, col, 0] + color_delta[0]))
...: image[row, col, 1] = min(255, max(0,
image[row, col, 1] + color_delta[1]))
...: image[row, col, 2] = min(255, max(0,
image[row, col, 2] + color_delta[2]))
...:
In [285]: %timeit clip_einsum(image,color_delta,mask)
10 loops, best of 3: 147 ms per loop
In [286]: %timeit org_approach(image,color_delta,mask)
1 loops, best of 3: 5.95 s per loop
我想在彩色图像上叠加一个二进制蒙版,这样蒙版为 "on" 的地方,像素值的变化量我可以设置。结果应如下所示:
我正在使用 OpenCV 2.4 和 Python 2.7.6。我有一种方法效果很好,但速度很慢,另一种方法速度很快,但存在上溢和下溢问题。这是更快代码的结果,带有 overflow/underflow 个工件:
这是我的代码,显示了快速版本和慢速版本:
def superimpose_mask_on_image(mask, image, color_delta = [20, -20, -20], slow = False):
# superimpose mask on image, the color change being controlled by color_delta
# TODO: currently only works on 3-channel, 8 bit images and 1-channel, 8 bit masks
# fast, but can't handle overflows
if not slow:
image[:,:,0] = image[:,:,0] + color_delta[0] * (mask[:,:,0] / 255)
image[:,:,1] = image[:,:,1] + color_delta[1] * (mask[:,:,0] / 255)
image[:,:,2] = image[:,:,2] + color_delta[2] * (mask[:,:,0] / 255)
# slower, but no issues with overflows
else:
rows, cols = image.shape[:2]
for row in xrange(rows):
for col in xrange(cols):
if mask[row, col, 0] > 0:
image[row, col, 0] = min(255, max(0, image[row, col, 0] + color_delta[0]))
image[row, col, 1] = min(255, max(0, image[row, col, 1] + color_delta[1]))
image[row, col, 2] = min(255, max(0, image[row, col, 2] + color_delta[2]))
return
有没有一种快速的方法(可能使用一些 numpy 的函数)来获得我的慢速代码当前产生的相同结果?
可能有更好的方法将着色蒙版应用到图像,但如果您想按照您建议的方式进行操作,那么这个简单的剪辑就可以满足您的要求:
import numpy as np
image[:, :, 0] = np.clip(image[:, :, 0] + color_delta[0] * (mask[:, :, 0] / 255), 0, 255)
image[:, :, 1] = np.clip(image[:, :, 1] + color_delta[1] * (mask[:, :, 0] / 255), 0, 255)
image[:, :, 2] = np.clip(image[:, :, 2] + color_delta[2] * (mask[:, :, 0] / 255), 0, 255)
结果是:
如果您的目标是将颜色应用到某个区域,另一种方法是简单地修改 hue/saturation。例如:
mask = np.zeros((image.shape[0], image.shape[1]), dtype=np.bool)
mask[100:200, 100:500] = True
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
image[mask, 0] = 80
image[mask, 1] = 255
image = cv2.cvtColor(image, cv2.COLOR_HSV2BGR)
import numpy as np
# Get clipped values after broadcasted summing of image and color_delta
clipvals = np.clip(image + color_delta,0,255)
# Mask of image elements to be changed
mask1 = mask[:,:,0]>0
# Extract clipped values for TRUE values in mask1, otherwise keep image
out = np.einsum('ijk,ij->ijk',clipvals,mask1) + np.einsum('ijk,ij->ijk',image,~mask1)
运行时测试
In [282]: # Setup inputs
...: M = 1000; N = 1000
...: image = np.random.randint(-255,255,(M,N,3))
...: imagecp = image.copy()
...: mask = np.random.randint(0,10,(M,N,3))
...: color_delta = np.random.randint(-255,255,(3))
...:
In [283]: def clip_einsum(image,color_delta,mask):
...: clipvals = np.clip(imagecp + color_delta,0,255)
...: mask1 = mask[:,:,0]>0
...: return np.einsum('ijk,ij->ijk',clipvals,mask1) +
np.einsum('ijk,ij->ijk',image,~mask1)
...:
In [284]: def org_approach(image,color_delta,mask):
...: rows, cols = image.shape[:2]
...: #out = image.copy()
...: for row in range(rows):
...: for col in range(cols):
...: if mask[row, col, 0] > 0:
...: image[row, col, 0] = min(255, max(0,
image[row, col, 0] + color_delta[0]))
...: image[row, col, 1] = min(255, max(0,
image[row, col, 1] + color_delta[1]))
...: image[row, col, 2] = min(255, max(0,
image[row, col, 2] + color_delta[2]))
...:
In [285]: %timeit clip_einsum(image,color_delta,mask)
10 loops, best of 3: 147 ms per loop
In [286]: %timeit org_approach(image,color_delta,mask)
1 loops, best of 3: 5.95 s per loop