from picamera.array import PiRGBArray # Generates a 3D RGB array
from picamera import PiCamera # Provides a Python interface for the RPi Camera Module
import requests as client
import time # Provides time-related functions
import cv2 # OpenCV library
import numpy as np # Import NumPy library
import json
import base64

import RPi.GPIO as GPIO

# Set GPIO numbering mode
GPIO.setmode(GPIO.BOARD)


GPIO.setup(36,GPIO.OUT)
servo = GPIO.PWM(36,50) 

#start PWM running, but with value of 0 (pulse off)
servo.start(0)

def rateImage (image):
  try:
    file = {'image': image}
    response = client.post('https://api-face-detector.herokuapp.com/api/classificator', files=file)
    return json.loads(response.content)
  except Exception as error:
    print("Falha ao realizar a classificação da imagem!", error)
    

def lock():
    servo.ChangeDutyCycle(12)
    time.sleep(0.7)
    servo.ChangeDutyCycle(0)

def unlock():
    servo.ChangeDutyCycle(2)
    time.sleep(0.7)
    servo.ChangeDutyCycle(0)
    time.sleep(10)
    lock()
    
def actionResult(classification):
    if(classification=="person"):
        unlock()
 
camera = PiCamera()
 
camera.resolution = (640, 480)
 
# Set the number of frames per second
camera.framerate = 30
 
# Generates a 3D RGB array and stores it in rawCapture
raw_capture = PiRGBArray(camera, size=(640, 480))
 
# Wait a certain number of seconds to allow the camera time to warmup
time.sleep(0.1)
 
# Initialize the first frame of the video stream
first_frame = None
 
# Create kernel for morphological operation. You can tweak
# the dimensions of the kernel.
# e.g. instead of 20, 20, you can try 30, 30
kernel = np.ones((20,20),np.uint8)
 
# Capture frames continuously from the camera
for frame in camera.capture_continuous(raw_capture, format="bgr", use_video_port=True):
     
    # Grab the raw NumPy array representing the image
    image = frame.array
 
    # Convert the image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
     
    # Close gaps using closing
    gray = cv2.morphologyEx(gray,cv2.MORPH_CLOSE,kernel)
       
    # Remove salt and pepper noise with a median filter
    gray = cv2.medianBlur(gray,5)
     
    # If first frame, we need to initialize it.
    if first_frame is None:
         
      first_frame = gray
       
      # Clear the stream in preparation for the next frame
      raw_capture.truncate(0)
       
      # Go to top of for loop
      continue
       
    # Calculate the absolute difference between the current frame
    # and the first frame
    absolute_difference = cv2.absdiff(first_frame, gray)
 
    # If a pixel is less than ##, it is considered black (background). 
    # Otherwise, it is white (foreground). 255 is upper limit.
    # Modify the number after absolute_difference as you see fit.
    _, absolute_difference = cv2.threshold(absolute_difference, 100, 255, cv2.THRESH_BINARY)
 
    # Find the contours of the object inside the binary image
    contours, hierarchy = cv2.findContours(absolute_difference,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[-2:]
    areas = [cv2.contourArea(c) for c in contours]
  
    # If there are no countours
    if len(areas) < 1:
  
      # Display the resulting frame
      #volta esse cara
      #cv2.imshow('Frame',image)
  
      # Wait for keyPress for 1 millisecond
      key = cv2.waitKey(1) & 0xFF
  
      # Clear the stream in preparation for the next frame
      raw_capture.truncate(0)
     
      # If "q" is pressed on the keyboard, 
      # exit this loop
      if key == ord("q"):
        break
     
      # Go to the top of the for loop
      continue
  
    else:
         
      # Find the largest moving object in the image
      max_index = np.argmax(areas)
       
    # Draw the bounding box
    cnt = contours[max_index]
    x,y,w,h = cv2.boundingRect(cnt)
    crop_image = image[y:y+h, x:x+w]
    test = cv2.imencode(".jpeg", image)[1]
    classificationResult = rateImage(test.tostring())
    print(classificationResult['rate'])
    
    actionResult(classificationResult['rate'])
    time.sleep(5)
    #cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),3)
  
    # Draw circle in the center of the bounding box
    x2 = x + int(w/2)
    y2 = y + int(h/2)
    cv2.circle(image,(x2,y2),4,(0,255,0),-1)
  
    # Print the centroid coordinates (we'll use the center of the
    # bounding box) on the image
    text = "x: " + str(x2) + ", y: " + str(y2)
    cv2.putText(image, text, (x2 - 10, y2 - 10),
      cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
          
    # Display the resulting frame
    #volta esse cara se quiser ver o frame
    #cv2.imshow("Frame",image)
     
    # Wait for keyPress for 1 millisecond
    key = cv2.waitKey(1) & 0xFF
  
    # Clear the stream in preparation for the next frame
    raw_capture.truncate(0)
     
    # If "q" is pressed on the keyboard, 
    # exit this loop
    if key == ord("q"):
      break
 
# Close down windows
cv2.destroyAllWindows()
