Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import cv2
- import numpy as np
- import sys
- import math
- import argparse
- # function for 2d convolution (used as is from previous project)
- def conv2(img, kernel, padding_style):
- h, w = kernel.shape
- yO, xO, cO = img.shape
- paddedImg = np.zeros([yO + math.floor(h/2) + math.floor(h/2), xO + math.floor(w/2) + math.floor(w/2), cO], dtype='float32')
- paddedImg[math.floor(h/2) : yO + math.floor(h/2),math.floor(w/2) : xO + math.floor(w/2),:] = img[:,:,:]
- # appply padding
- if(padding_style == 'zero-padding'):
- paddedImg = paddedImg
- elif(padding_style == 'wrap-around'):
- i = math.floor(w/2) - 1
- j = xO + math.floor(w/2) - 1
- while(i >= 0):
- paddedImg[:,i,:] = paddedImg[:,j,:]
- j -= 1
- i -= 1
- i = math.floor(h/2) - 1
- j = yO + math.floor(w/2) - 1
- while(i >= 0):
- paddedImg[i,:,:] = paddedImg[j,:,:]
- j -= 1
- i -= 1
- i = math.floor(w/2) + xO
- j = math.floor(w/2)
- while(i < paddedImg.shape[1]):
- paddedImg[:,i,:] = paddedImg[:,j,:]
- j += 1
- i += 1
- i = math.floor(h/2) + yO
- j = math.floor(h/2)
- while(i < paddedImg.shape[0]):
- paddedImg[i,:,:] = paddedImg[j,:,:]
- j += 1
- i += 1
- elif(padding_style == 'copy-edge'):
- i = math.floor(w/2) - 1
- j = math.floor(w/2)
- while(i >= 0):
- paddedImg[:,i,:] = paddedImg[:,j,:]
- i -= 1
- i = math.floor(h/2) - 1
- j = math.floor(h/2)
- while(i >= 0):
- paddedImg[i,:,:] = paddedImg[j,:,:]
- i -= 1
- i = math.floor(w/2) + xO
- j = xO + math.floor(w/2) - 1
- while(i < paddedImg.shape[1]):
- paddedImg[:,i,:] = paddedImg[:,j,:]
- i += 1
- i = math.floor(h/2) + yO
- j = yO + math.floor(h/2) - 1
- while(i < paddedImg.shape[0]):
- paddedImg[i,:,:] = paddedImg[j,:,:]
- i += 1
- elif(padding_style == 'reflect-across-edge'):
- i = math.floor(w/2) - 1
- j = math.floor(w/2)
- while(i >= 0):
- paddedImg[:,i,:] = paddedImg[:,j,:]
- j += 1
- i -= 1
- i = math.floor(h/2) - 1
- j = math.floor(h/2)
- while(i >= 0):
- paddedImg[i,:,:] = paddedImg[j,:,:]
- j += 1
- i -= 1
- i = math.floor(w/2) + xO
- j = xO + math.floor(w/2) - 1
- while(i < paddedImg.shape[1]):
- paddedImg[:,i,:] = paddedImg[:,j,:]
- j -= 1
- i += 1
- i = math.floor(h/2) + yO
- j = yO + math.floor(h/2) - 1
- while(i < paddedImg.shape[0]):
- paddedImg[i,:,:] = paddedImg[j,:,:]
- j -= 1
- i += 1
- img = paddedImg
- y, x, c = img.shape
- b, g, r = cv2.split(img)
- channels = [b, g, r]
- if(all((r==b).flatten()) and all((g==b).flatten())):
- img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- c = 1
- # apply convlution by point wise multiplication in frequency domain
- if(c == 1):
- imgF = np.fft.fft2(img)
- imgFS = np.fft.fftshift(imgF)
- kernelF = np.fft.fft2(kernel, [y,x])
- kernelFS = np.fft.fftshift(kernelF)
- imgF = imgFS * kernelFS
- imgishift = np.fft.ifftshift(imgF)
- img = np.fft.ifft2(imgishift)
- img = np.abs(img)
- elif(c == 3):
- bF = np.fft.fft2(b)
- bFS = np.fft.fftshift(bF)
- kernelF = np.fft.fft2(kernel, [y,x])
- kernelFS = np.fft.fftshift(kernelF)
- bF = bFS * kernelFS
- bishift = np.fft.ifftshift(bF)
- b = np.fft.ifft2(bishift)
- b = np.abs(b)
- gF = np.fft.fft2(g)
- gFS = np.fft.fftshift(gF)
- gF = gFS * kernelFS
- gishift = np.fft.ifftshift(gF)
- g = np.fft.ifft2(gishift)
- g = np.abs(g)
- rF = np.fft.fft2(r)
- rFS = np.fft.fftshift(rF)
- rF = rFS * kernelFS
- rishift = np.fft.ifftshift(rF)
- r = np.fft.ifft2(rishift)
- r = np.abs(r)
- img = cv2.merge((b, g, r))
- img = img[h-1:h-1+yO, w-1:w-1+xO]
- return img
- # function to resize using nearest neighbour interpolation
- def resize(img, newY, newX):
- res = np.zeros([newY, newX, img.shape[2]], dtype = 'uint8')
- i = 0
- factY = newY/img.shape[0]
- factX = newX/img.shape[1]
- while(i < newY):
- j = 0
- while(j < newX):
- res[i][j][:] = img[math.floor(i/factY)][math.floor(j/factX)][:]
- j += 1
- i += 1
- # kernel = gaussian_kernel(3,3)
- # res = conv2(np.uint8(res), kernel, 'reflect-across-edge')
- if(len(res.shape) == 2):
- res = cv2.cvtColor(np.uint8(res),cv2.COLOR_GRAY2RGB)
- return np.uint8(res)
- # function to generate gaussian kernel
- def gaussian_kernel(size, size_y):
- size = int(size)
- int(size_y)
- x, y = np.mgrid[-size:size+1, -size_y:size_y+1]
- g = np.exp(-(x**2/float(size)+y**2/float(size_y)))
- return g / g.sum()
- # function for pyramid down (like cv2.pyrDown)
- def pyrDown(img):
- k = int((4 * 2 * 2 / 6) +0.5)
- kernel = gaussian_kernel(k,k)
- imgBlur = conv2(np.uint8(img), kernel, 'copy-edge')
- if(len(imgBlur.shape) == 2):
- imgBlur = cv2.cvtColor(np.uint8(imgBlur),cv2.COLOR_GRAY2RGB)
- y, x, c = imgBlur.shape
- # imgDS = cv2.resize(imgBlur, (round(y/2), round(x/2)), interpolation = cv2.INTER_NEAREST)
- imgDS = resize(imgBlur, round(y/2), round(x/2))
- return np.uint8(imgDS)
- # function for pyramid up (like cv2.pyrUp)
- def pyrUp(img):
- y, x, c = img.shape
- k = int((4 * 2 * 2 / 6) +0.5)
- kernel = gaussian_kernel(k,k)
- # imgUS = cv2.resize(img, (y*2, x*2), interpolation = cv2.INTER_NEAREST)
- imgUS = resize(img, y*2, x*2)
- imgUS = conv2(np.uint8(imgUS), kernel, 'copy-edge')
- if(len(imgUS.shape) == 2):
- imgUS = cv2.cvtColor(np.uint8(imgUS),cv2.COLOR_GRAY2RGB)
- return np.uint8(imgUS)
- # function to compute gaussian and laplacian pyramids of given image
- def computePyr(img, number_of_layers):
- G = img.copy()
- gPyr = [G]
- max_num_of_layers = 0
- for i in range(number_of_layers - 1):
- G = pyrDown(G)
- gPyr.append(G)
- max_num_of_layers += 1
- if(G.shape[0] == 1 or G.shape[1] == 1):
- break
- lPyr = [gPyr[len(gPyr) - 1]]
- L = lPyr[0]
- for i in range(max_num_of_layers, 0, -1):
- GE = pyrUp(gPyr[i])
- L = cv2.subtract(gPyr[i-1],GE)
- lPyr.append(L)
- return gPyr, lPyr
- # mouse callback function to draw rectangle
- def draw_rect(event,x,y,flags,param):
- global ix,iy,drawing,mode, img, imgC, xMask, yMask
- if event == cv2.EVENT_LBUTTONDOWN:
- img = imgC.copy()
- drawing = True
- ix,iy = x,y
- elif event == cv2.EVENT_MOUSEMOVE:
- xMask,yMask = x,y
- if drawing == True:
- img = imgC.copy()
- cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),2)
- elif event == cv2.EVENT_LBUTTONUP:
- xMask,yMask = x,y
- drawing = False
- cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),2)
- # mouse callback function to draw ellipse
- def draw_ellipse(event,x,y,flags,param):
- global ix,iy,drawing,mode, img, imgC, xMask, yMask
- if event == cv2.EVENT_LBUTTONDOWN:
- img = imgC.copy()
- drawing = True
- ix,iy = x,y
- elif event == cv2.EVENT_MOUSEMOVE:
- xMask,yMask = x,y
- if drawing == True:
- img = imgC.copy()
- cv2.ellipse(img,(int((ix+xMask)/2),int((iy+yMask)/2)),(int((-ix+xMask)/2),int((-iy+yMask)/2)),0,0,360,(0,255,0),2)
- elif event == cv2.EVENT_LBUTTONUP:
- xMask,yMask = x,y
- drawing = False
- cv2.ellipse(img,(int((ix+xMask)/2),int((iy+yMask)/2)),(int((-ix+xMask)/2),int((-iy+yMask)/2)),0,0,360,(0,255,0),2)
- # function to create foreground mask using mouse callbacks
- def drawMask(fg, shape):
- global ix,iy,drawing,mode, img, imgC, xMask, yMask
- cv2.namedWindow('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue')
- if(shape == 'rect'):
- cv2.setMouseCallback('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue',draw_rect)
- else:
- cv2.setMouseCallback('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue',draw_ellipse)
- while(1):
- cv2.imshow('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue',img)
- k = cv2.waitKey(1) & 0xFF
- if k == 13:
- break
- cv2.destroyAllWindows()
- # r = cv2.selectROI(fg, False)
- fg_mask = np.zeros([fg.shape[0],fg.shape[1], fg.shape[2]], dtype = 'uint8')
- if(shape == 'rect'):
- fg_mask[iy:yMask,ix:xMask, :] = 255
- else:
- cv2.ellipse(fg_mask,(int((ix+xMask)/2),int((iy+yMask)/2)),(int((-ix+xMask)/2),int((-iy+yMask)/2)),0,0,360,(255,255,255),-1)
- return fg_mask
- # function to blend 2 images
- def blend(bg, fg, number_of_layers, shape):
- fg_mask = drawMask(fg, shape)
- g_bg, l_bg = computePyr(bg, number_of_layers)
- g_fg, l_fg = computePyr(fg, number_of_layers)
- g_mask, l_mask = computePyr(fg_mask, number_of_layers)
- LS = []
- i = len(g_mask) - 1
- for l_b, l_f in zip(l_bg, l_fg):
- y, x, c = l_b.shape
- ls = (l_f * (g_mask[i]/255)) + (l_b * (1 - (g_mask[i]/255)))
- LS.append(np.uint8(ls))
- i -= 1
- # now reconstruct
- ls_ = LS[0]
- for i in range(1,len(LS)):
- ls_ = pyrUp(ls_)
- ls_ = cv2.add(np.uint8(ls_), np.uint8(LS[i]))
- return ls_
- # driver code
- parser = argparse.ArgumentParser(description='Pyramid Blending')
- requiredArgs = parser.add_argument_group('required arguments')
- requiredArgs.add_argument('-f', action='store', dest='fg_path',help='Enter foreground path (relative path)', required=True)
- requiredArgs.add_argument('-b', action='store', dest='bg_path', type=str, help='Enter background path (relative path)', required=True)
- requiredArgs.add_argument('-n', action='store', dest='number_of_layers', type=str, help='Enter number of layers in pyramid', required=True)
- requiredArgs.add_argument('-s', action='store', dest='shape', type=str, help='Enter shape for creating mask (rect/ellipse)', required=True)
- args = parser.parse_args()
- bg_path = args.bg_path
- fg_path = args.fg_path
- number_of_layers = int(args.number_of_layers)
- shape = args.shape
- fg = cv2.imread(fg_path)
- bg = cv2.imread(bg_path)
- print(fg.shape)
- print(bg.shape)
- img = fg.copy()
- imgC = fg.copy()
- drawing = False
- ix,iy = -1,-1
- xMask,yMask = -1,-1
- result = blend(bg, fg, number_of_layers, shape)
- cv2.imshow("Result", result)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement