1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. import argparse
  4. import cv2
  5. import imutils
  6. # construct the argument parser and parse the arguments
  7. ap = argparse.ArgumentParser()
  8. ap.add_argument("-i", "--image", required=False, default='tetris_blocks.png', help="path to input image")
  9. args = vars(ap.parse_args())
  10. # load the input image (whose path was supplied via command line
  11. # argument) and display the image to our screen
  12. image = cv2.imread(args["image"])
  13. cv2.imshow("Image", image)
  14. cv2.waitKey(0)
  15. # convert the image to grayscale
  16. gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  17. cv2.imshow("Gray", gray)
  18. cv2.waitKey(0)
  19. # applying edge detection we can find the outlines of objects in
  20. # images
  21. edged = cv2.Canny(gray, 30, 150)
  22. cv2.imshow("Edged", edged)
  23. cv2.waitKey(0)
  24. # threshold the image by setting all pixel values less than 225
  25. # to 255 (white; foreground) and all pixel values >= 225 to 255
  26. # (black; background), thereby segmenting the image
  27. thresh = cv2.threshold(gray, 225, 255, cv2.THRESH_BINARY_INV)[1]
  28. cv2.imshow("Thresh", thresh)
  29. cv2.waitKey(0)
  30. # a typical operation we may want to apply is to take our mask and
  31. # apply a bitwise AND to our input image, keeping only the masked
  32. # regions
  33. mask = thresh.copy()
  34. output = cv2.bitwise_and(image, image, mask=mask)
  35. cv2.imshow("Output", output)
  36. cv2.waitKey(0)
  37. # we apply erosions to reduce the size of foreground objects
  38. mask = thresh.copy()
  39. mask = cv2.erode(mask, None, iterations=5)
  40. cv2.imshow("Eroded", mask)
  41. cv2.waitKey(0)
  42. # similarly, dilations can increase the size of the ground objects
  43. mask = thresh.copy()
  44. mask = cv2.dilate(mask, None, iterations=5)
  45. cv2.imshow("Dilated", mask)
  46. cv2.waitKey(0)
  47. # find contours (i.e., outlines) of the foreground objects in the
  48. # thresholded image
  49. cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  50. cnts = imutils.grab_contours(cnts)
  51. output = image.copy()
  52. # loop over the contours
  53. for c in cnts:
  54. # draw each contour on the output image with a 3px thick purple
  55. # outline, then display the output contours one at a time
  56. cv2.drawContours(output, [c], -1, (240, 0, 159), 3)
  57. cv2.imshow("Contours", output)
  58. cv2.waitKey(0)
  59. pass
  60. # draw the total number of contours found in purple
  61. text = "I found {} objects!".format(len(cnts))
  62. cv2.putText(output, text, (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (240, 0, 159), 2)
  63. cv2.imshow("Contours", output)
  64. cv2.waitKey(0)

image.png

image.png

ROI

Extracting “regions of interest” (ROIs) is an important skill for image processing.

Processing

Take note that drawing operations on images are performed in-place. Therefore at the beginning of each code block, we make a copy of the original image storing the copy

image.png

Canny

parameters to the cv2.Canny function:

  • img : The gray image.
  • minVal : A minimum threshold, in our case 30 .
  • maxVal : The maximum threshold which is 150 in our example.
  • aperture_size : The Sobel kernel size. By default this value is 3.

Thresholding

  1. # threshold the image by setting all pixel values less than 225
  2. # to 255 (white; foreground) and all pixel values >= 225 to 255
  3. # (black; background), thereby segmenting the image
  4. thresh = cv2.threshold(gray, 225, 255, cv2.THRESH_BINARY_INV)[1]
  5. cv2.imshow("Thresh", thresh)
  6. cv2.waitKey(0)
  • Grabbing all pixels in the gray image greater than 225 and setting them to 0 (black) which corresponds to the background of the image.
  • Setting pixel vales less than 225 to 255 (white) which corresponds to the foreground of the image.

Contours

Erosions and dilations

Erosions and dilations are typically used to reduce noise in binary images (a side effect of thresholding).

Masking and bitwise