import httplib, urllib, base64, json
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
%matplotlib inline

faceApiSubscriptionKey = "[Face API Primary Key]"

baseFaceUrl = "https://raw.githubusercontent.com/CortanaAnalyticsLabs/\
CortanaAnalyticsLabs/master/PerceptualIntelligence/Images/"

thumbsUp = baseFaceUrl + "ThumbsUp.png"
multipleFaces = baseFaceUrl + "MultipleFaces.png"
faceA = baseFaceUrl + "FaceA.png"
faceB = baseFaceUrl + "FaceB.png"
faceC = baseFaceUrl + "FaceC.png"
faceD = baseFaceUrl + "FaceD.png"
faceE = baseFaceUrl + "FaceE.png"

print("Initialization complete")

"""
Explanation: Perceptual Intelligence in Cortana Analytics
Exploring the Microsoft Project Oxford Face API
Face API site
Face API reference
<img src="https://raw.githubusercontent.com/deldersveld/CortanaAnalyticsLabs/master/PerceptualIntelligence/Images/ThumbsUp.png" width="200">
In this activity, you will use Python to explore various methods available from the Face API. 
You will detect a face in an image and crop the image so only the face appears. 
You will then detect multiple faces in a second image and similarly crop each face.
After getting exposure to detecting faces, you will then create a face list and add five distinct faces to the list.
Finally, you will use your initial image to find similar faces from your face list.
This activity uses the following API methods:
    * Detect
    * Create a Face List
    * Get a Face List
    * Delete a Face List (optional)
    * Add a Face to a Face List
    * Find Similar
All images are in the public domain.
Step 1: Enter your Face API key
Substitute the value of faceApiSubscriptionKey with your own API key. 
Replace [Face API Primary Key] but leave the quotation marks around your key.
To obtain your Face API key or sign up for the API, visit the Subscription page.
When ready, run the cell, which imports required libraries and sets initial variables.
End of explanation
"""


def detect(apiKey, imageUrl):
    jsonBody = '{"url":"' + imageUrl + '"}'

    headers = {
        'Content-Type': 'application/json',
        'Ocp-Apim-Subscription-Key': apiKey,
    }

    params = urllib.urlencode({
        'returnFaceId': 'true',
        'returnFaceLandmarks': 'false',
        'returnFaceAttributes': 'age,gender',
    })

    try:
        conn = httplib.HTTPSConnection('api.projectoxford.ai')
        conn.request("POST", "/face/v1.0/detect?%s" % params, jsonBody, headers)
        response = conn.getresponse()
        data = response.read()
        print(data)
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
        
    return data

def createFaceList(apiKey, faceListId):
    faceList = faceListId
    jsonBody = '{"name":"' + faceList + '", "userData":"User-provided data attached to the face list"}'
    
    headers = {
        'Content-Type': 'application/json',
        'Ocp-Apim-Subscription-Key': apiKey,
    }

    params = urllib.urlencode({
    })

    try:
        conn = httplib.HTTPSConnection('api.projectoxford.ai')
        conn.request("PUT", "/face/v1.0/facelists/" + faceList + "?%s" % params, jsonBody, headers)
        response = conn.getresponse()
        data = response.read()
        print(data)
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
        
def getFaceList(apiKey, faceListId):
    faceList = faceListId
    jsonBody = ''
    
    headers = {
        'Ocp-Apim-Subscription-Key': apiKey,
    }

    params = urllib.urlencode({
    })

    try:
        conn = httplib.HTTPSConnection('api.projectoxford.ai')
        conn.request("GET", "/face/v1.0/facelists/" + faceList + "?%s" % params, jsonBody, headers)
        response = conn.getresponse()
        data = response.read()
        print(data)
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
        
def deleteFaceList(apiKey, faceListId):
    faceList = faceListId
    jsonBody = ''
    
    headers = {
        'Ocp-Apim-Subscription-Key': apiKey,
    }

    params = urllib.urlencode({
    })

    try:
        conn = httplib.HTTPSConnection('api.projectoxford.ai')
        conn.request("DELETE", "/face/v1.0/facelists/" + faceList + "%s" % params, jsonBody, headers)
        response = conn.getresponse()
        data = response.read()
        print(data)
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
        
def addFaceToFaceList(apiKey, faceListId, imageUrl):
    faceList = faceListId
    jsonBody = '{"url":"' + imageUrl + '"}'
    
    headers = {
        'Content-Type': 'application/json',
        'Ocp-Apim-Subscription-Key': apiKey,
    }

    params = urllib.urlencode({
    })

    try:
        conn = httplib.HTTPSConnection('api.projectoxford.ai')
        conn.request("POST", "/face/v1.0/facelists/" + faceList + "/persistedFaces?%s" % params, jsonBody, headers)
        response = conn.getresponse()
        data = response.read()
        print(data)
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
        
def findSimilars(apiKey, faceListId, faceId, numberOfCandidates):
    jsonBody = '{"faceId":"' + faceId + '", \
                "faceListId":"' + faceListId + '", \
                "maxNumOfCandidatesReturned":' + numberOfCandidates + '}'
    headers = {
        'Content-Type': 'application/json',
        'Ocp-Apim-Subscription-Key': apiKey,
    }

    params = urllib.urlencode({
    })

    try:
        conn = httplib.HTTPSConnection('api.projectoxford.ai')
        conn.request("POST", "/face/v1.0/findsimilars?%s" % params, jsonBody, headers)
        response = conn.getresponse()
        data = response.read()
        print(data)
        conn.close()
    except Exception as e:
        print("[Errno {0}] {1}".format(e.errno, e.strerror))
        
print("API functions created")

"""
Explanation: Step 2: Define functions
The following five functions allow you to pass your API key and other relevant parameters based on the API reference.
Run the cell to create the various functions.
    * detect(apiKey, imageUrl)
    * createFaceList(apiKey, faceListId)
    * getFaceList(apiKey, faceListId)
    * deleteFaceList(apiKey, faceListId)
    * addFaceToFaceList(apiKey, faceListId, imageUrl)
    * findSimilars(apiKey, faceListId, faceId, numberOfCandidates)
End of explanation
"""


img = mpimg.imread(thumbsUp)
plt.imshow(img)

"""
Explanation: Step 3: Display the initial image
Run the following cell to display the image of a person. The image also displays pixels along the two axes.
End of explanation
"""


thumbsUpData = detect(faceApiSubscriptionKey, thumbsUp)

"""
Explanation: Step 4: Detect the face on the initial image
Run the following cell to call the detect method, which returns a face box for the image. Note the values of "top" and "left" in "faceRectangle" and compare that point to the axes on the original image. The face rectangle then defines a box using the appropriate "width" and "height" values starting from that point. In addition, gender and age are displayed as attributes.
End of explanation
"""


face = json.loads(thumbsUpData)
thumbsUpFaceId = face[0]["faceId"]
faceTop = face[0]["faceRectangle"]["top"]
faceLeft = face[0]["faceRectangle"]["left"]
faceWidth = face[0]["faceRectangle"]["width"]
faceHeight = face[0]["faceRectangle"]["height"]

img = mpimg.imread(thumbsUp)
plt.imshow(img[faceTop:faceTop + faceHeight, faceLeft:faceLeft + faceWidth])

"""
Explanation: Step 5: Crop the face
Run the following cell to take the JSON returned by the API and display only the faceRectangle
End of explanation
"""


img = mpimg.imread(multipleFaces)
plt.imshow(img)

multipleFacesData = detect(faceApiSubscriptionKey, multipleFaces)

face = json.loads(multipleFacesData)
faceTop = face[0]["faceRectangle"]["top"]
faceLeft = face[0]["faceRectangle"]["left"]
faceWidth = face[0]["faceRectangle"]["width"]
faceHeight = face[0]["faceRectangle"]["height"]

img = mpimg.imread(multipleFaces)
plt.imshow(img[faceTop:faceTop + faceHeight, faceLeft:faceLeft + faceWidth])

face = json.loads(multipleFacesData)
faceTop = face[1]["faceRectangle"]["top"]
faceLeft = face[1]["faceRectangle"]["left"]
faceWidth = face[1]["faceRectangle"]["width"]
faceHeight = face[1]["faceRectangle"]["height"]

img = mpimg.imread(multipleFaces)
plt.imshow(img[faceTop:faceTop + faceHeight, faceLeft:faceLeft + faceWidth])

"""
Explanation: Step 6: Detect multiple faces in an image
Run the following cells in sequence to display an image with multiple faces, call the API to detect faces, and display the results. Note that while there are three people in the image, the API only returns two faces due to the side-facing orientation of the third person.
End of explanation
"""


#deleteFaceList(faceApiSubscriptionKey, "sample")
createFaceList(faceApiSubscriptionKey, "sample")
getFaceList(faceApiSubscriptionKey, "sample")

"""
Explanation: Step 7: Create a Face List
Run the following cell to create a new face list called "sample", then show that the list is empty. 
A Face List is simply a collection of faces that remain unidentified and are referenced by Id. 
The API also has the ability to create a Person List for known people and call methods to identify new face images based on that list.
Note that there is also a delete function that is commented out in case you would like to delete and re-create your face list at a later time.
End of explanation
"""


img = mpimg.imread(faceA)
plt.imshow(img)
rawFaceDataA = detect(faceApiSubscriptionKey, faceA)
addFaceToFaceList(faceApiSubscriptionKey, "sample", faceA)

img = mpimg.imread(faceB)
plt.imshow(img)
rawFaceDataB = detect(faceApiSubscriptionKey, faceB)
addFaceToFaceList(faceApiSubscriptionKey, "sample", faceB)

img = mpimg.imread(faceC)
plt.imshow(img)
rawFaceDataC = detect(faceApiSubscriptionKey, faceC)
faceDataC = json.loads(rawFaceDataC)
addFaceToFaceList(faceApiSubscriptionKey, "sample", faceC)

img = mpimg.imread(faceD)
plt.imshow(img)
rawFaceDataD = detect(faceApiSubscriptionKey, faceD)
addFaceToFaceList(faceApiSubscriptionKey, "sample", faceD)

img = mpimg.imread(faceE)
plt.imshow(img)
rawFaceDataE = detect(faceApiSubscriptionKey, faceE)
addFaceToFaceList(faceApiSubscriptionKey, "sample", faceE)

"""
Explanation: Step 8: Add faces to your Face List
Run the following five cells in sequence to display images of five distinct people and load their face information into your face list. Your faces are referenced in the list using "persistedFaceId".
End of explanation
"""


getFaceList(faceApiSubscriptionKey, "sample")

"""
Explanation: Step 9: Display contents of your Face List
Run the following cell to display the contents of your recently populated face list. 
When you first created the list and called this function, it was empty.
You should now see the "persistedFaceId" values for the five faces that you added to your list.
End of explanation
"""


findSimilars(faceApiSubscriptionKey, "sample", thumbsUpFaceId, "5")

"""
Explanation: Step 10: Pass a sample image and find similar faces in your Face List
Run the following cell to compare the initial face of the "thumbs up woman" from Step 3 with the five faces in your face list.
One result should display with a reasonably high confidence value.
The "thumbs up woman" and "woman with apple" are the same person.
<img src="https://raw.githubusercontent.com/deldersveld/CortanaAnalyticsLabs/master/PerceptualIntelligence/Images/ThumbsUp.png" width="200">
<img src="https://raw.githubusercontent.com/deldersveld/CortanaAnalyticsLabs/master/PerceptualIntelligence/Images/FaceA.png" width="300">
End of explanation
"""


