# author: Adrian Rosebrock # website: http://www.pyimagesearch.com # import the necessary packages import numpy as np import cv2 import sys # import any special Python 2.7 packages if sys.version_info.major == 2: from urllib import urlopen # import any special Python 3 packages elif sys.version_info.major == 3: from urllib.request import urlopen def translate(image, x, y): # define the translation matrix and perform the translation M = np.float32([[1, 0, x], [0, 1, y]]) shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0])) # return the translated image return shifted def rotate(image, angle, center=None, scale=1.0): # grab the dimensions of the image (h, w) = image.shape[:2] # if the center is None, initialize it as the center of # the image if center is None: center = (w // 2, h // 2) # perform the rotation M = cv2.getRotationMatrix2D(center, angle, scale) rotated = cv2.warpAffine(image, M, (w, h)) # return the rotated image return rotated def rotate_bound(image, angle): # grab the dimensions of the image and then determine the # center (h, w) = image.shape[:2] (cX, cY) = (w / 2, h / 2) # grab the rotation matrix (applying the negative of the # angle to rotate clockwise), then grab the sine and cosine # (i.e., the rotation components of the matrix) M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0) cos = np.abs(M[0, 0]) sin = np.abs(M[0, 1]) # compute the new bounding dimensions of the image nW = int((h * sin) + (w * cos)) nH = int((h * cos) + (w * sin)) # adjust the rotation matrix to take into account translation M[0, 2] += (nW / 2) - cX M[1, 2] += (nH / 2) - cY # perform the actual rotation and return the image return cv2.warpAffine(image, M, (nW, nH)) def resize(image, width=None, height=None, inter=cv2.INTER_AREA): # initialize the dimensions of the image to be resized and # grab the image size dim = None (h, w) = image.shape[:2] # if both the width and height are None, then return the # original image if width is None and height is None: return image # check to see if the width is None if width is None: # calculate the ratio of the height and construct the # dimensions r = height / float(h) dim = (int(w * r), height) # otherwise, the height is None else: # calculate the ratio of the width and construct the # dimensions r = width / float(w) dim = (width, int(h * r)) # resize the image resized = cv2.resize(image, dim, interpolation=inter) # return the resized image return resized def skeletonize(image, size, structuring=cv2.MORPH_RECT): # determine the area (i.e. total number of pixels in the image), # initialize the output skeletonized image, and construct the # morphological structuring element area = image.shape[0] * image.shape[1] skeleton = np.zeros(image.shape, dtype="uint8") elem = cv2.getStructuringElement(structuring, size) # keep looping until the erosions remove all pixels from the # image while True: # erode and dilate the image using the structuring element eroded = cv2.erode(image, elem) temp = cv2.dilate(eroded, elem) # subtract the temporary image from the original, eroded # image, then take the bitwise 'or' between the skeleton # and the temporary image temp = cv2.subtract(image, temp) skeleton = cv2.bitwise_or(skeleton, temp) image = eroded.copy() # if there are no more 'white' pixels in the image, then # break from the loop if area == area - cv2.countNonZero(image): break # return the skeletonized image return skeleton def opencv2matplotlib(image): # OpenCV represents images in BGR order; however, Matplotlib # expects the image in RGB order, so simply convert from BGR # to RGB and return return cv2.cvtColor(image, cv2.COLOR_BGR2RGB) def url_to_image(url, readFlag=cv2.IMREAD_COLOR): # download the image, convert it to a NumPy array, and then read # it into OpenCV format resp = urlopen(url) image = np.asarray(bytearray(resp.read()), dtype="uint8") image = cv2.imdecode(image, readFlag) # return the image return image def auto_canny(image, sigma=0.33): # compute the median of the single channel pixel intensities v = np.median(image) # apply automatic Canny edge detection using the computed median lower = int(max(0, (1.0 - sigma) * v)) upper = int(min(255, (1.0 + sigma) * v)) edged = cv2.Canny(image, lower, upper) # return the edged image return edged def grab_contours(cnts): # if the length the contours tuple returned by cv2.findContours # is '2' then we are using either OpenCV v2.4, v4-beta, or # v4-official if len(cnts) == 2: cnts = cnts[0] # if the length of the contours tuple is '3' then we are using # either OpenCV v3, v4-pre, or v4-alpha elif len(cnts) == 3: cnts = cnts[1] # otherwise OpenCV has changed their cv2.findContours return # signature yet again and I have no idea WTH is going on else: raise Exception(("Contours tuple must have length 2 or 3, " "otherwise OpenCV changed their cv2.findContours return " "signature yet again. Refer to OpenCV's documentation " "in that case")) # return the actual contours array return cnts def is_cv2(or_better=False): # grab the OpenCV major version number major = get_opencv_major_version() # check to see if we are using *at least* OpenCV 2 if or_better: return major >= 2 # otherwise we want to check for *strictly* OpenCV 2 return major == 2 def is_cv3(or_better=False): # grab the OpenCV major version number major = get_opencv_major_version() # check to see if we are using *at least* OpenCV 3 if or_better: return major >= 3 # otherwise we want to check for *strictly* OpenCV 3 return major == 3 def is_cv4(or_better=False): # grab the OpenCV major version number major = get_opencv_major_version() # check to see if we are using *at least* OpenCV 4 if or_better: return major >= 4 # otherwise we want to check for *strictly* OpenCV 4 return major == 4 def get_opencv_major_version(lib=None): # if the supplied library is None, import OpenCV if lib is None: import cv2 as lib # return the major version number return int(lib.__version__.split(".")[0]) def check_opencv_version(major, lib=None): # this function may be removed in a future release as we now # use the get_opencv_major_function to obtain the current OpenCV # version and then perform the actual version check *within* the # respective function import warnings message = """ The check_opencv_version function is deprecated and may be removed in a future release. Use at your own risk. """ warnings.warn(message, DeprecationWarning, stacklevel=2) # if the supplied library is None, import OpenCV if lib is None: import cv2 as lib # return whether or not the current OpenCV version matches the # major version number return lib.__version__.startswith(major) def build_montages(image_list, image_shape, montage_shape): """ --------------------------------------------------------------------------------------------- author: Kyle Hounslow --------------------------------------------------------------------------------------------- Converts a list of single images into a list of 'montage' images of specified rows and columns. A new montage image is started once rows and columns of montage image is filled. Empty space of incomplete montage images are filled with black pixels --------------------------------------------------------------------------------------------- :param image_list: python list of input images :param image_shape: tuple, size each image will be resized to for display (width, height) :param montage_shape: tuple, shape of image montage (width, height) :return: list of montage images in numpy array format --------------------------------------------------------------------------------------------- example usage: # load single image img = cv2.imread('lena.jpg') # duplicate image 25 times num_imgs = 25 img_list = [] for i in xrange(num_imgs): img_list.append(img) # convert image list into a montage of 256x256 images tiled in a 5x5 montage montages = make_montages_of_images(img_list, (256, 256), (5, 5)) # iterate through montages and display for montage in montages: cv2.imshow('montage image', montage) cv2.waitKey(0) ---------------------------------------------------------------------------------------------- """ if len(image_shape) != 2: raise Exception('image shape must be list or tuple of length 2 (rows, cols)') if len(montage_shape) != 2: raise Exception('montage shape must be list or tuple of length 2 (rows, cols)') image_montages = [] # start with black canvas to draw images onto montage_image = np.zeros(shape=(image_shape[1] * (montage_shape[1]), image_shape[0] * montage_shape[0], 3), dtype=np.uint8) cursor_pos = [0, 0] start_new_img = False for img in image_list: if type(img).__module__ != np.__name__: raise Exception('input of type {} is not a valid numpy array'.format(type(img))) start_new_img = False img = cv2.resize(img, image_shape) # draw image to black canvas montage_image[cursor_pos[1]:cursor_pos[1] + image_shape[1], cursor_pos[0]:cursor_pos[0] + image_shape[0]] = img cursor_pos[0] += image_shape[0] # increment cursor x position if cursor_pos[0] >= montage_shape[0] * image_shape[0]: cursor_pos[1] += image_shape[1] # increment cursor y position cursor_pos[0] = 0 if cursor_pos[1] >= montage_shape[1] * image_shape[1]: cursor_pos = [0, 0] image_montages.append(montage_image) # reset black canvas montage_image = np.zeros(shape=(image_shape[1] * (montage_shape[1]), image_shape[0] * montage_shape[0], 3), dtype=np.uint8) start_new_img = True if start_new_img is False: image_montages.append(montage_image) # add unfinished montage return image_montages def adjust_brightness_contrast(image, brightness=0., contrast=0.): """ Adjust the brightness and/or contrast of an image :param image: OpenCV BGR image :param contrast: Float, contrast adjustment with 0 meaning no change :param brightness: Float, brightness adjustment with 0 meaning no change """ beta = 0 # See the OpenCV docs for more info on the `beta` parameter to addWeighted # https://docs.opencv.org/3.4.2/d2/de8/group__core__array.html#gafafb2513349db3bcff51f54ee5592a19 return cv2.addWeighted(image, 1 + float(contrast) / 100., image, beta, float(brightness))