diff --git a/README.md b/README.md index cd0b52e..dbb8421 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ A series of convenience functions to make basic image processing functions such For more information, along with a detailed code review check out the following posts on the [PyImageSearch.com](http://www.pyimagesearch.com) blog: - [http://www.pyimagesearch.com/2015/02/02/just-open-sourced-personal-imutils-package-series-opencv-convenience-functions/](http://www.pyimagesearch.com/2015/02/02/just-open-sourced-personal-imutils-package-series-opencv-convenience-functions/) +- [http://www.pyimagesearch.com/2015/03/02/convert-url-to-image-with-python-and-opencv/](http://www.pyimagesearch.com/2015/03/02/convert-url-to-image-with-python-and-opencv/) +- [http://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/](http://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/) +- [http://www.pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/](http://www.pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/) ## Translation Translation is the shifting of an image in either the *x* or *y* direction. To translate an image in OpenCV you would need to supply the *(x, y)*-shift, denoted as *(tx, ty)* to construct the translation matrix *M*: @@ -50,7 +53,7 @@ for width in (400, 300, 200, 100): Resizing example ## Skeletonization -Skeletonization is the process of constructing the "topological skeleton" of an object in an image, where the object is presumed to be white on a black background. OpenCV does not provide a function to explicity construct the skeleton, but does provide the morphological and binary functions to do so. +Skeletonization is the process of constructing the "topological skeleton" of an object in an image, where the object is presumed to be white on a black background. OpenCV does not provide a function to explicitly construct the skeleton, but does provide the morphological and binary functions to do so. For convenience, the `skeletonize` function of `imutils` can be used to construct the topological skeleton of the image. @@ -80,3 +83,45 @@ plt.show() #### Output: Matplotlib example + +## URL to Image +This the `url_to_image` function accepts a single parameter: the `url` of the image we want to download and convert to a NumPy array in OpenCV format. This function performs the download in-memory. The `url_to_image` function has been detailed [here](http://www.pyimagesearch.com/2015/03/02/convert-url-to-image-with-python-and-opencv/) on the PyImageSearch blog. + +#### Example: +
url = "http://pyimagesearch.com/static/pyimagesearch_logo_github.png"
+logo = imutils.url_to_image(url)
+cv2.imshow("URL to Image", logo)
+cv2.waitKey(0)
+ +#### Output: +Matplotlib example + +## Automatic Canny Edge Detection +The Canny edge detector requires two parameters when performing hysteresis. However, tuning these two parameters to obtain an optimal edge map is non-trivial, especially when working with a dataset of images. Instead, we can use the `auto_canny` function which uses the median of the grayscale pixel intensities to derive the upper and lower thresholds. You can read more about the `auto_canny` function [here](http://www.pyimagesearch.com/2015/04/06/zero-parameter-automatic-canny-edge-detection-with-python-and-opencv/). + +#### Example: +
gray = cv2.cvtColor(logo, cv2.COLOR_BGR2GRAY)
+edgeMap = imutils.auto_canny(gray)
+cv2.imshow("Original", logo)
+cv2.imshow("Automatic Edge Map", edgeMap)
+ +#### Output: +Matplotlib example + +## 4-point Perspective Transform +A common task in computer vision and image processing is to perform a 4-point perspective transform of a ROI in an image and obtain a top-down, "birds eye view" of the ROI. The `perspective` module takes care of this for you. A real-world example of applying a 4-point perspective transform can be bound in this blog on on [building a kick-ass mobile document scanner](http://www.pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/). + +#### Example +See the contents of `demos/perspective_transform.py` + +#### Output: +Matplotlib example + +## Sorting Contours +The contours returned from `cv2.findContours` are unsorted. By using the `contours` module the the `sort_contours` function we can sort a list of contours from left-to-right, right-to-left, top-to-bottom, and bottom-to-top, respectively. + +#### Example: +See the contents of `demos/sorting_contours.py` + +#### Output: +Matplotlib example \ No newline at end of file diff --git a/demo.py b/demos/image_basics.py similarity index 68% rename from demo.py rename to demos/image_basics.py index eea7781..eb0d498 100644 --- a/demo.py +++ b/demos/image_basics.py @@ -2,7 +2,8 @@ # website: http://www.pyimagesearch.com # USAGE -# python demo.py +# BE SURE TO INSTALL 'imutils' PRIOR TO EXECUTING THIS COMMAND +# python image_basics.py # import the necessary packages import matplotlib.pyplot as plt @@ -10,10 +11,10 @@ import cv2 # load the example images -bridge = cv2.imread("demo_images/bridge.jpg") -cactus = cv2.imread("demo_images/cactus.jpg") -logo = cv2.imread("demo_images/pyimagesearch_logo.jpg") -workspace = cv2.imread("demo_images/workspace.jpg") +bridge = cv2.imread("../demo_images/bridge.jpg") +cactus = cv2.imread("../demo_images/cactus.jpg") +logo = cv2.imread("../demo_images/pyimagesearch_logo.jpg") +workspace = cv2.imread("../demo_images/workspace.jpg") # 1. TRANSLATION # show the original image @@ -69,4 +70,21 @@ # CORRECT: convert color spaces before using plt.imshow plt.figure("Correct") plt.imshow(imutils.opencv2matplotlib(cactus)) -plt.show() \ No newline at end of file +plt.show() + +# 6. URL TO IMAGE +# load an image from a URL, convert it to OpenCV, format, and +# display it +url = "http://pyimagesearch.com/static/pyimagesearch_logo_github.png" +logo = imutils.url_to_image(url) +cv2.imshow("URL to Image", logo) +cv2.waitKey(0) +cv2.destroyAllWindows() + +# 7. AUTO CANNY +# convert the logo to grayscale and automatically detect edges +gray = cv2.cvtColor(logo, cv2.COLOR_BGR2GRAY) +edgeMap = imutils.auto_canny(gray) +cv2.imshow("Original", logo) +cv2.imshow("Automatic Edge Map", edgeMap) +cv2.waitKey(0) \ No newline at end of file diff --git a/demos/perspective_transform.py b/demos/perspective_transform.py new file mode 100644 index 0000000..f7772e4 --- /dev/null +++ b/demos/perspective_transform.py @@ -0,0 +1,30 @@ +# author: Adrian Rosebrock +# website: http://www.pyimagesearch.com + +# USAGE +# BE SURE TO INSTALL 'imutils' PRIOR TO EXECUTING THIS COMMAND +# python perspective_transform.py + +# import the necessary packages +from imutils import perspective +import numpy as np +import cv2 + +# load the notecard code image, clone it, and initialize the 4 points +# that correspond to the 4 corners of the notecard +notecard = cv2.imread("../demo_images/notecard.png") +clone = notecard.copy() +pts = np.array([(73, 239), (356, 117), (475, 265), (187, 443)]) + +# loop over the points and draw them on the cloned image +for (x, y) in pts: + cv2.circle(clone, (x, y), 5, (0, 255, 0), -1) + +# apply the four point tranform to obtain a "birds eye view" of +# the notecard +warped = perspective.four_point_transform(notecard, pts) + +# show the original and warped images +cv2.imshow("Original", clone) +cv2.imshow("Warped", warped) +cv2.waitKey(0) \ No newline at end of file diff --git a/demos/sorting_contours.py b/demos/sorting_contours.py new file mode 100644 index 0000000..db33002 --- /dev/null +++ b/demos/sorting_contours.py @@ -0,0 +1,45 @@ +# author: Adrian Rosebrock +# website: http://www.pyimagesearch.com + +# USAGE +# BE SURE TO INSTALL 'imutils' PRIOR TO EXECUTING THIS COMMAND +# python sorting_contours.py + +# import the necessary packages +from imutils import contours +import imutils +import cv2 + +# load the shapes image clone it, convert it to grayscale, and +# detect edges in the image +image = cv2.imread("../demo_images/shapes.png") +orig = image.copy() +gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) +edged = imutils.auto_canny(gray) + +# find contours in the edge map +(cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, + cv2.CHAIN_APPROX_SIMPLE) + +# loop over the (unsorted) contours and label them +for (i, c) in enumerate(cnts): + orig = contours.label_contour(orig, c, i, color=(240, 0, 159)) + +# show the original image +cv2.imshow("Original", orig) + +# loop over the sorting methods +for method in ("left-to-right", "right-to-left", "top-to-bottom", "bottom-to-top"): + # sort the contours + (cnts, boundingBoxes) = contours.sort_contours(cnts, method=method) + clone = image.copy() + + # loop over the sorted contours and label them + for (i, c) in enumerate(cnts): + sortedImage = contours.label_contour(clone, c, i, color=(240, 0, 159)) + + # show the sorted contour image + cv2.imshow(method, sortedImage) + +# wait for a keypress +cv2.waitKey(0) \ No newline at end of file diff --git a/imutils/__init__.py b/imutils/__init__.py index 10818ad..face6c2 100644 --- a/imutils/__init__.py +++ b/imutils/__init__.py @@ -2,96 +2,10 @@ # website: http://www.pyimagesearch.com # import the necessary packages -import numpy as np -import cv2 - -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 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) \ No newline at end of file +from convenience import translate +from convenience import rotate +from convenience import resize +from convenience import skeletonize +from convenience import opencv2matplotlib +from convenience import url_to_image +from convenience import auto_canny \ No newline at end of file diff --git a/imutils/__init__.pyc b/imutils/__init__.pyc index aaf41fb..40989bc 100644 Binary files a/imutils/__init__.pyc and b/imutils/__init__.pyc differ