import cv2
import numpy as np
import imgProcessor as iP
from imgProcessor.linearBlend import linearBlend
from imgProcessor.imgIO import imread
[docs]class StitchImages(object):
[docs] def __init__(self, img):
'''
Find the Overlap between image parts and stitch them at a given edge together.
There is no perspective correction.
@param img: the base image
'''
self.base_img_rgb = imread(img)
[docs] def addImg(self, img, side='bottom', overlap=50, overlapDeviation=0,
rotation=0, rotationDeviation=0, backgroundColor=None):
'''
@param side: 'left', 'right', 'top', 'bottom', default side is 'bottom'
@param overlap: overlap guess in pixels of both images
@param overLapDeviation uncertainty of overlap -> overlap in range(ov-deviation, ov+deviation)
@param rotation: max. rotational error between images
@param rotationDeviation: same as overLapDeviation, but for rotation
@param backgroundColor: if not None, treat this value as transparent within the stitching area
'''
img_rgb = imread(img)
if iP.ARRAYS_ORDER_IS_XY:
side = {'left':'top',
'right':'bottom',
'top':'left',
'bottom':'right'}[side]
#the following algorithm is based on side = 'bottom', so
if side in ('top', 'left'):
img_rgb,self.base_img_rgb = self.base_img_rgb, img_rgb
#rotate images if to be stitched 'left' or 'right'
if side in ('left','right'):
self.base_img_rgb = np.rot90(self.base_img_rgb,-1)
img_rgb = np.rot90(img_rgb,-1)
#check image shape
assert img_rgb.shape[1] == self.base_img_rgb.shape[1], 'image size must be identical in stitch-direction'
#find overlap
offsx, offsy, rot = self._findOverlap(img_rgb, overlap, overlapDeviation, rotation, rotationDeviation)
img_rgb = self._rotate(img_rgb, rot)
self._lastParams = (offsx, offsy, rot)
#move values in x axis:
img_rgb = np.roll(img_rgb, offsx)
#melt both images together
self.base_img_rgb = linearBlend(self.base_img_rgb, img_rgb, offsy, backgroundColor)
#rotate back if side='left' or 'right'
if side in ('left','right'):
self.base_img_rgb = np.rot90(self.base_img_rgb,1)#self.rotateImage(self.base_img_rgb,-90)
return self.base_img_rgb
@property
def lastParams(self):
return self._lastParams
@staticmethod
def _rotate(img, angle):
s = img.shape
if angle == 0:
return img
else:
M = cv2.getRotationMatrix2D((s[1]/2,s[0]/2),angle,1)
return cv2.warpAffine(img,M,(s[1],s[0]))
def _findOverlap(self, img_rgb, overlap, overlapDeviation, rotation, rotationDeviation):
'''
return offset(x,y) which fit best self._base_img
through template matching
'''
#get gray images
if len(img_rgb.shape) != len(img_rgb.shape):
raise Exception('number of channels(colors) for both images different')
if overlapDeviation == 0 and rotationDeviation==0:
return (0,overlap, rotation)
s = self.base_img_rgb.shape
ho = overlap*0.5
#create two image cuts to compare:
imgcut = self.base_img_rgb[s[0]-overlapDeviation-overlap:,:]
template = img_rgb[:overlap,ho:s[1]-ho]
if rotationDeviation == 0:
angles = [rotation]
else:
angles = np.linspace(rotation-rotationDeviation,rotation+rotationDeviation,int(rotationDeviation)*5)
results = []
locations = []
for a in angles:
rotTempl = self._rotate(template, a)
# Apply template Matching
res = cv2.matchTemplate(rotTempl.astype(np.float32),
imgcut.astype(np.float32),
cv2.TM_CCORR_NORMED)
results.append(res.mean())
locations.append(cv2.minMaxLoc(res)[-1])
i = np.argmax(results)
loc = locations[i]
offsx = int(round(loc[0]-ho))
offsy = overlapDeviation+overlap-loc[1]
#print 'offset x:%s, y:%s, rotation:%s' %(offsx, offsy, angles[i])
return offsx, offsy, angles[i]
if __name__ == '__main__':
from fancytools.os.PathStr import PathStr
d = PathStr('media').join('electroluminescence')
#STITCH BOTTOM
i1 = d.join('EL_module_a_dist.PNG')
i2 = d.join('EL_module_b_dist.PNG')
i3 = d.join('EL_module_c.PNG')
s = StitchImages(i1)
stitched = s.addImg(i2, side='bottom', overlap=50, overlapDeviation=20)
stitched = s.addImg(i3, side='bottom', overlap=50, overlapDeviation=20 )
cv2.namedWindow("bottom", cv2.cv.CV_WINDOW_NORMAL)
cv2.imshow('bottom',stitched)
#STITCH TOP
s = StitchImages(i3)
stitched = s.addImg(i2, side='top', overlap=50, overlapDeviation=20)
stitched = s.addImg(i1, side='top', overlap=50, overlapDeviation=20 )
cv2.namedWindow("top", cv2.cv.CV_WINDOW_NORMAL)
cv2.imshow('top',stitched)
#STITCH RIGHT
i1 = d.join('EL_module_a_dist2.PNG')
i2 = d.join('EL_module_b_dist2.PNG')
i3 = d.join('EL_module_c2.PNG')
s = StitchImages(i1)
s.addImg(i2, side='right', overlap=50, overlapDeviation=20)
stitched = s.addImg(i3, side='right', overlap=50, overlapDeviation=20)
cv2.namedWindow("right", cv2.cv.CV_WINDOW_NORMAL)
cv2.imshow('right',stitched)
#STITCH LEFT
s = StitchImages(i3)
stitched =s.addImg(i2, side='left', overlap=50, overlapDeviation=20)
stitched = s.addImg(i1, side='left', overlap=50, overlapDeviation=20)
cv2.namedWindow("left", cv2.cv.CV_WINDOW_NORMAL)
cv2.imshow('left',stitched)
cv2.waitKey()