Advertisement
akariya

[ECE558] Projec03 Image Blending

Nov 11th, 2019
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.70 KB | None | 0 0
  1. import cv2
  2. import numpy as np
  3. import sys
  4. import math
  5. import argparse
  6.  
  7. # function for 2d convolution (used as is from previous project)
  8. def conv2(img, kernel, padding_style):
  9.    
  10.     h, w = kernel.shape
  11.    
  12.     yO, xO, cO = img.shape
  13.  
  14.     paddedImg = np.zeros([yO + math.floor(h/2) + math.floor(h/2), xO + math.floor(w/2) + math.floor(w/2), cO], dtype='float32')
  15.     paddedImg[math.floor(h/2) : yO + math.floor(h/2),math.floor(w/2) : xO + math.floor(w/2),:] = img[:,:,:]
  16.    
  17.     # appply padding
  18.     if(padding_style == 'zero-padding'):
  19.         paddedImg = paddedImg
  20.     elif(padding_style == 'wrap-around'):
  21.         i = math.floor(w/2) - 1
  22.         j = xO + math.floor(w/2) - 1
  23.         while(i >= 0):
  24.             paddedImg[:,i,:] = paddedImg[:,j,:]
  25.             j -= 1
  26.             i -= 1
  27.         i = math.floor(h/2) - 1
  28.         j = yO + math.floor(w/2) - 1
  29.         while(i >= 0):
  30.             paddedImg[i,:,:] = paddedImg[j,:,:]
  31.             j -= 1
  32.             i -= 1
  33.         i = math.floor(w/2) + xO
  34.         j = math.floor(w/2)
  35.         while(i < paddedImg.shape[1]):
  36.             paddedImg[:,i,:] = paddedImg[:,j,:]
  37.             j += 1
  38.             i += 1
  39.         i = math.floor(h/2) + yO
  40.         j = math.floor(h/2)
  41.         while(i < paddedImg.shape[0]):
  42.             paddedImg[i,:,:] = paddedImg[j,:,:]
  43.             j += 1
  44.             i += 1
  45.     elif(padding_style == 'copy-edge'):
  46.         i = math.floor(w/2) - 1
  47.         j = math.floor(w/2)
  48.         while(i >= 0):
  49.             paddedImg[:,i,:] = paddedImg[:,j,:]
  50.             i -= 1
  51.         i = math.floor(h/2) - 1
  52.         j = math.floor(h/2)
  53.         while(i >= 0):
  54.             paddedImg[i,:,:] = paddedImg[j,:,:]
  55.             i -= 1
  56.         i = math.floor(w/2) + xO
  57.         j = xO + math.floor(w/2) - 1
  58.         while(i < paddedImg.shape[1]):
  59.             paddedImg[:,i,:] = paddedImg[:,j,:]
  60.             i += 1
  61.         i = math.floor(h/2) + yO
  62.         j = yO + math.floor(h/2) - 1
  63.         while(i < paddedImg.shape[0]):
  64.             paddedImg[i,:,:] = paddedImg[j,:,:]
  65.             i += 1
  66.     elif(padding_style == 'reflect-across-edge'):
  67.         i = math.floor(w/2) - 1
  68.         j = math.floor(w/2)
  69.         while(i >= 0):
  70.             paddedImg[:,i,:] = paddedImg[:,j,:]
  71.             j += 1
  72.             i -= 1
  73.         i = math.floor(h/2) - 1
  74.         j = math.floor(h/2)
  75.         while(i >= 0):
  76.             paddedImg[i,:,:] = paddedImg[j,:,:]
  77.             j += 1
  78.             i -= 1
  79.         i = math.floor(w/2) + xO
  80.         j = xO + math.floor(w/2) - 1
  81.         while(i < paddedImg.shape[1]):
  82.             paddedImg[:,i,:] = paddedImg[:,j,:]
  83.             j -= 1
  84.             i += 1
  85.         i = math.floor(h/2) + yO
  86.         j = yO + math.floor(h/2) - 1
  87.         while(i < paddedImg.shape[0]):
  88.             paddedImg[i,:,:] = paddedImg[j,:,:]
  89.             j -= 1
  90.             i += 1
  91.     img = paddedImg
  92.     y, x, c = img.shape
  93.     b, g, r = cv2.split(img)
  94.     channels = [b, g, r]
  95.    
  96.     if(all((r==b).flatten()) and all((g==b).flatten())):
  97.         img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  98.         c = 1
  99.  
  100.     # apply convlution by point wise multiplication in frequency domain
  101.     if(c == 1):
  102.         imgF = np.fft.fft2(img)
  103.         imgFS = np.fft.fftshift(imgF)
  104.         kernelF = np.fft.fft2(kernel, [y,x])
  105.         kernelFS = np.fft.fftshift(kernelF)
  106.         imgF = imgFS * kernelFS
  107.         imgishift = np.fft.ifftshift(imgF)
  108.         img = np.fft.ifft2(imgishift)
  109.         img = np.abs(img)
  110.  
  111.     elif(c == 3):
  112.         bF = np.fft.fft2(b)
  113.         bFS = np.fft.fftshift(bF)
  114.         kernelF = np.fft.fft2(kernel, [y,x])
  115.         kernelFS = np.fft.fftshift(kernelF)
  116.         bF = bFS * kernelFS
  117.         bishift = np.fft.ifftshift(bF)
  118.         b = np.fft.ifft2(bishift)
  119.         b = np.abs(b)
  120.  
  121.         gF = np.fft.fft2(g)
  122.         gFS = np.fft.fftshift(gF)
  123.         gF = gFS * kernelFS
  124.         gishift = np.fft.ifftshift(gF)
  125.         g = np.fft.ifft2(gishift)
  126.         g = np.abs(g)
  127.  
  128.         rF = np.fft.fft2(r)
  129.         rFS = np.fft.fftshift(rF)
  130.         rF = rFS * kernelFS
  131.         rishift = np.fft.ifftshift(rF)
  132.         r = np.fft.ifft2(rishift)
  133.         r = np.abs(r)
  134.         img = cv2.merge((b, g, r))
  135.  
  136.     img = img[h-1:h-1+yO, w-1:w-1+xO]
  137.    
  138.     return img
  139.  
  140. # function to resize using nearest neighbour interpolation
  141. def resize(img, newY, newX):
  142.    
  143.     res = np.zeros([newY, newX, img.shape[2]], dtype = 'uint8')
  144.     i = 0
  145.     factY = newY/img.shape[0]
  146.     factX = newX/img.shape[1]
  147.     while(i < newY):
  148.         j = 0
  149.         while(j < newX):
  150.             res[i][j][:] = img[math.floor(i/factY)][math.floor(j/factX)][:]
  151.             j += 1
  152.         i += 1
  153.     # kernel = gaussian_kernel(3,3)
  154.     # res = conv2(np.uint8(res), kernel, 'reflect-across-edge')
  155.     if(len(res.shape) == 2):
  156.         res = cv2.cvtColor(np.uint8(res),cv2.COLOR_GRAY2RGB)
  157.     return np.uint8(res)
  158.  
  159.  
  160. # function to generate gaussian kernel
  161. def gaussian_kernel(size, size_y):
  162.     size = int(size)
  163.     int(size_y)
  164.     x, y = np.mgrid[-size:size+1, -size_y:size_y+1]
  165.     g = np.exp(-(x**2/float(size)+y**2/float(size_y)))
  166.     return g / g.sum()
  167.  
  168. # function for pyramid down (like cv2.pyrDown)
  169. def pyrDown(img):
  170.     k = int((4 * 2 * 2 / 6) +0.5)
  171.     kernel = gaussian_kernel(k,k)
  172.     imgBlur = conv2(np.uint8(img), kernel, 'copy-edge')
  173.     if(len(imgBlur.shape) == 2):
  174.         imgBlur = cv2.cvtColor(np.uint8(imgBlur),cv2.COLOR_GRAY2RGB)
  175.     y, x, c = imgBlur.shape
  176.     # imgDS = cv2.resize(imgBlur, (round(y/2), round(x/2)), interpolation = cv2.INTER_NEAREST)
  177.     imgDS = resize(imgBlur, round(y/2), round(x/2))
  178.     return np.uint8(imgDS)
  179.  
  180. # function for pyramid up (like cv2.pyrUp)
  181. def pyrUp(img):
  182.     y, x, c = img.shape
  183.  
  184.     k = int((4 * 2 * 2 / 6) +0.5)
  185.     kernel = gaussian_kernel(k,k)
  186.     # imgUS = cv2.resize(img, (y*2, x*2), interpolation = cv2.INTER_NEAREST)
  187.     imgUS = resize(img, y*2, x*2)
  188.     imgUS = conv2(np.uint8(imgUS), kernel, 'copy-edge')
  189.     if(len(imgUS.shape) == 2):
  190.         imgUS = cv2.cvtColor(np.uint8(imgUS),cv2.COLOR_GRAY2RGB)
  191.     return np.uint8(imgUS)
  192.  
  193. # function to compute gaussian and laplacian pyramids of given image
  194. def computePyr(img, number_of_layers):
  195.     G = img.copy()
  196.     gPyr = [G]
  197.     max_num_of_layers = 0
  198.     for i in range(number_of_layers - 1):
  199.         G = pyrDown(G)
  200.         gPyr.append(G)
  201.         max_num_of_layers += 1
  202.         if(G.shape[0] == 1 or G.shape[1] == 1):
  203.             break
  204.  
  205.     lPyr = [gPyr[len(gPyr) - 1]]
  206.     L = lPyr[0]
  207.     for i in range(max_num_of_layers, 0, -1):
  208.         GE = pyrUp(gPyr[i])
  209.         L = cv2.subtract(gPyr[i-1],GE)
  210.         lPyr.append(L)
  211.        
  212.     return gPyr, lPyr
  213.  
  214. # mouse callback function to draw rectangle
  215. def draw_rect(event,x,y,flags,param):
  216.     global ix,iy,drawing,mode, img, imgC, xMask, yMask
  217.  
  218.     if event == cv2.EVENT_LBUTTONDOWN:
  219.         img = imgC.copy()
  220.         drawing = True
  221.         ix,iy = x,y
  222.  
  223.     elif event == cv2.EVENT_MOUSEMOVE:
  224.         xMask,yMask = x,y
  225.         if drawing == True:
  226.             img = imgC.copy()
  227.             cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),2)
  228.  
  229.     elif event == cv2.EVENT_LBUTTONUP:
  230.         xMask,yMask = x,y
  231.         drawing = False
  232.         cv2.rectangle(img,(ix,iy),(x,y),(0,255,0),2)
  233.  
  234. # mouse callback function to draw ellipse
  235. def draw_ellipse(event,x,y,flags,param):
  236.     global ix,iy,drawing,mode, img, imgC, xMask, yMask
  237.  
  238.     if event == cv2.EVENT_LBUTTONDOWN:
  239.         img = imgC.copy()
  240.         drawing = True
  241.         ix,iy = x,y
  242.     elif event == cv2.EVENT_MOUSEMOVE:
  243.         xMask,yMask = x,y
  244.         if drawing == True:
  245.             img = imgC.copy()
  246.             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)
  247.  
  248.     elif event == cv2.EVENT_LBUTTONUP:
  249.         xMask,yMask = x,y
  250.         drawing = False
  251.         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)
  252.  
  253. # function to create foreground mask using mouse callbacks
  254. def drawMask(fg, shape):
  255.     global ix,iy,drawing,mode, img, imgC, xMask, yMask
  256.     cv2.namedWindow('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue')
  257.     if(shape == 'rect'):
  258.         cv2.setMouseCallback('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue',draw_rect)
  259.     else:
  260.         cv2.setMouseCallback('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue',draw_ellipse)
  261.     while(1):
  262.         cv2.imshow('Drag Mouse to draw ' + shape + ' mask, press ENTER to continue',img)
  263.         k = cv2.waitKey(1) & 0xFF
  264.         if k == 13:
  265.             break
  266.  
  267.     cv2.destroyAllWindows()
  268.     # r = cv2.selectROI(fg, False)
  269.     fg_mask = np.zeros([fg.shape[0],fg.shape[1], fg.shape[2]], dtype = 'uint8')
  270.     if(shape == 'rect'):
  271.         fg_mask[iy:yMask,ix:xMask, :] = 255
  272.     else:
  273.         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)
  274.     return fg_mask
  275.  
  276. # function to blend 2 images
  277. def blend(bg, fg, number_of_layers, shape):
  278.     fg_mask = drawMask(fg, shape)
  279.     g_bg, l_bg = computePyr(bg, number_of_layers)
  280.     g_fg, l_fg = computePyr(fg, number_of_layers)
  281.     g_mask, l_mask = computePyr(fg_mask, number_of_layers)
  282.  
  283.     LS = []
  284.     i = len(g_mask) - 1
  285.     for l_b, l_f in zip(l_bg, l_fg):
  286.         y, x, c = l_b.shape
  287.         ls = (l_f * (g_mask[i]/255)) + (l_b * (1 - (g_mask[i]/255)))
  288.         LS.append(np.uint8(ls))
  289.         i -= 1
  290.     # now reconstruct
  291.     ls_ = LS[0]
  292.     for i in range(1,len(LS)):
  293.         ls_ = pyrUp(ls_)
  294.         ls_ = cv2.add(np.uint8(ls_), np.uint8(LS[i]))
  295.  
  296.     return ls_
  297.        
  298.  
  299. # driver code
  300.  
  301. parser = argparse.ArgumentParser(description='Pyramid Blending')
  302. requiredArgs = parser.add_argument_group('required arguments')
  303. requiredArgs.add_argument('-f', action='store', dest='fg_path',help='Enter foreground path (relative path)', required=True)
  304. requiredArgs.add_argument('-b', action='store', dest='bg_path', type=str, help='Enter background path (relative path)', required=True)
  305. requiredArgs.add_argument('-n', action='store', dest='number_of_layers', type=str, help='Enter number of layers in pyramid', required=True)
  306. requiredArgs.add_argument('-s', action='store', dest='shape', type=str, help='Enter shape for creating mask (rect/ellipse)', required=True)
  307. args = parser.parse_args()
  308. bg_path = args.bg_path
  309. fg_path = args.fg_path
  310. number_of_layers = int(args.number_of_layers)
  311. shape = args.shape
  312. fg = cv2.imread(fg_path)
  313. bg = cv2.imread(bg_path)
  314. print(fg.shape)
  315. print(bg.shape)
  316. img = fg.copy()
  317. imgC = fg.copy()
  318. drawing = False
  319. ix,iy = -1,-1
  320. xMask,yMask = -1,-1
  321. result = blend(bg, fg, number_of_layers, shape)
  322. cv2.imshow("Result", result)
  323. cv2.waitKey(0)
  324. cv2.destroyAllWindows()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement