-
-
Save alexlib/9156596592e6f0e7673fbd1457dd3680 to your computer and use it in GitHub Desktop.
A python min-max filter implementation after Adrain & Westerweel, "Particle image velocimetry", 2011, p.250.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cv2 | |
import numpy as np | |
def minMaxFilter(img, filterSize, minContrast): | |
""" | |
After R.Adrian, J.Westerweel, "Particle image velocimetry", Cambridge | |
university press, 2011. See ch.6.1.2, p.248-250. | |
Parameters: img (cv2.imread) - image to be filtered | |
filterSize (nd.array) - a 1x2 numpy array of the filter height | |
and width correspondingly | |
minContrast (float) - minimum contrast value imposed on the | |
image (if the calculated contrast falls | |
bellow this level, this level is imposed | |
as the contrast: see the referenced book) | |
Returns: imgFiltered (cv2.imread) - filtered image | |
""" | |
# cv2 doesn't have min and max filters, erode and dilate play the role of | |
# min and max filters correspondingly. Note, that, in opencv, erode and | |
# dilate can be implemented to gray scale images (recall, that normally | |
# they can only be implemented to binary images.) | |
# Define the lower and upper envelopes (see the book) of the image intensity | |
showWindowWell("original image", img, 0, 0) | |
low = cv2.erode(img, | |
cv2.getStructuringElement(cv2.MORPH_RECT, filterSize)) | |
showWindowWell("low before blurrig", low, 0, 0) | |
upp = cv2.dilate(img, | |
cv2.getStructuringElement(cv2.MORPH_RECT, filterSize)) | |
showWindowWell("upp before blurring", upp, 0, 0) | |
# Smooth the lower and upper envelopes with a uniform filter of the same size | |
low = lowPassFilter(low, filterSize) | |
showWindowWell("low after blurring", low, 0, 0) | |
upp = lowPassFilter(upp, filterSize) | |
showWindowWell("upp after blurring", upp, 0, 0) | |
# Define contrast and put a lower limit on it | |
contrast = cv2.subtract(upp, low) | |
showWindowWell("contrast before capping", contrast, 0, 0) | |
contrast[contrast < minContrast] = minContrast | |
showWindowWell("contrast after capping", contrast, 0, 0) | |
# Normalize image intensity, multiplication by 255 is necessary because | |
# if the pixel value of the original image is smaller than the corresponding | |
# value of the contrast, you get a less than 1 value after the division, | |
# which at the show image operation gets converted to 0 and you get black | |
# image | |
showWindowWell("img - low", cv2.subtract(img, low), 0, 0) | |
imgFiltered = cv2.divide(cv2.subtract(img, low), contrast) * 255 | |
showWindowWell("filtered image", cv2.subtract(img, low), 0, 0) | |
return imgFiltered | |
def showWindowWell(winname, img, x, y): | |
""" | |
cv2.imshow locates the image at the corner of the screen where I | |
can't see the full image. I have to relocate it programmatically. | |
This function wraps up all the image-showing and locating procedures to | |
ease image showing. | |
Note: don't forget to press "Enter" to close the window. | |
Parameters: winname (string) - the name of the window | |
img (cv2.imread) - the image I want to display in the window | |
x, y (int) - pixel coordinates of the window location in the | |
screen | |
Returns: none - just shows the image in the chosen location on the screen | |
""" | |
img = cv2.resize(img, (1200, 800)) # first, resize the image | |
cv2.namedWindow(winname) # second, create a window for the image | |
cv2.moveWindow(winname, x, y) # move it to (x,y) | |
cv2.imshow(winname, img) | |
cv2.waitKey() | |
cv2.destroyAllWindows() | |
def lowPassFilter(img_src, kernelSize): | |
""" | |
This is a uniform low pass filter, which measn that all the values in the | |
filter kernel are equal to 1. | |
Parameters: img_src (cv2.imread) - image to be filtered | |
kernelSize (nd.array) - 1x2 numpy array where the first value is | |
the kernel's height, the second value is | |
the kernel's width | |
Returns: img_rst (cv2.imread) - filtered image | |
""" | |
kernel = np.ones(kernelSize) | |
kernel = kernel/(np.sum(kernel) if np.sum(kernel)!=0 else 1) | |
img_rst = cv2.filter2D(img_src, -1, kernel) | |
return img_rst |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment