allow the camera to initilize
February 18, 2017 ยท View on GitHub
from picamera.array import PiYUVArray from picamera import PiCamera import time import cv2 import numpy as np import colorsys
#set Pi Camera settings camera = PiCamera() camera.resolution = (640, 480) camera.brightness = 40 bright = 40 camera.contrast = 0 camera.saturation = -10 camera.rotation = 180 camera.framerate = 10 rawCapture = PiYUVArray(camera, size=(640, 480))
allow the camera to initilize
time.sleep(0.1)
#set the lists for all 6 sides to white for initialize top= ("W", "W", "W", "W", "W", "W", "W", "W", "W") bottom=("W","W","W","W","W","W","W","W","W") left=("W","W","W","W","W","W","W","W","W") right=("W","W","W","W","W","W","W","W","W") front=("W","W","W","W","W","W","W","W","W") back=("W","W","W","W","W","W","W","W","W") #set flags that all side are not completed top_complete= False bottom_complete = False left_complete = False right_complete = False front_complete = False back_complete = False
#initialize working face to nil face=[]
#routine for counting number of each color has appeaded on each face. Used at the end to ensure there is 9 of each colour before exiting def count_colours (fcheck, countall): (wcount,bcount,rcount,gcount,ycount,ocount)=countall for pos in range (9): if fcheck[pos]=="W": wcount +=1 elif fcheck[pos] == "B": bcount +=1 elif fcheck[pos] == "R": rcount+=1 elif fcheck[pos] == "G": gcount+=1 elif fcheck[pos] == "Y": ycount+=1 elif fcheck[pos] == "O": ocount+=1 countall=(wcount,bcount,rcount,gcount,ycount,ocount) return countall
#routine for drawing the read faces on the screen def draw_face(colorss,x,y): toprow = colorss[0:3] midrow = colorss[3:6] lastrrow = colorss[6:9] tile_color = (0,0,0) #draw a black square as background cv2.rectangle(image, (0+x,0+y ), (65+x, 65+y), (0,0,0),-1)
#draw the coloured squares for top row
for pos in range(3):
if toprow[pos] == "W":
tile_color = (255,255,255)
elif toprow[pos] == "G":
tile_color = (0,255,0)
elif toprow[pos] == "B":
tile_color = (255,0,0)
elif toprow[pos] == "R":
tile_color = (0,0,255)
elif toprow[pos] == "O":
tile_color = (0,100,255)
elif toprow[pos] == "Y":
tile_color = (50,255,255)
elif toprow[pos] == "N":
tile_color = (0,0,0)
cv2.rectangle((image), (20pos+5+x,5+y ), (20pos+20+x, 20+y), tile_color,-1)
#draw the coloured squares for middle row
for pos in range(3):
if midrow[pos] == "W":
tile_color = (255,255,255)
elif midrow[pos] == "G":
tile_color = (0,255,0)
elif midrow[pos] == "B":
tile_color = (255,0,0)
elif midrow[pos] == "R":
tile_color = (0,0,255)
elif midrow[pos] == "O":
tile_color = (0,100,255)
elif midrow[pos] == "Y":
tile_color = (50,255,255)
elif middle_row[pos] == "N":
tile_color = (0,0,0)
cv2.rectangle((image), (20pos+5+x,25+y ), (20pos+20+x, 40+y), tile_color,-1)
#draw the coloured squares for bottom row
for pos in range(3):
if lastrrow[pos] == "W":
tile_color = (255,255,255)
elif lastrrow[pos] == "G":
tile_color = (0,255,0)
elif lastrrow[pos] == "B":
tile_color = (255,0,0)
elif lastrrow[pos] == "R":
tile_color = (0,0,255)
elif lastrrow[pos] == "O":
tile_color = (0,100,255)
elif lastrrow[pos] == "Y":
tile_color = (50,255,255)
elif lastrrow[pos] =="N":
tile_color = (0,0,0)
cv2.rectangle((image), (20pos+5+x,45+y ), (20pos+20+x, 60+y), tile_color,-1)
#setup videowriter to record frames, this can beroved for faster processing fourcc = cv2.VideoWriter_fourcc(*'XVID') writer = None writer = cv2.VideoWriter("/home/pi/Shane/outvideo.avi", fourcc, 5, (640, 480), True)
#loop for capturing frames from camera in raw YUV format for the purpose of adjusting brightness for frame in camera.capture_continuous(rawCapture, format="raw", use_video_port=True):
# grab the raw NumPy array representing the image, then initialize the timestamp
image = frame.array
#find the mean of all the image
(Y,U,V,DA)= cv2.mean(image)
#clear the image ready for next capture
rawCapture.truncate(0)
#if mean brightness : Y is between 70 and 72 then exit loop
if Y > 70 and Y < 72:
break
#adjust camera brightness based upon mean Y of image
if Y > 82:
bright -=3
if Y > 72:
bright -=1
camera.brightness = bright
if Y < 60 :
bright += 3
if Y < 70 :
bright+=1
camera.brightness = bright
Main loop for capturing frames from camera in raw YUV format
for frame in camera.capture_continuous(rawCapture, format="raw", use_video_port=True):
# grab the raw NumPy array representing the image, then initialize the timestamp
image = frame.array
#create serval biniary masks to issolate the colours we are looking for
White_Yellow_mask = cv2.inRange(image, (100,40,90), (255,255,255))
Red_mask= cv2.inRange(image, (0,0,143), (255,255,255))
Green_mask = cv2.inRange(image, (60,50,50), (150,170,110))
Center_Green_Mask = cv2.inRange(image, (20,60,50), (80,130,110))
Blue_Mask = cv2.inRange(image, (20,95,50), (90,200,115))
#Combined all the biniary masks together to get one image with all needed data
Combined_image = cv2.bitwise_or(White_Yellow_mask, Red_mask)
Combined_image = cv2.bitwise_or(Green_mask, Combined_image)
Combined_image = cv2.bitwise_or(Center_Green_Mask, Combined_image)
Combined_image = cv2.bitwise_or(Blue_Mask, Combined_image)
#look for countours in the combined binary mask
im2,contours2, hierarchy = cv2.findContours(Combined_image.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
candidates=[]
index = 0
# loop through the cpountours to find the ones we want
for c in contours2:
#approxPolyDP to find strainght line contours
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.06 * peri, True)
#find countours made up for 4 lines
if len (approx) ==4 :
(x, y, w, h) = cv2.boundingRect(approx)
#find aspect ratio of boundary rectangle around the countours
ar = w / float(h)
#get the area of ther countour
area= cv2.contourArea(contours2[index])
#if the countour has AR close to 1 i.e close to square not rectangle and area of countour is close to area of box around countouour i.e not diamonmd or robus add it to candidates list
if ar > .7 and ar < 1.3 and w > 30 and w < 90 and area/(w*h) > .4:
candidates.append((x,y,w,h))
index += 1
new=candidates
#loop through all the countours in the candidantes list
for d in new:
neighbors=0
(x,y,w,h) = d
for (x2,y2,w2,h2) in new:
#count up how many neighbors closer than width * 3.5 each countour in candidanteslist has
if abs(x-x2) < (w*3.5) and abs(y-y2) < (h*3.5):
neighbors +=1
#any candidantes with less than 5 neighbors remove
if neighbors < 5 :
candidates.remove(d)
#sort candidates if there's 9 of them
tmp=[]
if len(candidates)==9 :
#Write to tmp the center y,x of candidantes so that we can sort in y direction
for (x3,y3,w3,h3) in candidates:
tmp.append( (y3+(h/2), x3+(w/2)) )
tmp = sorted(tmp)
#cut into sets of 3 i.e the 3 rows of colours
top_row=tmp[0:3]
tmp = tmp[3:9]
tmp = sorted(tmp)
middle_row = tmp[0:3]
bottom_row = tmp[3:6]
#sort top_row
temp_row=[]
#write to temp_row the center x,y for sorting in x direction
for (y4,x4) in top_row:
temp_row.append((x4,y4))
#sort top_row
top_row = temp_row
top_row = sorted(top_row)
#sort middle_row
temp_row=[]
for (y4,x4) in middle_row:
temp_row.append((x4,y4))
middle_row = temp_row
middle_row = sorted(middle_row)
#sort bottom_row
temp_row=[]
for (y4,x4) in bottom_row:
temp_row.append((x4,y4))
bottom_row = temp_row
bottom_row = sorted(bottom_row)
face=[]
#loop through the 3 positions in each row for the purpose to detacting colour of each tile
for pos in range(3):
#cut out a 10x10 cube around center of contour
x,y = top_row[pos]
cube = image[y-5:y+5, x-5:x+5]
#find the mean of that cube
(Y,U,V,DA)= cv2.mean(cube)
#identify each color and write the detected colour to the face list
if Y > 120 and float(U/V)>0.9 :
face.append("W")
elif U > 130 and U > V and float (U/Y)> 1.15:
face.append("B")
elif float(U/V) > 1.1 and float(U/V) < 2:
face.append("G")
elif V > 120 and float (U/Y) > 0.7:
if float(U/Y) < 1.9 :
face.append("O")
else :
face.append("R")
elif Y > 110 and float(V/U)>0.95 :
face.append("Y")
#just doing same as above but for middle row
for pos in range(3):
x,y = middle_row[pos]
cube = image[y-5:y+5, x-5:x+5]
(Y,U,V,DA)= cv2.mean(cube)
if Y > 120 and float(U/V)>0.9 :
face.append("W")
elif U > 130 and U > V and float (U/Y)> 1.15:
face.append("B")
elif pos == 1 and float(U/V) > 1 and float(U/V) < 1.9:
face.append("G")
elif float(U/V) > 1.1 and float(U/V) < 1.9:
face.append("G")
elif V > 120 and float (U/Y) > 0.7:
if float(U/Y) < 1.9 :
face.append("O")
else :
face.append("R")
elif Y > 110 and float(V/U)>0.95 :
face.append("Y")
#one more time for bottom row
for pos in range(3):
x,y = bottom_row[pos]
cube = image[y-5:y+5, x-5:x+5]
(Y,U,V,DA)= cv2.mean(cube)
if Y > 120 and float(U/V)>0.9 :
face.append("W")
elif U > 130 and U > V and float (U/Y)> 1.15:
face.append("B")
elif float(U/V) > 1.1 and float(U/V) < 2:
face.append("G")
elif V > 120 and float (U/Y) > 0.7:
if float(U/Y) < 1.9 :
face.append("O")
else :
face.append("R")
elif Y > 110 and float(V/U)>0.95 :
face.append("Y")
#convert the image from raw YUV format to RGB for user viewing
image = cv2.cvtColor(image, cv2.COLOR_YUV2RGB)
#if there was 9 colours dectected then check middle tile to know which face to update.
if len(face) == 9:
#draw the current face in top left of viewing image
draw_face(face,0,0)
#based unpon which colour the center tile is update that face for the detected colours and switch the flag that face has been read completly
if face[4] == "W":
top = face
top_complete = True
elif face[4] == "G":
front = face
front_complete = True
elif face[4] == "R":
right = face
right_complete = True
elif face[4] == "O":
left = face
left_complete = True
elif face[4] == "B":
back = face
back_complete = True
elif face[4] == "Y":
bottom = face
bottom_complete = True
#draw the all the faces on the viewing image
draw_face(left,0,350)
draw_face(front, 65,350)
draw_face(top,65,285)
draw_face(bottom,65,415)
draw_face(right,130,350)
draw_face(back,195,350)
#draw circles of all the candidates on the viewing image
for (x,y,w,h) in candidates:
cv2.circle(image, (x+w/2, y+h/2), int(w/1.8), (255,0,255),3)
#Display the viewing image
cv2.imshow("Orginial", image)
#write image to video file
writer.write(image)
# clear the stream in preparation for the next frame
rawCapture.truncate(0)
#check to see if all faces have been read
if top_complete and bottom_complete and front_complete and back_complete and left_complete and right_complete:
#if all faces read then count up how many of each colour has been detacted
countall = (0,0,0,0,0,0)
countall = count_colours(top, countall)
countall = count_colours(bottom, countall)
countall = count_colours(front,countall)
countall = count_colours(back, countall)
countall = count_colours(left, countall)
countall = count_colours(right, countall)
(wcount,bcount,rcount,gcount,ycount,ocount)=countall
#if there is 9 of each colour then write result to file and break from loop
if bcount==9 and rcount==9 and gcount==9 and wcount==9 and ycount==9 and ocount==9:
cubefile = open('/home/pi/Sage/MacTwist.txt',"w")
cubefile.write("Front"+"\n")
for ch in front:
cubefile.write(ch)
cubefile.write("\n")
cubefile.write("Bottom"+"\n")
for ch in bottom:
cubefile.write(ch)
cubefile.write("\n")
cubefile.write("Left"+"\n")
for ch in left:
cubefile.write(ch)
cubefile.write("\n")
cubefile.write("Right"+"\n")
for ch in right:
cubefile.write(ch)
cubefile.write("\n")
cubefile.write("Top"+"\n")
for ch in top:
cubefile.write(ch)
cubefile.write("\n")
cubefile.write("Back"+"\n")
for ch in back:
cubefile.write(ch)
cubefile.write("\n")
cubefile.close()
break
#Check for key pressed
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
#close video file writer.release()