OpenCV 小ネタ集3

Approximating Contour + Convex Hull

  • Approximating Contour
import numpy as np
import cv2
import matplotlib.pyplot as plt

def cv2_imshow(title, image):
    plt.figure(figsize=(8, 8))
    plt.imshow(cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_BGR2RGB))
    plt.title(title)
    # as opencv loads in BGR format by default, we want to show it in RGB.
    plt.show()

# Load image and keep a copy
image = cv2.imread('images/house.jpg')
orig_image = image.copy()
cv2_imshow('Original Image', orig_image)

# Grayscale and binarize
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)

# Find contours 
contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

# Iterate through each contour and compute the bounding rectangle
for c in contours:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(orig_image,(x,y),(x+w,y+h),(0,0,255),2)    
    cv2_imshow('Bounding Rectangle', orig_image)

# Iterate through each contour and compute the approx contour
# bounding box ほど長方形じゃないが、それなりに近似している形
# 弧長のなん%かなどで、eps の大きさを決める
for c in contours:
    # Calculate accuracy as a percent of the contour perimeter
    accuracy = 0.03 * cv2.arcLength(c, True)
    # accuracy = epcilon なので、eps 以上に近い範囲の点は結ばない。
    approx = cv2.approxPolyDP(c, accuracy, True)
    cv2.drawContours(image, [approx], 0, (0, 255, 0), 2)
    cv2_imshow('Approx Poly DP', image)
  • Convex Hull: 曲線の凸性の欠陥を調べ修正する。手形だと、指の先をつないでくれる。
import numpy as np
import cv2

image = cv2.imread('images/hand.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

cv2_imshow('Original Image', image)

# Threshold the image
ret, thresh = cv2.threshold(gray, 176, 255, 0)

# Find contours 
contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
    
# Sort Contors by area and then remove the largest frame contour
n = len(contours) - 1
contours = sorted(contours, key=cv2.contourArea, reverse=False)[:n]

# Iterate through contours and draw the convex hull
for c in contours:
    hull = cv2.convexHull(c)
    cv2.drawContours(image, [hull], 0, (0, 255, 0), 2)
    cv2_imshow('Convex Hull', image)

Shape Matching

  • matchShapes: 形が近い場合、値が0に近づく
iimport cv2
import numpy as np
import matplotlib.pyplot as plt

def cv2_imshow(title, image):
    plt.figure(figsize=(8, 8))
    plt.imshow(cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_BGR2RGB))
    plt.title(title)
    # as opencv loads in BGR format by default, we want to show it in RGB.
    plt.show()

# Load the shape template or reference image
template = cv2.imread('images/4star.jpg',0)
cv2_imshow('Template', template)

# Load the target image with the shapes we're trying to match
target = cv2.imread('images/shapestomatch.jpg')
target_gray = cv2.cvtColor(target,cv2.COLOR_BGR2GRAY)

# Threshold both images first before using cv2.findContours
ret, thresh1 = cv2.threshold(template, 127, 255, 0)
ret, thresh2 = cv2.threshold(target_gray, 127, 255, 0)

# Find contours in template
contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

# We need to sort the contours by area so that we can remove the largest
# contour which is the image outline
sorted_contours = sorted(contours, key=cv2.contourArea, reverse=True)

# We extract the second largest contour which will be our template contour
template_contour = contours[1]

# Extract contours from second target image
contours, hierarchy = cv2.findContours(thresh2, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

for c in contours:
    # Iterate through each contour in the target image and 
    # use cv2.matchShapes to compare contour shapes
    match = cv2.matchShapes(template_contour, c, 3, 0.0)
    print(match)
    # If the match value is less than 0.15 we
    if match < 0.15:
        closest_contour = c
    else:
        closest_contour = [] 
                
cv2.drawContours(target, [closest_contour], -1, (0,255,0), 3)
cv2_imshow('Output', target)

Hough Line

  • cv2.HoughLines
import cv2
import numpy as np
import matplotlib.pyplot as plt

def cv2_imshow(title, image):
    plt.figure(figsize=(12, 12))
    plt.imshow(cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_BGR2RGB))
    plt.title(title)
    # as opencv loads in BGR format by default, we want to show it in RGB.
    plt.show()

image = cv2.imread('images/soduku.jpg')

# Grayscale and Canny Edges extracted
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 170, apertureSize = 3)

# Run HoughLines using a rho accuracy of 1 pixel
# theta accuracy of np.pi / 180 which is 1 degree
# Our line threshold is set to 240 (number of points on line)
lines = cv2.HoughLines(edges, 1, np.pi / 180, 240)

# We iterate through each line and convert it to the format
# required by cv.lines (i.e. requiring end points)
print(lines.shape)
for rho, theta in np.squeeze(lines):
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    cv2.line(image, (x1, y1), (x2, y2), (255, 0, 0), 2)

cv2_imshow('Hough Lines', image)
  • cv2.HoughLinesP (Probabilistic Hough Lines)
import cv2
import numpy as np

# Grayscale and Canny Edges extracted
image = cv2.imread('images/soduku.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 170, apertureSize = 3)

# Again we use the same rho and theta accuracies
# However, we specific a minimum vote (pts along line) of 100
# and Min line length of 5 pixels and max gap between lines of 10 pixels
# minLineLength - 検出する直線の最小の長さを表します.この値より短い線分は検出されません.
# maxLineGap - 二つの線分を一つの直線とみなす時に許容される最大の長さを表します.この値より小さいギャップを持つ二本の直線は一つの直線とみなされます.
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, 5, 10)
print(lines.shape)

for x1, y1, x2, y2 in np.squeeze(lines):
    cv2.line(image, (x1, y1), (x2, y2),(0, 255, 0), 3)

cv2_imshow('Probabilistic Hough Lines', image)
  • HoughCircles: 円の検出。なかなかうまく行かない
import cv2
import numpy as np

image = cv2.imread('images/bottlecaps.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

blur = cv2.medianBlur(gray, 5)
circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, 1.43, 10, maxRadius=70)

for i in circles[0,:]:
       # draw the outer circle
       cv2.circle(image,(i[0], i[1]), i[2], (255, 0, 0), 2)

       # draw the center of the circle
       cv2.circle(image, (i[0], i[1]), 2, (0, 255, 0), 5)

cv2_imshow('detected circles', image)

Blob Detection

# Standard imports
import cv2
import numpy as np;
import matplotlib.pyplot as plt

def cv2_imshow(title, image):
    plt.figure(figsize=(12, 12))
    plt.imshow(cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_BGR2RGB))
    plt.title(title)
    # as opencv loads in BGR format by default, we want to show it in RGB.
    plt.show()
 
# Read image
image = cv2.imread("images/Sunflowers.jpg")
 
# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector_create()
 
# Detect blobs.
keypoints = detector.detect(image)
 
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of
# the circle corresponds to the size of blob
blank = np.zeros((1,1)) 
blobs = cv2.drawKeypoints(image, keypoints, blank, (0,255,255),
                                      cv2.DRAW_MATCHES_FLAGS_DEFAULT)
 
# Show keypoints
cv2_imshow("Blobs", blobs)

Counting Circles and Ellipses

  • blob は、ぼやっとしていてもはっきりしていても、特定箇所に同じ色が集まっていればOK
import cv2
import numpy as np
import matplotlib.pyplot as plt

def cv2_imshow(title, image):
    plt.figure(figsize=(12, 12))
    plt.imshow(cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_BGR2RGB))
    plt.title(title)
    # as opencv loads in BGR format by default, we want to show it in RGB.
    plt.show()

# Load image
image = cv2.imread("images/blobs.jpg", 0)
cv2_imshow('Original Image',image)

# Intialize the detector using the default parameters
detector = cv2.SimpleBlobDetector_create()
 
# Detect blobs
keypoints = detector.detect(image)
 
# Draw blobs on our image as red circles
blank = np.zeros((1,1)) 
blobs = cv2.drawKeypoints(image, keypoints, blank, (0,0,255),
                                      cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

number_of_blobs = len(keypoints)
text = "Total Number of Blobs: " + str(len(keypoints))
cv2.putText(blobs, text, (20, 550), cv2.FONT_HERSHEY_SIMPLEX, 1, (100, 0, 255), 2)

# Display image with blob keypoints
cv2_imshow("Blobs using default parameters", blobs)


# Set our filtering parameters
# Initialize parameter settiing using cv2.SimpleBlobDetector
# SimpleBlobDetector_create のパラメータを指定できる
params = cv2.SimpleBlobDetector_Params()

# Set Area filtering parameters
params.filterByArea = True
params.minArea = 100

# Set Circularity filtering parameters
params.filterByCircularity = True 
params.minCircularity = 0.9

# Set Convexity filtering parameters
params.filterByConvexity = False
params.minConvexity = 0.2
    
# Set inertia filtering parameters
params.filterByInertia = True
params.minInertiaRatio = 0.01

# Create a detector with the parameters
detector = cv2.SimpleBlobDetector_create(params)
    
# Detect blobs
keypoints = detector.detect(image)

# Draw blobs on our image as red circles
blank = np.zeros((1,1)) 
blobs = cv2.drawKeypoints(image, keypoints, blank, (0,255,0),
                                      cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

number_of_blobs = len(keypoints)
text = "Number of Circular Blobs: " + str(len(keypoints))
cv2.putText(blobs, text, (20, 550), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 100, 255), 2)

# Show blobs
cv2_imshow("Filtering Circular Blobs Only", blobs)

www.learnopencv.com