From ba25dcc39da9b502541653b5d30ac61aa26e6019 Mon Sep 17 00:00:00 2001 From: Dzmitry Paulenka Date: Mon, 16 Dec 2019 20:22:11 +0300 Subject: [PATCH] Software update --- .../data/2019.12.16-opencv-filtering-gui.png | Bin 0 -> 50859 bytes opencv_filtering/opencv/logic_filters.py | 85 ++++++++--- opencv_filtering/readme.md | 2 +- simple_scripts/slic_segmentation.py | 135 ++++++++++++++++++ 4 files changed, 201 insertions(+), 21 deletions(-) create mode 100755 opencv_filtering/data/2019.12.16-opencv-filtering-gui.png create mode 100755 simple_scripts/slic_segmentation.py diff --git a/opencv_filtering/data/2019.12.16-opencv-filtering-gui.png b/opencv_filtering/data/2019.12.16-opencv-filtering-gui.png new file mode 100755 index 0000000000000000000000000000000000000000..fb717480f8d1c56d375925299e90c2259f579d08 GIT binary patch literal 50859 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 z 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 PfS1A>73dG}`+)xkgV2S* literal 0 HcmV?d00001 diff --git a/opencv_filtering/opencv/logic_filters.py b/opencv_filtering/opencv/logic_filters.py index b99e40a..4cd1794 100755 --- a/opencv_filtering/opencv/logic_filters.py +++ b/opencv_filtering/opencv/logic_filters.py @@ -48,11 +48,12 @@ def __init__(self, master, filter_num=0): ['Canny', self.filter_canny, 'Canny edge detection'], ['Threshold', self.filter_threshold, 'Adaptive Gaussian threshold'], ['Harris', self.filter_harris, 'Harris corner detection'], - ['SIFT', self.filter_sift, 'Scale-Invariant Feature Transform (SIFT), patented'], - ['SURF', self.filter_surf, 'Speeded-Up Robust Features (SURF), patented'], - ['ORB', self.filter_orb, 'Oriented FAST and Rotated BRIEF (ORB), free'], + ['SIFT', self.filter_sift, 'SIFT (Scale-Invariant Feature Transform) algorithm, patented'], + ['SURF', self.filter_surf, 'SURF (Speeded-Up Robust Features) algorithm, patented'], + ['ORB', self.filter_orb, 'ORB (Oriented FAST and Rotated BRIEF) algorithm, free'], ['BRIEF', self.filter_brief, 'BRIEF descriptors with the help of CenSurE (STAR) detector'], ['Contours', self.filter_contours, 'Draw contours with mean colors inside them'], + ['SEEDS', self.filter_seeds, 'SEEDS (Superpixels Extracted via Energy-Driven Sampling) algorithm'], ['Blur', self.filter_blur, 'Blur (Gaussian, median, bilateral or classic)'], ['Motion', self.filter_motion, 'Motion detection'], ['Background', self.filter_background, 'Background subtractor (KNN, MOG2, MOG or GMG)'], @@ -62,7 +63,7 @@ def __init__(self, master, filter_num=0): ['Affine2', self.filter_affine2, 'Affine random transformations'], ['Perspective', self.filter_perspective, 'Perspective random transformations'], ['Equalize', self.filter_equalize, 'Histogram Equalization'], - ['CLAHE', self.filter_clahe, 'Contrast Limited Adaptive Histogram Equalization (CLAHE)'], + ['CLAHE', self.filter_clahe, 'CLAHE (Contrast Limited Adaptive Histogram Equalization) algorithm'], ['LAB', self.filter_lab, 'Increase the contrast using LAB color space and CLAHE'], ['Pyramid', self.filter_pyramid, 'Image pyramid'], ['Laplacian', self.filter_laplacian, 'Laplacian gradient filter'], @@ -108,17 +109,17 @@ def filter_unchanged(self): def filter_canny(self): """ Canny edge detection """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # convert to gray scale + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # convert to gray scale return cv2.Canny(gray, 50, 200) # Canny edge detection def filter_threshold(self): """ Adaptive Gaussian threshold """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # convert to gray scale + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # convert to gray scale return cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) def filter_harris(self): """ Harris corner detection """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # convert to gray scale + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # convert to gray scale gray = np.float32(gray) # convert to NumPy array # k-size parameter is odd and must be [3, 31] dest = cv2.cornerHarris(src=gray, blockSize=2, ksize=5, k=0.07) @@ -128,7 +129,7 @@ def filter_harris(self): def get_features(self, xfeatures): """ Keypoints / features for SIFT, SURF and ORB filters """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # convert to gray scale + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # convert to gray scale keypoints, descriptor = xfeatures.detectAndCompute(gray, None) return cv2.drawKeypoints(image=self.frame, outImage=self.frame, keypoints=keypoints, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS, color=(51, 163, 236)) @@ -153,7 +154,7 @@ def filter_orb(self): def filter_brief(self): """ BRIEF descriptors with the help of CenSurE (STAR) detector """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # convert to gray scale + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # convert to gray scale keypoints = cv2.xfeatures2d.StarDetector_create().detect(gray, None) keypoints, descriptor = cv2.xfeatures2d.BriefDescriptorExtractor_create().compute(gray, keypoints) return cv2.drawKeypoints(image=self.frame, outImage=self.frame, keypoints=keypoints, @@ -161,7 +162,7 @@ def filter_brief(self): def filter_contours(self): """ Draw contours with mean colors inside them """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # convert to gray scale + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # convert to gray scale frame = self.frame.copy() # make a copy for threshold in [15, 50, 100, 240]: # use various thresholds ret, thresh = cv2.threshold(gray, threshold, 255, 0) @@ -175,6 +176,50 @@ def filter_contours(self): cv2.drawContours(frame, contours, -1, (0, 0, 0), 1) # draw contours with black color return frame + def filter_seeds(self): + """ SEEDS (Superpixels Extracted via Energy-Driven Sampling) algorithm """ + display_mode = 1 # display mode for SEEDS algorithm + num_superpixels = 400 + prior = 2 + num_levels = 4 + histogram_bins = 5 + num_iterations = 4 + + frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2HSV) + height, width, channels = frame.shape + + seeds = cv2.ximgproc.createSuperpixelSEEDS( + width, height, channels, num_superpixels, num_levels, prior, histogram_bins) + + seeds.iterate(frame, num_iterations) + mask = seeds.getLabelContourMask(False) + + if display_mode == 0: + frame = cv2.cvtColor(frame, cv2.COLOR_HSV2RGB) # convert back to RGB + # Set superpixels color + color_img = np.zeros((height, width, 3), np.uint8) + color_img[:] = (255, 0, 0) + # Stitch foreground & background together + mask_inv = cv2.bitwise_not(mask) + result_bg = cv2.bitwise_and(frame, frame, mask=mask_inv) + result_fg = cv2.bitwise_and(color_img, color_img, mask=mask) + result = cv2.add(result_bg, result_fg) + return result + elif display_mode == 1: + labels = seeds.getLabels() # get superpixels + # Calculate average color of a superpixel in scikit-image library + reshaped = frame.reshape((height * width, channels)) + frame_1d = np.reshape(labels, -1) + uni = np.unique(frame_1d) + mask = np.zeros(reshaped.shape) + for i in uni: + loc = np.where(frame_1d == i)[0] + mask[loc, :] = np.mean(reshaped[loc, :], axis=0) + frame = np.reshape(mask, [height, width, channels]).astype('uint8') + return cv2.cvtColor(frame, cv2.COLOR_HSV2RGB) + else: + return mask + def filter_blur(self): """ Blur (Gaussian, median, bilateral or classic) """ # return cv2.GaussianBlur(self.frame, (29, 29), 0) # Gaussian blur @@ -187,8 +232,8 @@ def filter_motion(self): if self.previous is None or self.previous.shape != self.frame.shape: self.previous = self.frame.copy() # remember previous frame return self.frame # return unchanged frame - gray1 = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) # convert to grayscale - gray2 = cv2.cvtColor(self.previous, cv2.COLOR_BGR2GRAY) + gray1 = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # convert to grayscale + gray2 = cv2.cvtColor(self.previous, cv2.COLOR_RGB2GRAY) self.previous = self.frame.copy() # remember previous frame return cv2.absdiff(gray1, gray2) # get absolute difference between two frames @@ -200,7 +245,7 @@ def filter_background(self): # self.background_subtractor = cv2.bgsegm.createBackgroundSubtractorGMG() # self.background_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG() fgmask = self.background_subtractor.apply(self.frame) - return self.frame & cv2.cvtColor(fgmask, cv2.COLOR_GRAY2BGR) + return self.frame & cv2.cvtColor(fgmask, cv2.COLOR_GRAY2RGB) def filter_skin(self): """ Skin tones detection""" @@ -208,7 +253,7 @@ def filter_skin(self): lower = np.array([0, 100, 0], dtype='uint8') upper = np.array([50, 255, 255], dtype='uint8') # Switch to HSV - hsv = cv2.cvtColor(self.frame, cv2.COLOR_BGR2HSV) + hsv = cv2.cvtColor(self.frame, cv2.COLOR_RGB2HSV) # Find mask of pixels within HSV range skin_mask = cv2.inRange(hsv, lower, upper) skin_mask = cv2.GaussianBlur(skin_mask, (9, 9), 0) # noise suppression @@ -222,7 +267,7 @@ def filter_skin(self): def filter_optflow(self): """ Lucas Kanade optical flow """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) frame = self.frame.copy() # copy the frame if self.previous is None or self.previous.shape != gray.shape: self.previous = gray.copy() # save previous gray frame @@ -326,12 +371,12 @@ def filter_clahe(self): def filter_lab(self): """ Increase the contrast using LAB color space and CLAHE """ - lab = cv2.cvtColor(self.frame, cv2.COLOR_BGR2LAB) # convert image to LAB color model + lab = cv2.cvtColor(self.frame, cv2.COLOR_RGB2LAB) # convert image to LAB color model l, a, b = cv2.split(lab) # split on l, a, b channels clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8)) l2 = clahe.apply(l) # apply CLAHE to L-channel lab = cv2.merge((l2, a, b)) # merge enhanced L-channel with the a and b channels - return cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) # convert back to BGR and return + return cv2.cvtColor(lab, cv2.COLOR_LAB2RGB) # convert back to RGB and return def filter_pyramid(self): """ Image pyramid """ @@ -349,13 +394,13 @@ def filter_pyramid(self): def filter_laplacian(self): """ Laplacian gradient filter """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # return cv2.Laplacian(gray, cv2.CV_8U) return np.uint8(np.absolute(cv2.Laplacian(gray, cv2.CV_64F))) def filter_sobel_x(self): """ Sobel / Scharr vertical gradient filter """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # return cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize=5) # return np.uint8(np.absolute(cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=5))) # return np.uint8(np.absolute(cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=-1))) @@ -364,7 +409,7 @@ def filter_sobel_x(self): def filter_sobel_y(self): """ Sobel / Scharr horizontal gradient filter """ - gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY) + gray = cv2.cvtColor(self.frame, cv2.COLOR_RGB2GRAY) # return cv2.Sobel(gray, cv2.CV_8U, 0, 1, ksize=5) # return np.uint8(np.absolute(cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=5))) # reutnr np.uint8(np.absolute(cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=-1))) diff --git a/opencv_filtering/readme.md b/opencv_filtering/readme.md index 7809e36..1e59a1b 100755 --- a/opencv_filtering/readme.md +++ b/opencv_filtering/readme.md @@ -1,6 +1,6 @@ #### OpenCV Filtering GUI application -![OpenCV Filtering GUI](data/2019.09.29-opencv-filtering-gui.png) +![OpenCV Filtering GUI](data/2019.12.16-opencv-filtering-gui.png) OpenCV Filtering GUI is a set of various realtime filters to process images from the webcam. diff --git a/simple_scripts/slic_segmentation.py b/simple_scripts/slic_segmentation.py new file mode 100755 index 0000000..a9ec7cd --- /dev/null +++ b/simple_scripts/slic_segmentation.py @@ -0,0 +1,135 @@ +# SLIC (Simple Linear Iterative Clustering) segmentation algorithm. +# Original link: https://stackoverflow.com/a/57746835/7550928 +import numpy as np +import cv2 +from skimage import segmentation +from skimage.segmentation import mark_boundaries +from skimage.data import astronaut + + +def slic_segmentation(image, segments): + """ Calculate average color of a superpixel in scikit-image library """ + reshaped = image.reshape((image.shape[0]*image.shape[1], image.shape[2])) + slic_1d = np.reshape(segments, -1) + uni = np.unique(slic_1d) + mask = np.zeros(reshaped.shape) + for i in uni: + loc = np.where(slic_1d==i)[0] + mask[loc, :] = np.mean(reshaped[loc, :], axis=0) + return np.reshape(mask, [image.shape[0], image.shape[1], image.shape[2]]).astype('uint8') + + +input = cv2.cvtColor(astronaut(), cv2.COLOR_BGR2RGB) +segments = segmentation.slic(input, compactness=10, n_segments=1000, sigma=3) +output = slic_segmentation(input, segments) + +cv2.imshow('Original image', input) +cv2.imshow('SLIC segmentation', output) +cv2.imshow('With boundaries', mark_boundaries(input, segments)) + +cv2.waitKey(0) # press any key to close the window +cv2.destroyAllWindows() + + +if __name__ == '__main__': + def nothing(*arg): + pass + + cv2.namedWindow('SEEDS') + cv2.createTrackbar('Number of Superpixels', 'SEEDS', 400, 1000, nothing) + cv2.createTrackbar('Iterations', 'SEEDS', 4, 12, nothing) + + seeds = None + display_mode = 0 + num_superpixels = 400 + prior = 2 + num_levels = 4 + num_histogram_bins = 5 + + cap = cv2.VideoCapture(0) # get default camera + while True: + flag, img = cap.read() + converted_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + height, width, channels = converted_img.shape + num_superpixels_new = cv2.getTrackbarPos('Number of Superpixels', 'SEEDS') + num_iterations = cv2.getTrackbarPos('Iterations', 'SEEDS') + + if not seeds or num_superpixels_new != num_superpixels: + num_superpixels = num_superpixels_new + + seeds = cv2.ximgproc.createSuperpixelSEEDS( + width, height, channels, num_superpixels, num_levels, prior, num_histogram_bins) + + color_img = np.zeros((height, width, 3), np.uint8) + color_img[:] = (0, 0, 255) + seeds.iterate(converted_img, num_iterations) + mask = seeds.getLabelContourMask(False) + + if display_mode == 0: + # Stitch foreground & background together + mask_inv = cv2.bitwise_not(mask) + result_bg = cv2.bitwise_and(img, img, mask=mask_inv) + result_fg = cv2.bitwise_and(color_img, color_img, mask=mask) + result = cv2.add(result_bg, result_fg) + cv2.imshow('SEEDS', result) + elif display_mode == 1: + labels = seeds.getLabels() + segments = slic_segmentation(img, labels) + cv2.imshow('SEEDS', segments) + else: + cv2.imshow('SEEDS', mask) + + ch = cv2.waitKey(1) + if ch == 27: + break + elif ch & 0xff == ord(' '): + display_mode = (display_mode + 1) % 3 + cv2.destroyAllWindows() + + + def nothing(*arg): + pass + + cv2.namedWindow('SLIC') + cv2.createTrackbar('Region Size', 'SLIC', 32, 100, nothing) + + seeds = None + display_mode = 0 + region_size = 32 + + cap = cv2.VideoCapture(0) # get default camera + while True: + flag, img = cap.read() + converted_img = cv2.GaussianBlur(img, (5, 5), 0) # gaussian blur + converted_img = cv2.cvtColor(converted_img, cv2.COLOR_BGR2LAB) # convert to LAB + height, width, channels = converted_img.shape + region_size_new = cv2.getTrackbarPos('Region Size', 'SLIC') + + if not seeds or region_size_new != region_size: + region_size = region_size_new + + seeds = cv_slic = cv2.ximgproc.createSuperpixelSLIC( + converted_img, algorithm=cv2.ximgproc.SLICO, region_size=region_size) + + color_img = np.zeros((height, width, 3), np.uint8) + color_img[:] = (0, 0, 255) + seeds.iterate() + mask = seeds.getLabelContourMask(False) + + # Stitch foreground & background together + mask_inv = cv2.bitwise_not(mask) + result_bg = cv2.bitwise_and(img, img, mask=mask_inv) + result_fg = cv2.bitwise_and(color_img, color_img, mask=mask) + result = cv2.add(result_bg, result_fg) + + if display_mode == 0: + cv2.imshow('SLIC', result) + else: + cv2.imshow('SLIC', mask) + + ch = cv2.waitKey(1) + if ch == 27: + break + elif ch & 0xff == ord(' '): + display_mode = (display_mode + 1) % 2 + cv2.destroyAllWindows()