git-svn-id: http://moon:8086/svn/software/trunk/projects/opencv@314 b431acfa-c32f-4a4a-93f1-934dc6c82436
233 lines
6.9 KiB
Python
Executable File
233 lines
6.9 KiB
Python
Executable File
# import the necessary packages
|
|
from __future__ import print_function
|
|
from PiVideoStream import PiVideoStream
|
|
from imutils.video import FPS
|
|
from picamera.array import PiRGBArray
|
|
from picamera import PiCamera
|
|
import numpy as np
|
|
import argparse
|
|
import imutils
|
|
import time
|
|
import cv2
|
|
import pprint
|
|
from matplotlib import pyplot as plt
|
|
from mpl_toolkits.mplot3d import Axes3D
|
|
|
|
width = 320
|
|
height = 240
|
|
|
|
class FindObjects():
|
|
def __init__(self):
|
|
self.innerOuterRatio = 0.6 # const
|
|
self.meanThickness = 0
|
|
self.meanOuterDiameter = 0
|
|
self.meanInnerDiameter = 0
|
|
self.maxDiameter = -10000
|
|
self.minDiameter = +10000
|
|
self.pp = pprint.PrettyPrinter(indent=4)
|
|
|
|
@staticmethod
|
|
def getFamily(family, parentId, hierachy):
|
|
|
|
family.append(parentId)
|
|
if hierachy[0][parentId][2] != -1:
|
|
return FindObjects.getFamily(family, hierachy[0][parentId][2], hierachy)
|
|
else:
|
|
return family
|
|
|
|
|
|
def find(self, contours, hierachy):
|
|
count = 0
|
|
objects = []
|
|
temp_objects = []
|
|
objectsIds = []
|
|
objectsCandIds = []
|
|
for cnt in contours:
|
|
if hierachy[0][count][3] == -1:
|
|
family = FindObjects.getFamily([], count, hierachy)
|
|
|
|
dupDict = {}
|
|
members = []
|
|
for member in family:
|
|
x,y,w,h = cv2.boundingRect(contours[member]);
|
|
key = str([x,y,w,h]) + '.key'
|
|
if not key in dupDict:
|
|
dupDict[key] = member
|
|
members.append({ 'id' : member, 'bbox' : [x,y,w,h]})
|
|
|
|
objectsCandIds.append(members)
|
|
|
|
count += 1
|
|
|
|
for family in objectsCandIds:
|
|
obj = []
|
|
for member in family:
|
|
area = cv2.contourArea(contours[member['id']])
|
|
perimeter = cv2.arcLength(contours[member['id']], True)
|
|
pi = 3.14159265359
|
|
Q = 0
|
|
if (perimeter > 0):
|
|
Q = 4*pi*area/(perimeter*perimeter)
|
|
|
|
if Q >= 0.7:
|
|
diameter = max(member['bbox'][2], member['bbox'][3])
|
|
self.maxDiameter = max(self.maxDiameter, diameter)
|
|
self.minDiameter = min(self.minDiameter, diameter)
|
|
member['diameter'] = diameter
|
|
member['pos'] = (int(member['bbox'][0] + member['bbox'][2]/2), int(member['bbox'][1] + member['bbox'][3]/2))
|
|
obj.append(member)
|
|
|
|
if obj:
|
|
temp_objects.append(obj)
|
|
|
|
for obj in temp_objects:
|
|
for member in obj:
|
|
if member['diameter'] < self.innerOuterRatio*self.maxDiameter:
|
|
member['isHole'] = True
|
|
else:
|
|
member['isHole'] = False
|
|
|
|
if len(obj) == 2:
|
|
self.meanThickness = int(abs(obj[0]['diameter'] - obj[1]['diameter'])/2)
|
|
|
|
objects.append({'thickness' : self.meanThickness, 'members' : obj})
|
|
|
|
return objects
|
|
|
|
def printStats(self):
|
|
print ("maxDiameter = " + str(self.maxDiameter) + " px")
|
|
print ("minDiameter = " + str(self.minDiameter) + " px")
|
|
print ("meanThickness = " + str(self.meanThickness) + " px")
|
|
|
|
# construct the argument parse and parse the arguments
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("-n", "--num-frames", type=int, default=100,
|
|
help="# of frames to loop over for FPS test")
|
|
ap.add_argument("-d", "--display", type=int, default=-1,
|
|
help="Whether or not frames should be displayed")
|
|
args = vars(ap.parse_args())
|
|
|
|
# created a *threaded *video stream, allow the camera sensor to warmup,
|
|
# and start the FPS counter
|
|
print("[INFO] sampling THREADED frames from `picamera` module...")
|
|
vs = PiVideoStream(resolution=(width,height), framerate=30).start()
|
|
time.sleep(2.0)
|
|
fps = FPS().start()
|
|
findObjects = FindObjects()
|
|
|
|
beadColors = []
|
|
|
|
# loop over some frames...this time using the threaded stream
|
|
while fps._numFrames < args["num_frames"]:
|
|
# grab the frame from the threaded video stream
|
|
frame = vs.read()
|
|
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
|
|
gray_blurred = cv2.medianBlur(gray,5)
|
|
|
|
# Canny edge detection
|
|
img1_canny = cv2.Canny(gray_blurred, 100, 50)
|
|
kernel = np.ones((1,1),np.uint8)
|
|
# img1_canny = cv2.blur(img1_canny,(3,3))
|
|
# img1_canny = cv2.dilate(img1_canny,kernel,iterations = 1)
|
|
|
|
# Thresholding
|
|
# ret,img1_thr = cv2.threshold(gray_blurred,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
|
|
# img1_thr = cv2.adaptiveThreshold(gray_blurred,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,11,2)
|
|
# img1_thr = cv2.adaptiveThreshold(gray_blurred,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)
|
|
|
|
# Contours
|
|
(_, contours, hierachy) = cv2.findContours(img1_canny.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
|
|
|
|
objects = findObjects.find(contours, hierachy)
|
|
|
|
# print (ids)
|
|
|
|
img1_objects = frame.copy()
|
|
img1_colors = np.zeros((height,width,3), np.uint8)
|
|
maskCenter = 4
|
|
roides = []
|
|
beads = []
|
|
for obj in objects:
|
|
memberCount = 0
|
|
radius = 0
|
|
roi = 0
|
|
for member in obj['members']:
|
|
# Draw bounding box
|
|
x,y,w,h = [member['bbox'][0], member['bbox'][1], member['bbox'][2], member['bbox'][3]];
|
|
if member['isHole']:
|
|
img1_objects = cv2.rectangle(img1_objects,(x,y),(x+w,y+h),(255,0,0),2)
|
|
thickness = obj['thickness']-maskCenter
|
|
diameter = member['diameter']+thickness+maskCenter
|
|
roi = frame[y-thickness:y+diameter, x-thickness:x+diameter]
|
|
pos = member['pos']
|
|
if diameter > 0:
|
|
mask = np.zeros((diameter,diameter,1), np.uint8)
|
|
mask = cv2.circle(mask,(int(diameter/2), int(diameter/2)),radius,255,thickness)
|
|
mean_color = cv2.mean(roi)
|
|
img1_colors = cv2.circle(img1_colors,(int(pos[0]),int(pos[1])),int(diameter/2),mean_color,-1)
|
|
beads.append({'pos' : pos, 'diameter' : diameter, 'color' : mean_color[0:3]})
|
|
img1_objects = cv2.circle(img1_objects,member['pos'],int(diameter/2),(255,255,255),thickness)
|
|
else:
|
|
img1_objects = cv2.rectangle(img1_objects,(x,y),(x+w,y+h),(0,0,255),2)
|
|
|
|
memberCount += 1
|
|
|
|
for bead in beads:
|
|
beadColors.append(bead['color'])
|
|
|
|
# cv2.imshow('Thresholded',img1_thr)
|
|
cv2.imshow('detected colors', img1_colors)
|
|
cv2.imshow('Canny',img1_canny)
|
|
cv2.imshow('Objects',img1_objects)
|
|
cv2.waitKey(1)
|
|
|
|
# update the FPS counter
|
|
fps.update()
|
|
|
|
# stop the timer and display FPS information
|
|
fps.stop()
|
|
vs.stop()
|
|
print("[INFO] elasped time: {:.2f}".format(fps.elapsed()))
|
|
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
|
|
print("[INFO] Camera : elasped time: {:.2f}".format(vs.getfps().elapsed()))
|
|
print("[INFO] Camera: approx. FPS: {:.2f}".format(vs.getfps().fps()))
|
|
|
|
# Output stats
|
|
findObjects.printStats()
|
|
|
|
# Analyze colors
|
|
numObjects = len(beadColors);
|
|
blue = np.zeros(numObjects)
|
|
green = np.zeros(numObjects)
|
|
red = np.zeros(numObjects)
|
|
plotColors = np.zeros((numObjects,3))
|
|
i = 0
|
|
for color in beadColors:
|
|
blue[i] = color[0]/255
|
|
green[i] = color[1]/255
|
|
red[i] = color[2]/255
|
|
plotColors[i] = [red[i], green[i], blue[i]]
|
|
i += 1
|
|
|
|
# Kmeans create color classes
|
|
Z = np.float32(plotColors)
|
|
|
|
# Define criteria = ( type, max_iter, epsilon )
|
|
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.1)
|
|
ret,label,center=cv2.kmeans(Z,10,None,criteria,10,cv2.KMEANS_PP_CENTERS)
|
|
|
|
print (center)
|
|
|
|
# Scatter plot of colors
|
|
fig = plt.figure()
|
|
ax = fig.add_subplot(111, projection='3d')
|
|
ax.scatter(blue, green, red, zdir='z', s=10, c=(0,0,0), lw = 0, depthshade=True)
|
|
ax.scatter(center[:,2], center[:,1], center[:,0], zdir='z', s=250, facecolors=center, lw = 1, depthshade=True)
|
|
|
|
plt.show()
|
|
|
|
|
|
# do a bit of cleanup
|
|
cv2.destroyAllWindows()
|
|
|