This repository has been archived by the owner on Nov 8, 2021. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Initial version for sample. * README update. - Remove TODO section. - Remove redundant empty lines. * Remove Jupyter Notebook and corresponding README. * Several logic bug fix. * Several view bugs have been fixed.
- Loading branch information
1 parent
d4041d6
commit 856d9bc
Showing
17 changed files
with
1,719 additions
and
296 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,3 +91,4 @@ ENV/ | |
# Custom | ||
*.swp | ||
config.py | ||
Subscription.txt |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
File: main.py | ||
Description: main script for Python SDK sample. | ||
""" | ||
|
||
from view import MyApp | ||
|
||
|
||
if __name__ == "__main__": | ||
app = MyApp(False) | ||
app.MainLoop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
File: __init__.py | ||
Description: Model components for Python SDK sample. | ||
""" | ||
from model.face import Face |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
File: face.py | ||
Description: Face model for Python SDK Sample. | ||
""" | ||
|
||
import wx | ||
|
||
import util | ||
|
||
|
||
class Face(object): | ||
"""Face Model for each face.""" | ||
def __init__(self, res, path, size=util.MAX_THUMBNAIL_SIZE): | ||
super(Face, self).__init__() | ||
self.path = path | ||
self.bmp = wx.Bitmap(path) | ||
self.name = None | ||
if res.get('faceId'): | ||
self.id = res['faceId'] | ||
if res.get('persistedFaceId'): | ||
self.persisted_id = res['persistedFaceId'] | ||
if res.get('faceRectangle'): | ||
rect = res['faceRectangle'] | ||
self.left = int(rect['left']) | ||
self.top = int(rect['top']) | ||
self.width = int(rect['width']) | ||
self.height = int(rect['height']) | ||
self.bmp = self.bmp.GetSubBitmap(wx.Rect( | ||
self.left, self.top, self.width, self.height)) | ||
if res.get('faceAttributes'): | ||
attr = res['faceAttributes'] | ||
self.age = int(attr['age']) | ||
self.gender = attr['gender'] | ||
self.smile = float(attr['smile']) > 0 and 'Smile' or 'Not Smile' | ||
self.glasses = attr['glasses'] | ||
self.bmp = util.scale_bitmap(self.bmp, size) | ||
|
||
def set_name(self, name): | ||
"""Set the name for the face.""" | ||
self.name = name |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
File: util.py | ||
Description: util module for Python SDK sample. | ||
""" | ||
|
||
from threading import Thread | ||
import os.path | ||
|
||
import wx | ||
|
||
try: | ||
import cognitive_face as CF | ||
except ImportError: | ||
import sys | ||
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
sys.path.insert(0, ROOT_DIR) | ||
import cognitive_face as CF | ||
|
||
|
||
IMAGE_WILDCARD = 'Image files (*.jpg, *.png)|*.jpg; *.png' | ||
INNER_PANEL_WIDTH = 710 | ||
MAX_IMAGE_SIZE = 300 | ||
MAX_THUMBNAIL_SIZE = 75 | ||
STYLE = wx.SIMPLE_BORDER | ||
SUBSCRIPTION_KEY_FILENAME = 'Subscription.txt' | ||
|
||
LOG_FACE_LIST_REQUEST = ( | ||
'Request: Face List {} will be used for build person database. ' | ||
'Checking whether group exists.' | ||
) | ||
LOG_FACE_LIST_NOT_EXIST = 'Response: Face List {} does not exist before.' | ||
LOG_FACE_LIST_EXIST = 'Response: Face List {} exists.' | ||
|
||
|
||
class SubscriptionKey(object): | ||
"""Subscription Key.""" | ||
|
||
@classmethod | ||
def get(cls): | ||
"""Get the subscription key.""" | ||
if not hasattr(cls, 'key'): | ||
cls.key = '' | ||
if not cls.key: | ||
if os.path.isfile(SUBSCRIPTION_KEY_FILENAME): | ||
with file(SUBSCRIPTION_KEY_FILENAME) as fin: | ||
cls.key = fin.read().strip() | ||
else: | ||
cls.key = '' | ||
CF.Key.set(cls.key) | ||
return cls.key | ||
|
||
@classmethod | ||
def set(cls, key): | ||
"""Set the subscription key.""" | ||
cls.key = key | ||
with file(SUBSCRIPTION_KEY_FILENAME, 'w') as fout: | ||
print >>fout, key | ||
CF.Key.set(cls.key) | ||
|
||
@classmethod | ||
def delete(cls): | ||
"""Delete the subscription key.""" | ||
cls.key = '' | ||
if os.path.isfile(SUBSCRIPTION_KEY_FILENAME): | ||
os.remove(SUBSCRIPTION_KEY_FILENAME) | ||
CF.Key.set(cls.key) | ||
|
||
|
||
def scale_bitmap(bitmap, size=MAX_IMAGE_SIZE): | ||
"""Scale the image.""" | ||
img = bitmap.ConvertToImage() | ||
width = img.GetWidth() | ||
height = img.GetHeight() | ||
if width > height: | ||
new_width = size | ||
new_height = size * height / width | ||
else: | ||
new_height = size | ||
new_width = size * width / height | ||
img = img.Scale(new_width, new_height) | ||
return wx.BitmapFromImage(img) | ||
|
||
|
||
def draw_bitmap_rectangle(bitmap, faces): | ||
"""Draw rectangle on bitmap.""" | ||
dc = wx.MemoryDC(bitmap.bmp) | ||
dc.SetPen(wx.BLUE_PEN) | ||
dc.SetBrush(wx.TRANSPARENT_BRUSH) | ||
dc.SetTextBackground('black') | ||
dc.SetTextForeground('white') | ||
dc.SetBackgroundMode(wx.SOLID) | ||
dc.SetFont(wx.Font(8, | ||
wx.FONTFAMILY_DEFAULT, | ||
wx.FONTSTYLE_NORMAL, | ||
wx.FONTWEIGHT_BOLD)) | ||
for face in faces: | ||
dc.DrawRectangle( | ||
face.left * bitmap.scale, | ||
face.top * bitmap.scale, | ||
face.width * bitmap.scale, | ||
face.height * bitmap.scale, | ||
) | ||
if face.name: | ||
text_width, text_height = dc.GetTextExtent(face.name) | ||
dc.DrawText(face.name, | ||
face.left * bitmap.scale, | ||
face.top * bitmap.scale - text_height) | ||
dc.SelectObject(wx.NullBitmap) | ||
bitmap.bitmap.SetBitmap(bitmap.bmp) | ||
|
||
|
||
def async(func): | ||
"""Async wrapper.""" | ||
def wrapper(*args, **kwargs): | ||
"""docstring for wrapper""" | ||
thr = Thread(target=func, args=args, kwargs=kwargs) | ||
thr.start() | ||
return wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
""" | ||
File: __init__.py | ||
Description: View components for Python SDK sample. | ||
""" | ||
|
||
import wx | ||
import wx.lib.agw.labelbook as LB | ||
|
||
from wx.lib.agw.fmresources import INB_FIT_LABELTEXT | ||
from wx.lib.agw.fmresources import INB_LEFT | ||
from wx.lib.agw.fmresources import INB_NO_RESIZE | ||
|
||
from view.panel_detection import DetectionPanel | ||
from view.panel_subscription import SubscriptionPanel | ||
from view.panel_find_similar import FindSimilarPanel | ||
from view.panel_group import GroupPanel | ||
from view.panel_identification import IdentificationPanel | ||
from view.panel_verification import VerificationPanel | ||
|
||
TITLE = u"Microsoft Cognitive Services Face Samples" | ||
|
||
|
||
class MyLabelBook(LB.LabelBook): | ||
"""LabelBook part in Main Frame.""" | ||
def __init__(self, parent): | ||
agw_style = INB_LEFT | INB_FIT_LABELTEXT | INB_NO_RESIZE | ||
super(MyLabelBook, self).__init__(parent, agwStyle=agw_style) | ||
|
||
subscription_panel = SubscriptionPanel(self) | ||
subscription_text = u"Subscription Key Management" | ||
self.AddPage(subscription_panel, subscription_text, True) | ||
|
||
self.AddPage(wx.Panel(self), u"Select a scenario:") | ||
self.EnableTab(1, False) | ||
|
||
self.AddPage(DetectionPanel(self), u" - Face Detection") | ||
self.AddPage(FindSimilarPanel(self), u" - Face Find Similar") | ||
self.AddPage(GroupPanel(self), u" - Face Grouping") | ||
self.AddPage(IdentificationPanel(self), u" - Face Identification") | ||
self.AddPage(VerificationPanel(self), u" - Face Verification") | ||
|
||
|
||
class MyTitle(wx.Panel): | ||
"""Title part in Main Frame.""" | ||
def __init__(self, parent): | ||
super(MyTitle, self).__init__(parent) | ||
self.SetBackgroundColour('#00b294') | ||
self.SetMinSize((-1, 80)) | ||
|
||
sizer = wx.BoxSizer() | ||
sizer.AddStretchSpacer() | ||
|
||
family = wx.FONTFAMILY_DEFAULT | ||
style = wx.FONTSTYLE_NORMAL | ||
weight = wx.FONTWEIGHT_NORMAL | ||
font = wx.Font(20, family, style, weight) | ||
self.text = wx.StaticText(self, label=TITLE, style=wx.ALIGN_CENTER) | ||
self.text.SetFont(font) | ||
sizer.Add(self.text, flag=wx.ALIGN_CENTER_VERTICAL) | ||
|
||
sizer.AddStretchSpacer() | ||
self.SetSizer(sizer) | ||
|
||
|
||
class MyFrame(wx.Frame): | ||
"""Main Frame.""" | ||
def __init__(self, parent): | ||
super(MyFrame, self).__init__(parent, title=TITLE, size=(1280, 768)) | ||
|
||
icon_path = 'Assets/Microsoft-logo_rgb_c-gray.png' | ||
self.SetIcon(wx.Icon(icon_path)) | ||
|
||
sizer = wx.BoxSizer(wx.VERTICAL) | ||
|
||
self.title = MyTitle(self) | ||
sizer.Add(self.title, flag=wx.EXPAND) | ||
|
||
self.book = MyLabelBook(self) | ||
sizer.Add(self.book, 1, flag=wx.EXPAND) | ||
|
||
status_text = ( | ||
'Microsoft will receive the images you upload and may use them to ' | ||
'improve Face API and related services. By submitting an image, ' | ||
'you confirm you have consent from everyone in it.' | ||
) | ||
self.status = wx.StatusBar(self) | ||
self.status.SetStatusText(status_text) | ||
sizer.Add(self.status, flag=wx.EXPAND) | ||
|
||
self.SetSizer(sizer) | ||
self.Layout() | ||
|
||
|
||
class MyApp(wx.App): | ||
"""The whole app.""" | ||
def OnInit(self): | ||
"""Show main frame.""" | ||
frame = MyFrame(None) | ||
frame.Show() | ||
return True |
Oops, something went wrong.