New version of sample
This commit is contained in:
JesseWang 2016-09-26 17:05:10 +08:00 коммит произвёл wangjun
Родитель d313500942
Коммит 38cf124013
88 изменённых файлов: 9510 добавлений и 1720 удалений

Просмотреть файл

@ -1,717 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="LMA-Fd-pFW">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="LMA-Fd-pFW">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Project Oxford Face Demo-->
<scene sceneID="nGM-o8-Qc0">
<objects>
<viewController id="ULp-tZ-Nnd" customClass="MPODemoViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="kGy-ve-U1v"/>
<viewControllerLayoutGuide type="bottom" id="Kfy-Vv-g7Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="W48-74-6E2">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Cj8-Sg-8kv">
<rect key="frame" x="8" y="92" width="168" height="82"/>
<constraints>
<constraint firstAttribute="width" constant="168" id="EXo-vm-Ydp"/>
</constraints>
<string key="text">Detect faces, face landmarks, pose, gender, and age.
</string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mwb-6h-aGC">
<rect key="frame" x="8" y="205" width="168" height="82"/>
<constraints>
<constraint firstAttribute="width" constant="168" id="PHd-cm-syz"/>
</constraints>
<string key="text">Check if two faces belong to the same person.
</string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Group faces based on similarity." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gsm-AS-XxV">
<rect key="frame" x="8" y="310" width="168" height="41"/>
<constraints>
<constraint firstAttribute="width" constant="168" id="pb8-kD-MP9"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Fri-sc-iIV">
<rect key="frame" x="209" y="108" width="95" height="50"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="95" id="Bqy-Dc-qaF"/>
<constraint firstAttribute="height" constant="50" id="snR-WS-dhO"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Detection">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="selectImageButtonPressed:" destination="BA8-Uv-beZ" eventType="touchUpInside" id="XRs-9q-S54"/>
<segue destination="BA8-Uv-beZ" kind="push" id="4Yz-vy-Ipf"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Nh3-1z-Ecm">
<rect key="frame" x="209" y="221" width="95" height="50"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="COP-Fj-E9d"/>
<constraint firstAttribute="width" constant="95" id="a64-Hm-13f"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Verification">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="selectImageButtonPressed:" destination="BA8-Uv-beZ" eventType="touchUpInside" id="Nws-jC-yyw"/>
<segue destination="3gj-yH-Inh" kind="push" id="0c1-be-KRA"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kHT-Fh-L2Z">
<rect key="frame" x="209" y="306" width="95" height="50"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="95" id="RhZ-nS-yp6"/>
<constraint firstAttribute="height" constant="50" id="vL6-rv-qrB"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Grouping">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="selectImageButtonPressed:" destination="BA8-Uv-beZ" eventType="touchUpInside" id="dSj-br-V2A"/>
<segue destination="Ctm-Tx-v75" kind="push" id="z8H-bX-cu8"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YKA-D8-PWa">
<rect key="frame" x="8" y="502" width="304" height="58"/>
<string key="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 that you have that you have consent from everyone in it.</string>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="Kfy-Vv-g7Z" firstAttribute="top" secondItem="YKA-D8-PWa" secondAttribute="bottom" constant="8" id="0Y5-OU-XcC"/>
<constraint firstItem="Cj8-Sg-8kv" firstAttribute="top" secondItem="kGy-ve-U1v" secondAttribute="bottom" constant="28" id="2gR-2t-akQ"/>
<constraint firstItem="gsm-AS-XxV" firstAttribute="top" secondItem="Mwb-6h-aGC" secondAttribute="bottom" constant="23" id="3bK-UE-ht2"/>
<constraint firstItem="gsm-AS-XxV" firstAttribute="leading" secondItem="W48-74-6E2" secondAttribute="leadingMargin" constant="-8" id="3jd-CC-Lm6"/>
<constraint firstItem="kHT-Fh-L2Z" firstAttribute="top" secondItem="Nh3-1z-Ecm" secondAttribute="bottom" constant="35" id="5I9-G4-fFN"/>
<constraint firstItem="kHT-Fh-L2Z" firstAttribute="width" secondItem="Fri-sc-iIV" secondAttribute="width" id="6ef-jO-Odu"/>
<constraint firstItem="kHT-Fh-L2Z" firstAttribute="height" secondItem="Fri-sc-iIV" secondAttribute="height" id="8tj-XZ-sCM"/>
<constraint firstItem="gsm-AS-XxV" firstAttribute="leading" secondItem="Cj8-Sg-8kv" secondAttribute="leading" id="9xK-gR-aGU"/>
<constraint firstItem="Nh3-1z-Ecm" firstAttribute="trailing" secondItem="W48-74-6E2" secondAttribute="trailingMargin" id="MOl-YD-WCg"/>
<constraint firstItem="Nh3-1z-Ecm" firstAttribute="top" secondItem="Fri-sc-iIV" secondAttribute="bottom" constant="63" id="RPC-PW-Ifs"/>
<constraint firstItem="Mwb-6h-aGC" firstAttribute="top" secondItem="Cj8-Sg-8kv" secondAttribute="bottom" constant="31" id="Xzv-wj-1bQ"/>
<constraint firstItem="YKA-D8-PWa" firstAttribute="centerX" secondItem="W48-74-6E2" secondAttribute="centerX" id="YGi-q3-Ni0"/>
<constraint firstItem="Cj8-Sg-8kv" firstAttribute="leading" secondItem="W48-74-6E2" secondAttribute="leadingMargin" constant="-8" id="bZt-RR-GYh"/>
<constraint firstItem="kHT-Fh-L2Z" firstAttribute="trailing" secondItem="W48-74-6E2" secondAttribute="trailingMargin" id="fyB-fu-dLe"/>
<constraint firstItem="Nh3-1z-Ecm" firstAttribute="height" secondItem="Fri-sc-iIV" secondAttribute="height" id="gQE-fC-Dyc"/>
<constraint firstItem="YKA-D8-PWa" firstAttribute="leading" secondItem="W48-74-6E2" secondAttribute="leadingMargin" constant="-8" id="mWQ-xM-vLc"/>
<constraint firstItem="Nh3-1z-Ecm" firstAttribute="width" secondItem="Fri-sc-iIV" secondAttribute="width" id="mdU-sw-4IV"/>
<constraint firstItem="Mwb-6h-aGC" firstAttribute="leading" secondItem="Cj8-Sg-8kv" secondAttribute="leading" id="nAr-fp-VLY"/>
<constraint firstAttribute="trailingMargin" secondItem="YKA-D8-PWa" secondAttribute="trailing" constant="-8" id="oV4-3Y-3R3"/>
<constraint firstItem="Fri-sc-iIV" firstAttribute="top" secondItem="kGy-ve-U1v" secondAttribute="bottom" constant="44" id="sCC-tY-qwT"/>
<constraint firstItem="Fri-sc-iIV" firstAttribute="trailing" secondItem="W48-74-6E2" secondAttribute="trailingMargin" id="tpb-no-drX"/>
<constraint firstItem="Mwb-6h-aGC" firstAttribute="leading" secondItem="W48-74-6E2" secondAttribute="leadingMargin" constant="-8" id="ud8-nU-DOH"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Project Oxford Face Demo" id="UhN-kx-LHf"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="sdw-SZ-qhS" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="765" y="559"/>
</scene>
<!--Detection-->
<scene sceneID="Bpb-AF-bBm">
<objects>
<viewController definesPresentationContext="YES" id="BA8-Uv-beZ" customClass="MPODetectionViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="EmE-mS-gk4"/>
<viewControllerLayoutGuide type="bottom" id="R7g-jf-Sgn"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="31K-Kf-r1l">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QaA-WF-ZYd">
<rect key="frame" x="16" y="91" width="105" height="50"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="Kku-R4-wto"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Select Image">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="selectImageButtonPressed:" destination="BA8-Uv-beZ" eventType="touchUpInside" id="cPG-M6-P13"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="CP1-6Y-rwH">
<rect key="frame" x="130" y="510" width="60" height="50"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="RiS-lV-wMO"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Detect">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="detectionButtonPressed:" destination="BA8-Uv-beZ" eventType="touchUpInside" id="9Dr-Sg-0vd"/>
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="AXh-Z8-UCt">
<rect key="frame" x="161" y="64" width="159" height="150"/>
<constraints>
<constraint firstAttribute="width" constant="159" id="2z8-Tn-nqQ"/>
<constraint firstAttribute="height" constant="150" id="PaK-hG-KG2"/>
</constraints>
</imageView>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="9tE-nv-Kxs">
<rect key="frame" x="-4" y="232" width="320" height="264"/>
<color key="backgroundColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="calibratedRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="1DU-6D-6VW">
<size key="itemSize" width="200" height="144"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="fRa-qK-bRF" customClass="MPODetectionCollectionViewCell">
<rect key="frame" x="60" y="0.0" width="200" height="144"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="200" height="144"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="L4e-nT-cgn">
<rect key="frame" x="8" y="8" width="184" height="128"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="8bo-oJ-YPE">
<rect key="frame" x="0.0" y="0.0" width="46" height="128"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Szz-Bt-y1b">
<rect key="frame" x="0.0" y="0.0" width="46" height="128"/>
</imageView>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="FkR-dt-JPt">
<rect key="frame" x="46" y="0.0" width="138" height="128"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1Aw-B8-XeW">
<rect key="frame" x="0.0" y="0.0" width="138" height="21"/>
<edgeInsets key="layoutMargins" top="15" left="10" bottom="14" right="15"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ivO-u4-Xj2">
<rect key="frame" x="0.0" y="27" width="138" height="21"/>
<edgeInsets key="layoutMargins" top="8" left="8" bottom="8" right="8"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="p3i-Xi-vfA">
<rect key="frame" x="0.0" y="54" width="138" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JAa-08-7oD">
<rect key="frame" x="0.0" y="80" width="138" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vPh-J7-5gu">
<rect key="frame" x="0.0" y="107" width="138" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="8bo-oJ-YPE" firstAttribute="width" secondItem="FkR-dt-JPt" secondAttribute="width" multiplier="1:3" id="TsB-wc-o7X"/>
</constraints>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" red="0.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="L4e-nT-cgn" firstAttribute="bottom" secondItem="fRa-qK-bRF" secondAttribute="bottomMargin" id="WfI-P2-m8d"/>
<constraint firstItem="L4e-nT-cgn" firstAttribute="top" secondItem="fRa-qK-bRF" secondAttribute="topMargin" id="cgk-O1-r4y"/>
<constraint firstItem="L4e-nT-cgn" firstAttribute="leading" secondItem="fRa-qK-bRF" secondAttribute="leadingMargin" id="lj3-EQ-L85"/>
<constraint firstAttribute="trailingMargin" secondItem="L4e-nT-cgn" secondAttribute="trailing" id="wE4-dC-YbC"/>
</constraints>
<connections>
<outlet property="ageLabel" destination="1Aw-B8-XeW" id="hcy-qx-GYb"/>
<outlet property="genderLabel" destination="ivO-u4-Xj2" id="E7d-CT-Pw7"/>
<outlet property="headPoseLabel" destination="p3i-Xi-vfA" id="1Dm-Rh-8Oe"/>
<outlet property="imageView" destination="Szz-Bt-y1b" id="DDF-2e-Nc8"/>
<outlet property="moustacheLabel" destination="JAa-08-7oD" id="oSw-Av-Eq8"/>
<outlet property="smileLabel" destination="vPh-J7-5gu" id="UVl-dC-rOZ"/>
</connections>
</collectionViewCell>
</cells>
</collectionView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XLm-4p-U81">
<rect key="frame" x="12" y="184" width="0.0" height="0.0"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="QaA-WF-ZYd" firstAttribute="top" secondItem="EmE-mS-gk4" secondAttribute="bottom" constant="27" id="5Gl-Lf-wPm"/>
<constraint firstItem="XLm-4p-U81" firstAttribute="leading" secondItem="31K-Kf-r1l" secondAttribute="leadingMargin" constant="-4" id="8iC-oV-vgx"/>
<constraint firstItem="R7g-jf-Sgn" firstAttribute="top" secondItem="CP1-6Y-rwH" secondAttribute="bottom" constant="8" id="FKc-aG-qJN"/>
<constraint firstItem="9tE-nv-Kxs" firstAttribute="leading" secondItem="31K-Kf-r1l" secondAttribute="leadingMargin" constant="-20" id="IRa-hW-8bu"/>
<constraint firstItem="CP1-6Y-rwH" firstAttribute="top" secondItem="9tE-nv-Kxs" secondAttribute="bottom" constant="14" id="OuP-eQ-o8E"/>
<constraint firstItem="CP1-6Y-rwH" firstAttribute="centerX" secondItem="31K-Kf-r1l" secondAttribute="centerX" id="PKw-5F-kPL"/>
<constraint firstAttribute="leadingMargin" secondItem="QaA-WF-ZYd" secondAttribute="leading" id="X70-d1-vVG"/>
<constraint firstItem="XLm-4p-U81" firstAttribute="top" secondItem="QaA-WF-ZYd" secondAttribute="bottom" constant="43" id="Y6W-qY-LxH"/>
<constraint firstItem="9tE-nv-Kxs" firstAttribute="width" secondItem="31K-Kf-r1l" secondAttribute="width" id="bHP-kl-XED"/>
<constraint firstItem="9tE-nv-Kxs" firstAttribute="top" secondItem="AXh-Z8-UCt" secondAttribute="bottom" constant="18" id="biP-Ul-aLk"/>
<constraint firstAttribute="trailing" secondItem="AXh-Z8-UCt" secondAttribute="trailing" id="dTz-wO-r8q"/>
<constraint firstItem="AXh-Z8-UCt" firstAttribute="top" secondItem="EmE-mS-gk4" secondAttribute="bottom" id="hRL-Yo-ovp"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Detection" id="ghX-tY-Dd7"/>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="collectionView" destination="9tE-nv-Kxs" id="Pci-7i-ddr"/>
<outlet property="imageView" destination="AXh-Z8-UCt" id="OwR-yv-hot"/>
<outlet property="numberOfFacesDetectedLabel" destination="XLm-4p-U81" id="LhH-VG-w2W"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="8nr-xq-0ON" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1253" y="559"/>
</scene>
<!--Grouping View Controller-->
<scene sceneID="FBa-TO-Qlk">
<objects>
<viewController definesPresentationContext="YES" id="Ctm-Tx-v75" customClass="MPOGroupingViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="s3H-vi-cxu"/>
<viewControllerLayoutGuide type="bottom" id="zBy-4n-kVf"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="xSa-BO-WGP">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kpl-nN-dQE">
<rect key="frame" x="9" y="162" width="86" height="50"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="EEX-aP-20S"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Add Faces">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="addFacesButtonPressed:" destination="Ctm-Tx-v75" eventType="touchUpInside" id="xU5-Sl-KUZ"/>
<action selector="firstFaceSelectImageButtonPressed:" destination="3gj-yH-Inh" eventType="touchUpInside" id="FFa-pA-RvL"/>
</connections>
</button>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="4sK-0T-xfI">
<rect key="frame" x="103" y="72" width="210" height="229"/>
<color key="backgroundColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="8Wl-8O-vY5">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="XDb-lX-xdR" customClass="MPOImageCollectionViewCell">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="pUt-C1-yiO">
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstItem="pUt-C1-yiO" firstAttribute="width" secondItem="XDb-lX-xdR" secondAttribute="width" id="DRT-iu-9ra"/>
<constraint firstItem="pUt-C1-yiO" firstAttribute="height" secondItem="XDb-lX-xdR" secondAttribute="height" id="OSI-U2-Wh8"/>
<constraint firstItem="pUt-C1-yiO" firstAttribute="centerX" secondItem="XDb-lX-xdR" secondAttribute="centerX" id="t55-FY-ocs"/>
<constraint firstItem="pUt-C1-yiO" firstAttribute="centerY" secondItem="XDb-lX-xdR" secondAttribute="centerY" id="wpm-Xc-jYF"/>
</constraints>
<connections>
<outlet property="imageView" destination="pUt-C1-yiO" id="kyc-19-qHO"/>
</connections>
</collectionViewCell>
</cells>
</collectionView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uCV-p2-Wqc">
<rect key="frame" x="16" y="81" width="79" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9b7-7A-c3y">
<rect key="frame" x="113" y="510" width="94" height="50"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="94" id="bKx-hE-M04"/>
<constraint firstAttribute="height" constant="50" id="eci-Ju-ADb"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Group">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="firstFaceSelectImageButtonPressed:" destination="3gj-yH-Inh" eventType="touchUpInside" id="ADX-Dw-gpf"/>
<action selector="groupButtonPressed:" destination="Ctm-Tx-v75" eventType="touchUpInside" id="9en-db-fgl"/>
</connections>
</button>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="112" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="Qrv-1P-Z7W">
<rect key="frame" x="5" y="317" width="312" height="185"/>
<color key="backgroundColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="calibratedRGB"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="cell" rowHeight="112" id="eyL-M8-l1S" customClass="MPOGroupingTableViewCell">
<rect key="frame" x="0.0" y="28" width="312" height="112"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="eyL-M8-l1S" id="Tq3-kM-aF6">
<rect key="frame" x="0.0" y="0.0" width="312" height="112"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" misplaced="YES" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="qBm-xa-pSA">
<rect key="frame" x="0.0" y="0.0" width="312" height="111"/>
<color key="backgroundColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="6tc-TV-n8Z">
<size key="itemSize" width="119" height="75"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="groupCell" id="OEb-Wy-k3P" customClass="MPOImageCollectionViewCell">
<rect key="frame" x="0.0" y="18" width="119" height="75"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="119" height="75"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Sfc-nV-ySE">
<rect key="frame" x="0.0" y="0.0" width="119" height="75"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstItem="Sfc-nV-ySE" firstAttribute="width" secondItem="OEb-Wy-k3P" secondAttribute="width" id="4Af-ye-9Lu"/>
<constraint firstItem="Sfc-nV-ySE" firstAttribute="centerX" secondItem="OEb-Wy-k3P" secondAttribute="centerX" id="8b6-EI-G5c"/>
<constraint firstItem="Sfc-nV-ySE" firstAttribute="height" secondItem="OEb-Wy-k3P" secondAttribute="height" id="bd7-Bg-OSz"/>
<constraint firstItem="Sfc-nV-ySE" firstAttribute="centerY" secondItem="OEb-Wy-k3P" secondAttribute="centerY" id="nHn-BL-5yP"/>
</constraints>
<connections>
<outlet property="imageView" destination="Sfc-nV-ySE" id="cGt-lr-dHf"/>
</connections>
</collectionViewCell>
</cells>
<connections>
<outlet property="dataSource" destination="eyL-M8-l1S" id="7wJ-PU-AxQ"/>
<outlet property="delegate" destination="eyL-M8-l1S" id="S9T-zQ-x0V"/>
</connections>
</collectionView>
</subviews>
<constraints>
<constraint firstItem="qBm-xa-pSA" firstAttribute="centerX" secondItem="Tq3-kM-aF6" secondAttribute="centerX" id="IU4-Jw-oGU"/>
<constraint firstItem="qBm-xa-pSA" firstAttribute="width" secondItem="Tq3-kM-aF6" secondAttribute="width" id="Xfa-F3-Ak7"/>
<constraint firstItem="qBm-xa-pSA" firstAttribute="height" secondItem="Tq3-kM-aF6" secondAttribute="height" id="kgU-iH-YDr"/>
<constraint firstItem="qBm-xa-pSA" firstAttribute="centerY" secondItem="Tq3-kM-aF6" secondAttribute="centerY" id="mEg-1h-zKd"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<outlet property="collectionView" destination="qBm-xa-pSA" id="JkM-JU-coI"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="Ctm-Tx-v75" id="yHU-ig-PMa"/>
<outlet property="delegate" destination="Ctm-Tx-v75" id="0kC-6i-dUj"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" red="0.74117647060000003" green="0.76470588240000004" blue="0.78039215689999997" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="leadingMargin" secondItem="uCV-p2-Wqc" secondAttribute="leading" id="8ff-v4-hGx"/>
<constraint firstAttribute="trailingMargin" secondItem="4sK-0T-xfI" secondAttribute="trailing" constant="-9" id="AjW-IL-hES"/>
<constraint firstItem="9b7-7A-c3y" firstAttribute="top" secondItem="Qrv-1P-Z7W" secondAttribute="bottom" constant="8" id="BGZ-NJ-N9M"/>
<constraint firstItem="9b7-7A-c3y" firstAttribute="centerX" secondItem="xSa-BO-WGP" secondAttribute="centerX" id="Eyb-lu-xuN"/>
<constraint firstItem="uCV-p2-Wqc" firstAttribute="top" secondItem="s3H-vi-cxu" secondAttribute="bottom" constant="17" id="I02-9W-zFj"/>
<constraint firstItem="4sK-0T-xfI" firstAttribute="leading" secondItem="kpl-nN-dQE" secondAttribute="trailing" constant="8" id="Oqe-gX-zga"/>
<constraint firstItem="4sK-0T-xfI" firstAttribute="top" secondItem="s3H-vi-cxu" secondAttribute="bottom" constant="8" id="PwC-I5-CZN"/>
<constraint firstItem="Qrv-1P-Z7W" firstAttribute="top" secondItem="kpl-nN-dQE" secondAttribute="bottom" constant="105" id="VY9-Y9-6Kk"/>
<constraint firstAttribute="trailingMargin" secondItem="Qrv-1P-Z7W" secondAttribute="trailing" constant="-13" id="X3T-vn-W8n"/>
<constraint firstItem="Qrv-1P-Z7W" firstAttribute="top" secondItem="4sK-0T-xfI" secondAttribute="bottom" constant="16" id="piB-1E-kI1"/>
<constraint firstItem="4sK-0T-xfI" firstAttribute="leading" secondItem="uCV-p2-Wqc" secondAttribute="trailing" constant="8" id="u67-zy-OoR"/>
<constraint firstItem="kpl-nN-dQE" firstAttribute="top" secondItem="uCV-p2-Wqc" secondAttribute="bottom" constant="60" id="uBf-L0-Lia"/>
<constraint firstItem="zBy-4n-kVf" firstAttribute="top" secondItem="9b7-7A-c3y" secondAttribute="bottom" constant="8" id="vSg-Hv-rFk"/>
<constraint firstItem="kpl-nN-dQE" firstAttribute="leading" secondItem="xSa-BO-WGP" secondAttribute="leadingMargin" constant="-7" id="ymE-sL-x0A"/>
<constraint firstItem="Qrv-1P-Z7W" firstAttribute="leading" secondItem="xSa-BO-WGP" secondAttribute="leadingMargin" constant="-11" id="zb6-xe-6PW"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="eCd-qZ-OfF"/>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="facesCollectionView" destination="4sK-0T-xfI" id="BpZ-97-C7p"/>
<outlet property="numberOfFacesDetectedLabel" destination="uCV-p2-Wqc" id="rGe-vh-R2o"/>
<outlet property="tableView" destination="Qrv-1P-Z7W" id="CBb-US-KuC"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Syr-tN-5eS" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="506" y="1222"/>
</scene>
<!--Verification-->
<scene sceneID="wWA-uL-B6p">
<objects>
<viewController definesPresentationContext="YES" id="3gj-yH-Inh" customClass="MPOVerificationViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="MFb-S1-K5v"/>
<viewControllerLayoutGuide type="bottom" id="FCf-ye-Mls"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="ojm-J5-hrF">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Bco-ep-Jzz">
<rect key="frame" x="11" y="123" width="105" height="28"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Select Image">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="firstFaceSelectImageButtonPressed:" destination="3gj-yH-Inh" eventType="touchUpInside" id="Ncu-zQ-TS9"/>
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="hAo-KD-w5r">
<rect key="frame" x="124" y="84" width="120" height="201"/>
<constraints>
<constraint firstAttribute="width" constant="120" id="iig-0G-51K"/>
</constraints>
</imageView>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="nTe-Mj-dBW">
<rect key="frame" x="252" y="84" width="65" height="201"/>
<color key="backgroundColor" red="0.17254901960784313" green="0.24313725490196078" blue="0.31372549019607843" alpha="1" colorSpace="calibratedRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="UP9-lz-uUJ">
<size key="itemSize" width="60" height="116"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="VjF-ws-L2L" customClass="MPOImageCollectionViewCell">
<rect key="frame" x="3" y="0.0" width="60" height="116"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="60" height="116"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="6V7-0A-8Gs">
<rect key="frame" x="0.0" y="0.0" width="60" height="116"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstItem="6V7-0A-8Gs" firstAttribute="width" secondItem="VjF-ws-L2L" secondAttribute="width" id="4GC-26-11K"/>
<constraint firstItem="6V7-0A-8Gs" firstAttribute="centerX" secondItem="VjF-ws-L2L" secondAttribute="centerX" id="GqS-zh-K50"/>
<constraint firstItem="6V7-0A-8Gs" firstAttribute="centerY" secondItem="VjF-ws-L2L" secondAttribute="centerY" id="NqP-8V-sbr"/>
<constraint firstItem="6V7-0A-8Gs" firstAttribute="height" secondItem="VjF-ws-L2L" secondAttribute="height" id="ryh-zE-2XG"/>
</constraints>
<connections>
<outlet property="imageView" destination="6V7-0A-8Gs" id="hVN-QW-qd7"/>
</connections>
</collectionViewCell>
</cells>
<connections>
<outlet property="dataSource" destination="3gj-yH-Inh" id="HlO-a6-aSE"/>
<outlet property="delegate" destination="3gj-yH-Inh" id="Utw-wc-wC4"/>
</connections>
</collectionView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Second Face" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3e3-ue-rii">
<rect key="frame" x="14" y="300" width="99" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3bY-IX-SQI">
<rect key="frame" x="11" y="339" width="105" height="28"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Select Image">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="secondFaceSelectImageButtonPressed:" destination="3gj-yH-Inh" eventType="touchUpInside" id="Mdc-Fe-mcv"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SeE-dO-AqQ">
<rect key="frame" x="100" y="509" width="120" height="28"/>
<color key="backgroundColor" red="0.1019607843" green="0.73725490199999999" blue="0.61176470589999998" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" title="Verify">
<color key="titleColor" white="0.95999999999999996" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="verifyButtonPressed:" destination="3gj-yH-Inh" eventType="touchUpInside" id="2fz-Dt-ESW"/>
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="it7-ll-sJg">
<rect key="frame" x="124" y="300" width="120" height="201"/>
</imageView>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="lX2-si-fIx">
<rect key="frame" x="252" y="300" width="65" height="201"/>
<color key="backgroundColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="calibratedRGB"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="Gn8-n0-PhG">
<size key="itemSize" width="60" height="67"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="cell" id="jAY-Te-Y0N" customClass="MPOImageCollectionViewCell">
<rect key="frame" x="3" y="0.0" width="60" height="67"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="60" height="67"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Dst-43-Spx">
<rect key="frame" x="0.0" y="0.0" width="60" height="67"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstItem="Dst-43-Spx" firstAttribute="height" secondItem="jAY-Te-Y0N" secondAttribute="height" id="2Ef-J3-PUd"/>
<constraint firstItem="Dst-43-Spx" firstAttribute="centerX" secondItem="jAY-Te-Y0N" secondAttribute="centerX" id="2rW-1j-HPo"/>
<constraint firstItem="Dst-43-Spx" firstAttribute="centerY" secondItem="jAY-Te-Y0N" secondAttribute="centerY" id="ikg-ta-8Fo"/>
<constraint firstItem="Dst-43-Spx" firstAttribute="width" secondItem="jAY-Te-Y0N" secondAttribute="width" id="uii-Xt-xnf"/>
</constraints>
<connections>
<outlet property="imageView" destination="Dst-43-Spx" id="qK2-9z-tVH"/>
</connections>
</collectionViewCell>
</cells>
<connections>
<outlet property="dataSource" destination="3gj-yH-Inh" id="GUC-eC-hie"/>
<outlet property="delegate" destination="3gj-yH-Inh" id="vEr-25-pV7"/>
</connections>
</collectionView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="First Face" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VjR-0n-kyG">
<rect key="frame" x="26" y="84" width="74" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.74117647058823533" green="0.76470588235294112" blue="0.7803921568627451" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="nTe-Mj-dBW" firstAttribute="top" secondItem="MFb-S1-K5v" secondAttribute="bottom" constant="20" id="0yb-OI-8Sv"/>
<constraint firstItem="Bco-ep-Jzz" firstAttribute="leading" secondItem="ojm-J5-hrF" secondAttribute="leadingMargin" constant="-5" id="1O7-ff-anV"/>
<constraint firstItem="nTe-Mj-dBW" firstAttribute="height" secondItem="lX2-si-fIx" secondAttribute="height" id="7dV-nr-8sd"/>
<constraint firstItem="SeE-dO-AqQ" firstAttribute="top" secondItem="it7-ll-sJg" secondAttribute="bottom" constant="8" id="8sQ-NQ-ewl"/>
<constraint firstItem="3bY-IX-SQI" firstAttribute="leading" secondItem="ojm-J5-hrF" secondAttribute="leadingMargin" constant="-5" id="BDX-KS-Jki"/>
<constraint firstItem="SeE-dO-AqQ" firstAttribute="centerX" secondItem="ojm-J5-hrF" secondAttribute="centerX" id="Ij1-WU-mhu"/>
<constraint firstItem="lX2-si-fIx" firstAttribute="leading" secondItem="it7-ll-sJg" secondAttribute="trailing" constant="8" id="PWH-uW-n34"/>
<constraint firstItem="lX2-si-fIx" firstAttribute="top" secondItem="3e3-ue-rii" secondAttribute="top" id="Qge-YZ-hTJ"/>
<constraint firstItem="nTe-Mj-dBW" firstAttribute="leading" secondItem="lX2-si-fIx" secondAttribute="leading" id="S1H-pI-ngV"/>
<constraint firstItem="nTe-Mj-dBW" firstAttribute="width" secondItem="lX2-si-fIx" secondAttribute="width" id="UJk-JQ-GOu"/>
<constraint firstItem="it7-ll-sJg" firstAttribute="width" secondItem="hAo-KD-w5r" secondAttribute="width" id="Z4d-Gd-HsL"/>
<constraint firstItem="nTe-Mj-dBW" firstAttribute="leading" secondItem="hAo-KD-w5r" secondAttribute="trailing" constant="8" id="a9e-KG-h6k"/>
<constraint firstItem="Bco-ep-Jzz" firstAttribute="top" secondItem="VjR-0n-kyG" secondAttribute="bottom" constant="18" id="aAh-qb-BjF"/>
<constraint firstItem="VjR-0n-kyG" firstAttribute="top" secondItem="MFb-S1-K5v" secondAttribute="bottom" constant="20" id="bcM-q5-BQZ"/>
<constraint firstItem="SeE-dO-AqQ" firstAttribute="width" secondItem="it7-ll-sJg" secondAttribute="width" id="c9f-nS-6VV"/>
<constraint firstItem="hAo-KD-w5r" firstAttribute="top" secondItem="MFb-S1-K5v" secondAttribute="bottom" constant="20" id="dVT-D0-bPD"/>
<constraint firstItem="hAo-KD-w5r" firstAttribute="height" secondItem="it7-ll-sJg" secondAttribute="height" id="dWd-ic-6Qa"/>
<constraint firstItem="lX2-si-fIx" firstAttribute="top" secondItem="it7-ll-sJg" secondAttribute="top" id="dnI-N6-fr0"/>
<constraint firstItem="it7-ll-sJg" firstAttribute="leading" secondItem="3bY-IX-SQI" secondAttribute="trailing" constant="8" id="fw0-fA-xUp"/>
<constraint firstItem="FCf-ye-Mls" firstAttribute="top" secondItem="lX2-si-fIx" secondAttribute="bottom" constant="67" id="gSs-FJ-fxm"/>
<constraint firstItem="it7-ll-sJg" firstAttribute="top" secondItem="hAo-KD-w5r" secondAttribute="bottom" constant="15" id="iFc-nb-hQh"/>
<constraint firstItem="3e3-ue-rii" firstAttribute="leading" secondItem="ojm-J5-hrF" secondAttribute="leadingMargin" constant="-2" id="j2K-Kc-oC2"/>
<constraint firstItem="Bco-ep-Jzz" firstAttribute="leading" secondItem="ojm-J5-hrF" secondAttribute="leadingMargin" constant="-5" id="jfp-x3-RIx"/>
<constraint firstItem="lX2-si-fIx" firstAttribute="top" secondItem="nTe-Mj-dBW" secondAttribute="bottom" constant="15" id="kK5-fk-V3p"/>
<constraint firstItem="VjR-0n-kyG" firstAttribute="leading" secondItem="ojm-J5-hrF" secondAttribute="leadingMargin" constant="10" id="n3d-HI-PUu"/>
<constraint firstItem="hAo-KD-w5r" firstAttribute="leading" secondItem="Bco-ep-Jzz" secondAttribute="trailing" constant="8" id="tAd-iT-Mf4"/>
<constraint firstItem="3bY-IX-SQI" firstAttribute="top" secondItem="3e3-ue-rii" secondAttribute="bottom" constant="18" id="xEB-qg-eQC"/>
<constraint firstAttribute="trailingMargin" secondItem="nTe-Mj-dBW" secondAttribute="trailing" constant="-13" id="yc6-44-zEm"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Verification" id="AJD-RP-bJt"/>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<connections>
<outlet property="firstFaceCollectionView" destination="nTe-Mj-dBW" id="G6x-vu-Hcd"/>
<outlet property="firstFaceImageView" destination="hAo-KD-w5r" id="h69-Pp-VCG"/>
<outlet property="secondFaceCollectionView" destination="lX2-si-fIx" id="fSy-LH-Gdb"/>
<outlet property="secondFaceImageView" destination="it7-ll-sJg" id="giF-ny-uqU"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="1hd-lg-xjM" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1166" y="1234"/>
</scene>
<!--Navigation Controller-->
<!--Main Navigation Controller-->
<scene sceneID="YKg-aq-k9J">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="LMA-Fd-pFW" sceneMemberID="viewController">
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="LMA-Fd-pFW" customClass="MPOMainNavigationController" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="oqe-IA-eLp">
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" translucent="NO" prompted="NO"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="oqe-IA-eLp">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="ULp-tZ-Nnd" kind="relationship" relationship="rootViewController" id="9Hm-YM-dYc"/>
<segue destination="cFY-th-UOk" kind="relationship" relationship="rootViewController" id="HOy-X1-txi"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="EPZ-zD-xNo" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="233" y="559"/>
<point key="canvasLocation" x="113" y="413"/>
</scene>
<!--Cognitive Services Face Demo-->
<scene sceneID="r4y-Yc-f2v">
<objects>
<viewController id="cFY-th-UOk" customClass="MPOMainViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Alu-z1-O4M"/>
<viewControllerLayoutGuide type="bottom" id="8h1-1F-v5v"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="KTp-Zt-BlG">
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" title="Cognitive Services Face Demo" id="Fmm-Pr-WMt"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Mul-6q-QFY" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="506" y="401"/>
</scene>
</scenes>
</document>

6
Example/Pods/Pods.xcodeproj/project.pbxproj сгенерированный
Просмотреть файл

@ -504,7 +504,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0730;
};
buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
compatibilityVersion = "Xcode 3.2";
@ -678,6 +678,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = "Target Support Files/ProjectOxfordFace/ProjectOxfordFace.modulemap";
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_BUNDLE_IDENTIFIER}";
PRODUCT_NAME = ProjectOxfordFace;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
@ -696,6 +697,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "Target Support Files/ProjectOxfordFace/ResourceBundle-ProjectOxfordFace-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_BUNDLE_IDENTIFIER}";
PRODUCT_NAME = ProjectOxfordFace;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
@ -746,6 +748,7 @@
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = "Target Support Files/ProjectOxfordFace/ResourceBundle-ProjectOxfordFace-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_BUNDLE_IDENTIFIER}";
PRODUCT_NAME = ProjectOxfordFace;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
@ -774,6 +777,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MODULEMAP_FILE = "Target Support Files/ProjectOxfordFace/ProjectOxfordFace.modulemap";
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = "${PRODUCT_BUNDLE_IDENTIFIER}";
PRODUCT_NAME = ProjectOxfordFace;
SDKROOT = iphoneos;
SKIP_INSTALL = YES;

Просмотреть файл

@ -2,25 +2,25 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

Просмотреть файл

@ -2,23 +2,23 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSPrincipalClass</key>
<string></string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

Просмотреть файл

@ -14,14 +14,44 @@
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; };
6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; };
6003F59E195388D20070C39A /* MPOAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* MPOAppDelegate.m */; };
6003F5A7195388D20070C39A /* MPODemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* MPODemoViewController.m */; };
6003F59E195388D20070C39A /* MPOAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* MPOAppDelegate.mm */; };
6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; };
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; };
7B4071AD1D65EC1100362256 /* MPOAddPersonFaceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B4071AC1D65EC1100362256 /* MPOAddPersonFaceController.m */; };
7B4071B01D69BEDB00362256 /* UIViewController+BackButtonHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B4071AF1D69BEDB00362256 /* UIViewController+BackButtonHandler.m */; };
7B4071B31D69BFF300362256 /* MPOMainNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B4071B21D69BFF300362256 /* MPOMainNavigationController.m */; };
7B643B7E1D5F44780012F342 /* Colours.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B701D5F44780012F342 /* Colours.m */; };
7B643B7F1D5F44780012F342 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 7B643B711D5F44780012F342 /* LICENSE */; };
7B643B811D5F44780012F342 /* ImageHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B771D5F44780012F342 /* ImageHelper.m */; };
7B643B821D5F44780012F342 /* MBProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B7A1D5F44780012F342 /* MBProgressHUD.m */; };
7B643B8C1D5F450F0012F342 /* MPOPersonFaceCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B871D5F450F0012F342 /* MPOPersonFaceCell.m */; };
7B643B8D1D5F450F0012F342 /* MPOPersonFaceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B643B881D5F450F0012F342 /* MPOPersonFaceCell.xib */; };
7B643B8E1D5F450F0012F342 /* MPOSimpleFaceCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B8A1D5F450F0012F342 /* MPOSimpleFaceCell.m */; };
7B643B8F1D5F450F0012F342 /* MPOSimpleFaceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7B643B8B1D5F450F0012F342 /* MPOSimpleFaceCell.xib */; };
7B643B961D5F45190012F342 /* GroupPerson.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B911D5F45190012F342 /* GroupPerson.m */; };
7B643B971D5F45190012F342 /* PersonFace.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B931D5F45190012F342 /* PersonFace.m */; };
7B643B981D5F45190012F342 /* PersonGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B951D5F45190012F342 /* PersonGroup.m */; };
7B643BAB1D5F452B0012F342 /* MPOMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B9A1D5F452B0012F342 /* MPOMainViewController.m */; };
7B643BAC1D5F452B0012F342 /* MPODetectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B9C1D5F452B0012F342 /* MPODetectionViewController.m */; };
7B643BAD1D5F452B0012F342 /* MPOVerificationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643B9E1D5F452B0012F342 /* MPOVerificationViewController.m */; };
7B643BAE1D5F452B0012F342 /* MPOGroupingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BA01D5F452B0012F342 /* MPOGroupingViewController.m */; };
7B643BAF1D5F452B0012F342 /* MPOSimilarFaceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BA21D5F452B0012F342 /* MPOSimilarFaceViewController.m */; };
7B643BB01D5F452B0012F342 /* MPOIdentificationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BA41D5F452B0012F342 /* MPOIdentificationViewController.m */; };
7B643BB11D5F452B0012F342 /* MPOPersonGroupListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BA61D5F452B0012F342 /* MPOPersonGroupListController.m */; };
7B643BB21D5F452B0012F342 /* MPOPersonGroupController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BA81D5F452B0012F342 /* MPOPersonGroupController.m */; };
7B643BB31D5F452B0012F342 /* MPOPersonFacesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BAA1D5F452B0012F342 /* MPOPersonFacesController.m */; };
7B643BC51D5F467B0012F342 /* UIImage+Crop.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BB61D5F467B0012F342 /* UIImage+Crop.m */; };
7B643BC61D5F467B0012F342 /* UIImage+FixOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BB81D5F467B0012F342 /* UIImage+FixOrientation.m */; };
7B643BC71D5F467B0012F342 /* UIImage+Resize.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BBA1D5F467B0012F342 /* UIImage+Resize.m */; };
7B643BC81D5F467B0012F342 /* UIViewController+DismissKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BBC1D5F467B0012F342 /* UIViewController+DismissKeyboard.m */; };
7B643BCA1D5F467B0012F342 /* ViewUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BC01D5F467B0012F342 /* ViewUtils.m */; };
7B643BCB1D5F467B0012F342 /* CommonUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BC21D5F467B0012F342 /* CommonUtil.m */; };
7B643BD51D6041E00012F342 /* MPODetectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BD41D6041E00012F342 /* MPODetectionCell.m */; };
7B643BDB1D60604A0012F342 /* MPOGroupSectionHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B643BDA1D60604A0012F342 /* MPOGroupSectionHeaderView.m */; };
EF575B0F1C6872540021A3AD /* DetectTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EF575B061C6872540021A3AD /* DetectTestCase.m */; };
EF575B101C6872540021A3AD /* GroupTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EF575B071C6872540021A3AD /* GroupTestCase.m */; };
EF575B111C6872540021A3AD /* IdentifyTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EF575B081C6872540021A3AD /* IdentifyTestCase.m */; };
@ -29,11 +59,6 @@
EF575B131C6872540021A3AD /* PersonGroupTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EF575B0C1C6872540021A3AD /* PersonGroupTestCase.m */; };
EF575B141C6872540021A3AD /* SimilarTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EF575B0D1C6872540021A3AD /* SimilarTestCase.m */; };
EF575B151C6872540021A3AD /* VerifyTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EF575B0E1C6872540021A3AD /* VerifyTestCase.m */; };
EF5E15691C9CA3C800BA4B22 /* MPOGroupingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EF5E15681C9CA3C800BA4B22 /* MPOGroupingViewController.m */; };
EF5E156C1C9CAF5B00BA4B22 /* MPOGroupingTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = EF5E156B1C9CAF5B00BA4B22 /* MPOGroupingTableViewCell.m */; };
EF5E156F1C9CB89500BA4B22 /* MPOGroupingFaceCellObject.m in Sources */ = {isa = PBXBuildFile; fileRef = EF5E156E1C9CB89500BA4B22 /* MPOGroupingFaceCellObject.m */; };
EF707D731CA1061B00C7AF5D /* MPOActivityIndicatorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EF707D711CA1061B00C7AF5D /* MPOActivityIndicatorViewController.m */; };
EF707D741CA1061B00C7AF5D /* MPOActivityIndicatorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = EF707D721CA1061B00C7AF5D /* MPOActivityIndicatorViewController.xib */; };
EF7E8CA01CA0C5A8005FFB2F /* MSC12_John_001.jpg in Resources */ = {isa = PBXBuildFile; fileRef = EF7E8C991CA0C5A8005FFB2F /* MSC12_John_001.jpg */; };
EF7E8CA11CA0C5A8005FFB2F /* MSC12_John_002.jpg in Resources */ = {isa = PBXBuildFile; fileRef = EF7E8C9A1CA0C5A8005FFB2F /* MSC12_John_002.jpg */; };
EF7E8CA21CA0C5A8005FFB2F /* MSC13_ChrisA_01.jpg in Resources */ = {isa = PBXBuildFile; fileRef = EF7E8C9B1CA0C5A8005FFB2F /* MSC13_ChrisA_01.jpg */; };
@ -41,13 +66,8 @@
EF7E8CA41CA0C5A8005FFB2F /* MSC13_ChrisA_04.jpg in Resources */ = {isa = PBXBuildFile; fileRef = EF7E8C9D1CA0C5A8005FFB2F /* MSC13_ChrisA_04.jpg */; };
EF7E8CA51CA0C5A8005FFB2F /* WIN12_Alberto_01.png in Resources */ = {isa = PBXBuildFile; fileRef = EF7E8C9E1CA0C5A8005FFB2F /* WIN12_Alberto_01.png */; };
EF7E8CA61CA0C5A8005FFB2F /* WIN12_Alberto_03.png in Resources */ = {isa = PBXBuildFile; fileRef = EF7E8C9F1CA0C5A8005FFB2F /* WIN12_Alberto_03.png */; };
EF8BFFC51C9A9C40007FF1A3 /* MPOImageCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = EF8BFFC41C9A9C40007FF1A3 /* MPOImageCollectionViewCell.m */; };
EF9BE0141C7083380017C1FB /* FaceListTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = EF9BE0131C7083380017C1FB /* FaceListTestCase.m */; };
EFD119A31C9A2DF200CC118F /* MPOUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = EFD119A21C9A2DF200CC118F /* MPOUtilities.m */; };
EFD119A61C9A596600CC118F /* MPOVerificationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EFD119A51C9A596600CC118F /* MPOVerificationViewController.m */; };
EFD5E59B1C79AA7300CD8FE8 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EFD5E59A1C79AA7300CD8FE8 /* MainStoryboard.storyboard */; };
EFD5E59E1C79AE2700CD8FE8 /* MPODetectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EFD5E59D1C79AE2700CD8FE8 /* MPODetectionViewController.m */; };
EFD5E5A31C79B3F600CD8FE8 /* MPODetectionCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = EFD5E5A21C79B3F600CD8FE8 /* MPODetectionCollectionViewCell.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -75,9 +95,7 @@
6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
6003F59B195388D20070C39A /* ProjectOxfordFace-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ProjectOxfordFace-Prefix.pch"; sourceTree = "<group>"; };
6003F59C195388D20070C39A /* MPOAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPOAppDelegate.h; sourceTree = "<group>"; };
6003F59D195388D20070C39A /* MPOAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPOAppDelegate.m; sourceTree = "<group>"; };
6003F5A5195388D20070C39A /* MPODemoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPODemoViewController.h; sourceTree = "<group>"; };
6003F5A6195388D20070C39A /* MPODemoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPODemoViewController.m; sourceTree = "<group>"; };
6003F59D195388D20070C39A /* MPOAppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MPOAppDelegate.mm; sourceTree = "<group>"; };
6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
6003F5AE195388D20070C39A /* ProjectOxfordFace_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProjectOxfordFace_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
@ -86,6 +104,66 @@
6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
6721C85774307A50E8CEE96C /* Pods-ProjectOxfordFace_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProjectOxfordFace_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ProjectOxfordFace_Tests/Pods-ProjectOxfordFace_Tests.release.xcconfig"; sourceTree = "<group>"; };
7B4071AB1D65EC1100362256 /* MPOAddPersonFaceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAddPersonFaceController.h; sourceTree = "<group>"; };
7B4071AC1D65EC1100362256 /* MPOAddPersonFaceController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAddPersonFaceController.m; sourceTree = "<group>"; };
7B4071AE1D69BEDB00362256 /* UIViewController+BackButtonHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+BackButtonHandler.h"; sourceTree = "<group>"; };
7B4071AF1D69BEDB00362256 /* UIViewController+BackButtonHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+BackButtonHandler.m"; sourceTree = "<group>"; };
7B4071B11D69BFF300362256 /* MPOMainNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOMainNavigationController.h; sourceTree = "<group>"; };
7B4071B21D69BFF300362256 /* MPOMainNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOMainNavigationController.m; sourceTree = "<group>"; };
7B643B6F1D5F44780012F342 /* Colours.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Colours.h; sourceTree = "<group>"; };
7B643B701D5F44780012F342 /* Colours.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Colours.m; sourceTree = "<group>"; };
7B643B711D5F44780012F342 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
7B643B761D5F44780012F342 /* ImageHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageHelper.h; sourceTree = "<group>"; };
7B643B771D5F44780012F342 /* ImageHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageHelper.m; sourceTree = "<group>"; };
7B643B791D5F44780012F342 /* MBProgressHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBProgressHUD.h; sourceTree = "<group>"; };
7B643B7A1D5F44780012F342 /* MBProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBProgressHUD.m; sourceTree = "<group>"; };
7B643B861D5F450F0012F342 /* MPOPersonFaceCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOPersonFaceCell.h; sourceTree = "<group>"; };
7B643B871D5F450F0012F342 /* MPOPersonFaceCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOPersonFaceCell.m; sourceTree = "<group>"; };
7B643B881D5F450F0012F342 /* MPOPersonFaceCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPOPersonFaceCell.xib; sourceTree = "<group>"; };
7B643B891D5F450F0012F342 /* MPOSimpleFaceCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOSimpleFaceCell.h; sourceTree = "<group>"; };
7B643B8A1D5F450F0012F342 /* MPOSimpleFaceCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOSimpleFaceCell.m; sourceTree = "<group>"; };
7B643B8B1D5F450F0012F342 /* MPOSimpleFaceCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPOSimpleFaceCell.xib; sourceTree = "<group>"; };
7B643B901D5F45190012F342 /* GroupPerson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupPerson.h; sourceTree = "<group>"; };
7B643B911D5F45190012F342 /* GroupPerson.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupPerson.m; sourceTree = "<group>"; };
7B643B921D5F45190012F342 /* PersonFace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PersonFace.h; sourceTree = "<group>"; };
7B643B931D5F45190012F342 /* PersonFace.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PersonFace.m; sourceTree = "<group>"; };
7B643B941D5F45190012F342 /* PersonGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PersonGroup.h; sourceTree = "<group>"; };
7B643B951D5F45190012F342 /* PersonGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PersonGroup.m; sourceTree = "<group>"; };
7B643B991D5F452B0012F342 /* MPOMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOMainViewController.h; sourceTree = "<group>"; };
7B643B9A1D5F452B0012F342 /* MPOMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOMainViewController.m; sourceTree = "<group>"; };
7B643B9B1D5F452B0012F342 /* MPODetectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPODetectionViewController.h; sourceTree = "<group>"; };
7B643B9C1D5F452B0012F342 /* MPODetectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPODetectionViewController.m; sourceTree = "<group>"; };
7B643B9D1D5F452B0012F342 /* MPOVerificationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOVerificationViewController.h; sourceTree = "<group>"; };
7B643B9E1D5F452B0012F342 /* MPOVerificationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOVerificationViewController.m; sourceTree = "<group>"; };
7B643B9F1D5F452B0012F342 /* MPOGroupingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOGroupingViewController.h; sourceTree = "<group>"; };
7B643BA01D5F452B0012F342 /* MPOGroupingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOGroupingViewController.m; sourceTree = "<group>"; };
7B643BA11D5F452B0012F342 /* MPOSimilarFaceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOSimilarFaceViewController.h; sourceTree = "<group>"; };
7B643BA21D5F452B0012F342 /* MPOSimilarFaceViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOSimilarFaceViewController.m; sourceTree = "<group>"; };
7B643BA31D5F452B0012F342 /* MPOIdentificationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOIdentificationViewController.h; sourceTree = "<group>"; };
7B643BA41D5F452B0012F342 /* MPOIdentificationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOIdentificationViewController.m; sourceTree = "<group>"; };
7B643BA51D5F452B0012F342 /* MPOPersonGroupListController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOPersonGroupListController.h; sourceTree = "<group>"; };
7B643BA61D5F452B0012F342 /* MPOPersonGroupListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOPersonGroupListController.m; sourceTree = "<group>"; };
7B643BA71D5F452B0012F342 /* MPOPersonGroupController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOPersonGroupController.h; sourceTree = "<group>"; };
7B643BA81D5F452B0012F342 /* MPOPersonGroupController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOPersonGroupController.m; sourceTree = "<group>"; };
7B643BA91D5F452B0012F342 /* MPOPersonFacesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOPersonFacesController.h; sourceTree = "<group>"; };
7B643BAA1D5F452B0012F342 /* MPOPersonFacesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOPersonFacesController.m; sourceTree = "<group>"; };
7B643BB51D5F467B0012F342 /* UIImage+Crop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Crop.h"; sourceTree = "<group>"; };
7B643BB61D5F467B0012F342 /* UIImage+Crop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Crop.m"; sourceTree = "<group>"; };
7B643BB71D5F467B0012F342 /* UIImage+FixOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+FixOrientation.h"; sourceTree = "<group>"; };
7B643BB81D5F467B0012F342 /* UIImage+FixOrientation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+FixOrientation.m"; sourceTree = "<group>"; };
7B643BB91D5F467B0012F342 /* UIImage+Resize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Resize.h"; sourceTree = "<group>"; };
7B643BBA1D5F467B0012F342 /* UIImage+Resize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Resize.m"; sourceTree = "<group>"; };
7B643BBB1D5F467B0012F342 /* UIViewController+DismissKeyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+DismissKeyboard.h"; sourceTree = "<group>"; };
7B643BBC1D5F467B0012F342 /* UIViewController+DismissKeyboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+DismissKeyboard.m"; sourceTree = "<group>"; };
7B643BBF1D5F467B0012F342 /* ViewUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewUtils.h; sourceTree = "<group>"; };
7B643BC01D5F467B0012F342 /* ViewUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewUtils.m; sourceTree = "<group>"; };
7B643BC11D5F467B0012F342 /* CommonUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonUtil.h; sourceTree = "<group>"; };
7B643BC21D5F467B0012F342 /* CommonUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommonUtil.m; sourceTree = "<group>"; };
7B643BCD1D5F47B60012F342 /* FaceSdkMobile.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FaceSdkMobile.framework; path = FaceSDK/FaceSdkMobile.framework; sourceTree = "<group>"; };
7B643BD31D6041E00012F342 /* MPODetectionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPODetectionCell.h; sourceTree = "<group>"; };
7B643BD41D6041E00012F342 /* MPODetectionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPODetectionCell.m; sourceTree = "<group>"; };
7B643BD91D60604A0012F342 /* MPOGroupSectionHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOGroupSectionHeaderView.h; sourceTree = "<group>"; };
7B643BDA1D60604A0012F342 /* MPOGroupSectionHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOGroupSectionHeaderView.m; sourceTree = "<group>"; };
87F83B3BC26C7A3EF3D14D52 /* Pods_ProjectOxfordFace_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProjectOxfordFace_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A51D13CAF7F407F1572D680E /* Pods-ProjectOxfordFace_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProjectOxfordFace_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-ProjectOxfordFace_Example/Pods-ProjectOxfordFace_Example.release.xcconfig"; sourceTree = "<group>"; };
AE558E5537FC3033395667D9 /* Pods_ProjectOxfordFace_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProjectOxfordFace_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -98,16 +176,6 @@
EF575B0C1C6872540021A3AD /* PersonGroupTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PersonGroupTestCase.m; sourceTree = "<group>"; };
EF575B0D1C6872540021A3AD /* SimilarTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimilarTestCase.m; sourceTree = "<group>"; };
EF575B0E1C6872540021A3AD /* VerifyTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VerifyTestCase.m; sourceTree = "<group>"; };
EF5E15671C9CA3C800BA4B22 /* MPOGroupingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOGroupingViewController.h; sourceTree = "<group>"; };
EF5E15681C9CA3C800BA4B22 /* MPOGroupingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOGroupingViewController.m; sourceTree = "<group>"; };
EF5E156A1C9CAF5B00BA4B22 /* MPOGroupingTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOGroupingTableViewCell.h; sourceTree = "<group>"; };
EF5E156B1C9CAF5B00BA4B22 /* MPOGroupingTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOGroupingTableViewCell.m; sourceTree = "<group>"; };
EF5E156D1C9CB89500BA4B22 /* MPOGroupingFaceCellObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOGroupingFaceCellObject.h; sourceTree = "<group>"; };
EF5E156E1C9CB89500BA4B22 /* MPOGroupingFaceCellObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOGroupingFaceCellObject.m; sourceTree = "<group>"; };
EF5E15761C9CC8D100BA4B22 /* MPODemoConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPODemoConstants.h; sourceTree = "<group>"; };
EF707D701CA1061B00C7AF5D /* MPOActivityIndicatorViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOActivityIndicatorViewController.h; sourceTree = "<group>"; };
EF707D711CA1061B00C7AF5D /* MPOActivityIndicatorViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOActivityIndicatorViewController.m; sourceTree = "<group>"; };
EF707D721CA1061B00C7AF5D /* MPOActivityIndicatorViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPOActivityIndicatorViewController.xib; sourceTree = "<group>"; };
EF7E8C991CA0C5A8005FFB2F /* MSC12_John_001.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = MSC12_John_001.jpg; path = SampleImages/MSC12_John_001.jpg; sourceTree = SOURCE_ROOT; };
EF7E8C9A1CA0C5A8005FFB2F /* MSC12_John_002.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = MSC12_John_002.jpg; path = SampleImages/MSC12_John_002.jpg; sourceTree = SOURCE_ROOT; };
EF7E8C9B1CA0C5A8005FFB2F /* MSC13_ChrisA_01.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = MSC13_ChrisA_01.jpg; path = SampleImages/MSC13_ChrisA_01.jpg; sourceTree = SOURCE_ROOT; };
@ -115,18 +183,8 @@
EF7E8C9D1CA0C5A8005FFB2F /* MSC13_ChrisA_04.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = MSC13_ChrisA_04.jpg; path = SampleImages/MSC13_ChrisA_04.jpg; sourceTree = SOURCE_ROOT; };
EF7E8C9E1CA0C5A8005FFB2F /* WIN12_Alberto_01.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = WIN12_Alberto_01.png; path = SampleImages/WIN12_Alberto_01.png; sourceTree = SOURCE_ROOT; };
EF7E8C9F1CA0C5A8005FFB2F /* WIN12_Alberto_03.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = WIN12_Alberto_03.png; path = SampleImages/WIN12_Alberto_03.png; sourceTree = SOURCE_ROOT; };
EF8BFFC31C9A9C40007FF1A3 /* MPOImageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOImageCollectionViewCell.h; sourceTree = "<group>"; };
EF8BFFC41C9A9C40007FF1A3 /* MPOImageCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOImageCollectionViewCell.m; sourceTree = "<group>"; };
EF9BE0131C7083380017C1FB /* FaceListTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FaceListTestCase.m; sourceTree = "<group>"; };
EFD119A11C9A2DF200CC118F /* MPOUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOUtilities.h; sourceTree = "<group>"; };
EFD119A21C9A2DF200CC118F /* MPOUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOUtilities.m; sourceTree = "<group>"; };
EFD119A41C9A596600CC118F /* MPOVerificationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOVerificationViewController.h; sourceTree = "<group>"; };
EFD119A51C9A596600CC118F /* MPOVerificationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOVerificationViewController.m; sourceTree = "<group>"; };
EFD5E59A1C79AA7300CD8FE8 /* MainStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = MainStoryboard.storyboard; path = ../MainStoryboard.storyboard; sourceTree = "<group>"; };
EFD5E59C1C79AE2700CD8FE8 /* MPODetectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPODetectionViewController.h; sourceTree = "<group>"; };
EFD5E59D1C79AE2700CD8FE8 /* MPODetectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPODetectionViewController.m; sourceTree = "<group>"; };
EFD5E5A11C79B3F600CD8FE8 /* MPODetectionCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPODetectionCollectionViewCell.h; sourceTree = "<group>"; };
EFD5E5A21C79B3F600CD8FE8 /* MPODetectionCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPODetectionCollectionViewCell.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -179,6 +237,7 @@
6003F58C195388D20070C39A /* Frameworks */ = {
isa = PBXGroup;
children = (
7B643BCD1D5F47B60012F342 /* FaceSdkMobile.framework */,
6003F58D195388D20070C39A /* Foundation.framework */,
6003F58F195388D20070C39A /* CoreGraphics.framework */,
6003F591195388D20070C39A /* UIKit.framework */,
@ -192,20 +251,13 @@
6003F593195388D20070C39A /* Example for ProjectOxfordFace */ = {
isa = PBXGroup;
children = (
EF5E15761C9CC8D100BA4B22 /* MPODemoConstants.h */,
EFD5E59A1C79AA7300CD8FE8 /* MainStoryboard.storyboard */,
EFD119A11C9A2DF200CC118F /* MPOUtilities.h */,
EFD119A21C9A2DF200CC118F /* MPOUtilities.m */,
EF8BFFC31C9A9C40007FF1A3 /* MPOImageCollectionViewCell.h */,
EF8BFFC41C9A9C40007FF1A3 /* MPOImageCollectionViewCell.m */,
EF33A6501C9C944F00C62A7E /* Detection */,
EF707D751CA10C9C00C7AF5D /* Helpers */,
EF33A6511C9C945500C62A7E /* Verification */,
EF5E15701C9CC4B800BA4B22 /* Grouping */,
7B643B851D5F44F60012F342 /* Model */,
7B643B841D5F44EF0012F342 /* View */,
7B643B831D5F44E60012F342 /* Controller */,
7B643B6D1D5F44780012F342 /* Utils */,
6003F59C195388D20070C39A /* MPOAppDelegate.h */,
6003F59D195388D20070C39A /* MPOAppDelegate.m */,
6003F5A5195388D20070C39A /* MPODemoViewController.h */,
6003F5A6195388D20070C39A /* MPODemoViewController.m */,
6003F59D195388D20070C39A /* MPOAppDelegate.mm */,
EFD5E59A1C79AA7300CD8FE8 /* MainStoryboard.storyboard */,
6003F5A8195388D20070C39A /* Images.xcassets */,
6003F594195388D20070C39A /* Supporting Files */,
);
@ -264,6 +316,118 @@
name = "Podspec Metadata";
sourceTree = "<group>";
};
7B643B6D1D5F44780012F342 /* Utils */ = {
isa = PBXGroup;
children = (
7B643BB51D5F467B0012F342 /* UIImage+Crop.h */,
7B643BB61D5F467B0012F342 /* UIImage+Crop.m */,
7B643BB71D5F467B0012F342 /* UIImage+FixOrientation.h */,
7B643BB81D5F467B0012F342 /* UIImage+FixOrientation.m */,
7B643BB91D5F467B0012F342 /* UIImage+Resize.h */,
7B643BBA1D5F467B0012F342 /* UIImage+Resize.m */,
7B643BBB1D5F467B0012F342 /* UIViewController+DismissKeyboard.h */,
7B643BBC1D5F467B0012F342 /* UIViewController+DismissKeyboard.m */,
7B643BBF1D5F467B0012F342 /* ViewUtils.h */,
7B643BC01D5F467B0012F342 /* ViewUtils.m */,
7B643BC11D5F467B0012F342 /* CommonUtil.h */,
7B643BC21D5F467B0012F342 /* CommonUtil.m */,
7B4071AE1D69BEDB00362256 /* UIViewController+BackButtonHandler.h */,
7B4071AF1D69BEDB00362256 /* UIViewController+BackButtonHandler.m */,
7B643B6E1D5F44780012F342 /* Colours */,
7B643B751D5F44780012F342 /* ImageHelper */,
7B643B781D5F44780012F342 /* MBProgressHUD */,
);
name = Utils;
path = utils;
sourceTree = SOURCE_ROOT;
};
7B643B6E1D5F44780012F342 /* Colours */ = {
isa = PBXGroup;
children = (
7B643B6F1D5F44780012F342 /* Colours.h */,
7B643B701D5F44780012F342 /* Colours.m */,
7B643B711D5F44780012F342 /* LICENSE */,
);
path = Colours;
sourceTree = "<group>";
};
7B643B751D5F44780012F342 /* ImageHelper */ = {
isa = PBXGroup;
children = (
7B643B761D5F44780012F342 /* ImageHelper.h */,
7B643B771D5F44780012F342 /* ImageHelper.m */,
);
path = ImageHelper;
sourceTree = "<group>";
};
7B643B781D5F44780012F342 /* MBProgressHUD */ = {
isa = PBXGroup;
children = (
7B643B791D5F44780012F342 /* MBProgressHUD.h */,
7B643B7A1D5F44780012F342 /* MBProgressHUD.m */,
);
path = MBProgressHUD;
sourceTree = "<group>";
};
7B643B831D5F44E60012F342 /* Controller */ = {
isa = PBXGroup;
children = (
7B643B991D5F452B0012F342 /* MPOMainViewController.h */,
7B643B9A1D5F452B0012F342 /* MPOMainViewController.m */,
7B643B9B1D5F452B0012F342 /* MPODetectionViewController.h */,
7B643B9C1D5F452B0012F342 /* MPODetectionViewController.m */,
7B643B9D1D5F452B0012F342 /* MPOVerificationViewController.h */,
7B643B9E1D5F452B0012F342 /* MPOVerificationViewController.m */,
7B643B9F1D5F452B0012F342 /* MPOGroupingViewController.h */,
7B643BA01D5F452B0012F342 /* MPOGroupingViewController.m */,
7B643BA11D5F452B0012F342 /* MPOSimilarFaceViewController.h */,
7B643BA21D5F452B0012F342 /* MPOSimilarFaceViewController.m */,
7B643BA31D5F452B0012F342 /* MPOIdentificationViewController.h */,
7B643BA41D5F452B0012F342 /* MPOIdentificationViewController.m */,
7B643BA51D5F452B0012F342 /* MPOPersonGroupListController.h */,
7B643BA61D5F452B0012F342 /* MPOPersonGroupListController.m */,
7B643BA71D5F452B0012F342 /* MPOPersonGroupController.h */,
7B643BA81D5F452B0012F342 /* MPOPersonGroupController.m */,
7B643BA91D5F452B0012F342 /* MPOPersonFacesController.h */,
7B643BAA1D5F452B0012F342 /* MPOPersonFacesController.m */,
7B4071AB1D65EC1100362256 /* MPOAddPersonFaceController.h */,
7B4071AC1D65EC1100362256 /* MPOAddPersonFaceController.m */,
7B4071B11D69BFF300362256 /* MPOMainNavigationController.h */,
7B4071B21D69BFF300362256 /* MPOMainNavigationController.m */,
);
name = Controller;
sourceTree = "<group>";
};
7B643B841D5F44EF0012F342 /* View */ = {
isa = PBXGroup;
children = (
7B643B861D5F450F0012F342 /* MPOPersonFaceCell.h */,
7B643B871D5F450F0012F342 /* MPOPersonFaceCell.m */,
7B643B881D5F450F0012F342 /* MPOPersonFaceCell.xib */,
7B643B891D5F450F0012F342 /* MPOSimpleFaceCell.h */,
7B643B8A1D5F450F0012F342 /* MPOSimpleFaceCell.m */,
7B643B8B1D5F450F0012F342 /* MPOSimpleFaceCell.xib */,
7B643BD31D6041E00012F342 /* MPODetectionCell.h */,
7B643BD41D6041E00012F342 /* MPODetectionCell.m */,
7B643BD91D60604A0012F342 /* MPOGroupSectionHeaderView.h */,
7B643BDA1D60604A0012F342 /* MPOGroupSectionHeaderView.m */,
);
name = View;
sourceTree = "<group>";
};
7B643B851D5F44F60012F342 /* Model */ = {
isa = PBXGroup;
children = (
7B643B901D5F45190012F342 /* GroupPerson.h */,
7B643B911D5F45190012F342 /* GroupPerson.m */,
7B643B921D5F45190012F342 /* PersonFace.h */,
7B643B931D5F45190012F342 /* PersonFace.m */,
7B643B941D5F45190012F342 /* PersonGroup.h */,
7B643B951D5F45190012F342 /* PersonGroup.m */,
);
name = Model;
sourceTree = "<group>";
};
88B336E0ABE7F88A7E93C1DB /* Pods */ = {
isa = PBXGroup;
children = (
@ -275,49 +439,6 @@
name = Pods;
sourceTree = "<group>";
};
EF33A6501C9C944F00C62A7E /* Detection */ = {
isa = PBXGroup;
children = (
EFD5E59C1C79AE2700CD8FE8 /* MPODetectionViewController.h */,
EFD5E59D1C79AE2700CD8FE8 /* MPODetectionViewController.m */,
);
name = Detection;
sourceTree = "<group>";
};
EF33A6511C9C945500C62A7E /* Verification */ = {
isa = PBXGroup;
children = (
EFD119A41C9A596600CC118F /* MPOVerificationViewController.h */,
EFD119A51C9A596600CC118F /* MPOVerificationViewController.m */,
);
name = Verification;
sourceTree = "<group>";
};
EF5E15701C9CC4B800BA4B22 /* Grouping */ = {
isa = PBXGroup;
children = (
EF5E15671C9CA3C800BA4B22 /* MPOGroupingViewController.h */,
EF5E15681C9CA3C800BA4B22 /* MPOGroupingViewController.m */,
EF5E156D1C9CB89500BA4B22 /* MPOGroupingFaceCellObject.h */,
EF5E156E1C9CB89500BA4B22 /* MPOGroupingFaceCellObject.m */,
EF5E156A1C9CAF5B00BA4B22 /* MPOGroupingTableViewCell.h */,
EF5E156B1C9CAF5B00BA4B22 /* MPOGroupingTableViewCell.m */,
);
name = Grouping;
sourceTree = "<group>";
};
EF707D751CA10C9C00C7AF5D /* Helpers */ = {
isa = PBXGroup;
children = (
EFD5E5A11C79B3F600CD8FE8 /* MPODetectionCollectionViewCell.h */,
EFD5E5A21C79B3F600CD8FE8 /* MPODetectionCollectionViewCell.m */,
EF707D701CA1061B00C7AF5D /* MPOActivityIndicatorViewController.h */,
EF707D711CA1061B00C7AF5D /* MPOActivityIndicatorViewController.m */,
EF707D721CA1061B00C7AF5D /* MPOActivityIndicatorViewController.xib */,
);
name = Helpers;
sourceTree = "<group>";
};
EFE53D071CA0D46700C37898 /* Images */ = {
isa = PBXGroup;
children = (
@ -383,10 +504,14 @@
isa = PBXProject;
attributes = {
CLASSPREFIX = MPO;
LastUpgradeCheck = 0720;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "David Porter";
TargetAttributes = {
6003F589195388D20070C39A = {
DevelopmentTeam = UBF8T346G9;
};
6003F5AD195388D20070C39A = {
DevelopmentTeam = 86C6K78PD9;
TestTargetID = 6003F589195388D20070C39A;
};
};
@ -416,11 +541,13 @@
buildActionMask = 2147483647;
files = (
EF7E8CA61CA0C5A8005FFB2F /* WIN12_Alberto_03.png in Resources */,
EF707D741CA1061B00C7AF5D /* MPOActivityIndicatorViewController.xib in Resources */,
7B643B8D1D5F450F0012F342 /* MPOPersonFaceCell.xib in Resources */,
EF7E8CA21CA0C5A8005FFB2F /* MSC13_ChrisA_01.jpg in Resources */,
EF7E8CA31CA0C5A8005FFB2F /* MSC13_ChrisA_02.jpg in Resources */,
6003F5A9195388D20070C39A /* Images.xcassets in Resources */,
EF7E8CA01CA0C5A8005FFB2F /* MSC12_John_001.jpg in Resources */,
7B643B7F1D5F44780012F342 /* LICENSE in Resources */,
7B643B8F1D5F450F0012F342 /* MPOSimpleFaceCell.xib in Resources */,
EFD5E59B1C79AA7300CD8FE8 /* MainStoryboard.storyboard in Resources */,
EF7E8CA41CA0C5A8005FFB2F /* MSC13_ChrisA_04.jpg in Resources */,
EF7E8CA51CA0C5A8005FFB2F /* WIN12_Alberto_01.png in Resources */,
@ -537,18 +664,36 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EF5E15691C9CA3C800BA4B22 /* MPOGroupingViewController.m in Sources */,
EF5E156C1C9CAF5B00BA4B22 /* MPOGroupingTableViewCell.m in Sources */,
6003F59E195388D20070C39A /* MPOAppDelegate.m in Sources */,
EFD5E59E1C79AE2700CD8FE8 /* MPODetectionViewController.m in Sources */,
EF707D731CA1061B00C7AF5D /* MPOActivityIndicatorViewController.m in Sources */,
EFD5E5A31C79B3F600CD8FE8 /* MPODetectionCollectionViewCell.m in Sources */,
6003F5A7195388D20070C39A /* MPODemoViewController.m in Sources */,
EF8BFFC51C9A9C40007FF1A3 /* MPOImageCollectionViewCell.m in Sources */,
7B643BDB1D60604A0012F342 /* MPOGroupSectionHeaderView.m in Sources */,
6003F59E195388D20070C39A /* MPOAppDelegate.mm in Sources */,
7B643B961D5F45190012F342 /* GroupPerson.m in Sources */,
7B643BB21D5F452B0012F342 /* MPOPersonGroupController.m in Sources */,
7B643B971D5F45190012F342 /* PersonFace.m in Sources */,
7B643BB01D5F452B0012F342 /* MPOIdentificationViewController.m in Sources */,
7B643BC71D5F467B0012F342 /* UIImage+Resize.m in Sources */,
7B643BAE1D5F452B0012F342 /* MPOGroupingViewController.m in Sources */,
7B4071AD1D65EC1100362256 /* MPOAddPersonFaceController.m in Sources */,
7B4071B01D69BEDB00362256 /* UIViewController+BackButtonHandler.m in Sources */,
7B643BCB1D5F467B0012F342 /* CommonUtil.m in Sources */,
7B643B7E1D5F44780012F342 /* Colours.m in Sources */,
7B643BC51D5F467B0012F342 /* UIImage+Crop.m in Sources */,
7B643BD51D6041E00012F342 /* MPODetectionCell.m in Sources */,
7B643BB31D5F452B0012F342 /* MPOPersonFacesController.m in Sources */,
7B4071B31D69BFF300362256 /* MPOMainNavigationController.m in Sources */,
7B643B8E1D5F450F0012F342 /* MPOSimpleFaceCell.m in Sources */,
7B643BCA1D5F467B0012F342 /* ViewUtils.m in Sources */,
7B643BAB1D5F452B0012F342 /* MPOMainViewController.m in Sources */,
7B643BC61D5F467B0012F342 /* UIImage+FixOrientation.m in Sources */,
7B643B811D5F44780012F342 /* ImageHelper.m in Sources */,
7B643B8C1D5F450F0012F342 /* MPOPersonFaceCell.m in Sources */,
7B643BAC1D5F452B0012F342 /* MPODetectionViewController.m in Sources */,
7B643BAF1D5F452B0012F342 /* MPOSimilarFaceViewController.m in Sources */,
6003F59A195388D20070C39A /* main.m in Sources */,
EFD119A61C9A596600CC118F /* MPOVerificationViewController.m in Sources */,
EFD119A31C9A2DF200CC118F /* MPOUtilities.m in Sources */,
EF5E156F1C9CB89500BA4B22 /* MPOGroupingFaceCellObject.m in Sources */,
7B643BC81D5F467B0012F342 /* UIViewController+DismissKeyboard.m in Sources */,
7B643BB11D5F452B0012F342 /* MPOPersonGroupListController.m in Sources */,
7B643B981D5F45190012F342 /* PersonGroup.m in Sources */,
7B643B821D5F44780012F342 /* MBProgressHUD.m in Sources */,
7B643BAD1D5F452B0012F342 /* MPOVerificationViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -611,14 +756,19 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@ -651,13 +801,18 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@ -679,10 +834,13 @@
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = UBF8T346G9;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ProjectOxfordFace/ProjectOxfordFace-Prefix.pch";
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/FaceSDK/FaceSdkMobile.framework/Headers";
INFOPLIST_FILE = "ProjectOxfordFace/ProjectOxfordFace-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -699,10 +857,13 @@
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = UBF8T346G9;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "ProjectOxfordFace/ProjectOxfordFace-Prefix.pch";
HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/FaceSDK/FaceSdkMobile.framework/Headers";
INFOPLIST_FILE = "ProjectOxfordFace/ProjectOxfordFace-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -716,6 +877,7 @@
baseConfigurationReference = 14D9649E7385DC1922B971FB /* Pods-ProjectOxfordFace_Tests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = 86C6K78PD9;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
@ -740,6 +902,7 @@
baseConfigurationReference = 6721C85774307A50E8CEE96C /* Pods-ProjectOxfordFace_Tests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEVELOPMENT_TEAM = 86C6K78PD9;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

Просмотреть файл

@ -28,8 +28,13 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
@interface MPOUtilities : NSObject
+ (UIImage *)cropImageToFaceRectangle:(UIImage *)image faceRectangle:(MPOFaceRectangle *)faceRectangle;
@interface GroupPerson : NSObject
@property (retain, nonatomic) NSString * personName;
@property (retain, nonatomic) NSString * personId;
@property (retain, nonatomic) NSMutableArray * faces;
@end

Просмотреть файл

@ -0,0 +1,43 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "GroupPerson.h"
@implementation GroupPerson
-(instancetype) init {
self = [super init];
_faces = [[NSMutableArray alloc] init];
_personName = @"";
return self;
}
@end

Просмотреть файл

@ -5,16 +5,31 @@
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
@ -44,10 +59,15 @@
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
}

Просмотреть файл

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MPOActivityIndicatorViewController">
<connections>
<outlet property="activityBackgroundView" destination="tsy-bg-Z9U" id="svx-GF-aP3"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tsy-bg-Z9U">
<rect key="frame" x="40" y="194" width="240" height="180"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Loading..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Q0Q-nC-3Td">
<rect key="frame" x="80" y="150" width="80" height="22"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="Q0Q-nC-3Td" firstAttribute="centerX" secondItem="tsy-bg-Z9U" secondAttribute="centerX" id="DET-QC-NL2"/>
<constraint firstAttribute="height" constant="180" id="RMQ-h3-2nl"/>
<constraint firstAttribute="bottom" secondItem="Q0Q-nC-3Td" secondAttribute="bottom" constant="8" id="dYY-kq-iOJ"/>
</constraints>
</view>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="2Pe-2G-scc">
<rect key="frame" x="142" y="265" width="37" height="37"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="2Pe-2G-scc" firstAttribute="centerX" secondItem="tsy-bg-Z9U" secondAttribute="centerX" id="3jS-ij-HTj"/>
<constraint firstItem="2Pe-2G-scc" firstAttribute="centerY" secondItem="tsy-bg-Z9U" secondAttribute="centerY" id="Hwo-zw-GqR"/>
<constraint firstItem="tsy-bg-Z9U" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" constant="40" id="KjE-f7-m5R"/>
<constraint firstAttribute="trailing" secondItem="tsy-bg-Z9U" secondAttribute="trailing" constant="40" id="WLi-NX-980"/>
<constraint firstItem="tsy-bg-Z9U" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" id="e91-9B-F0s"/>
<constraint firstItem="tsy-bg-Z9U" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="k3s-Uw-ytX"/>
</constraints>
<point key="canvasLocation" x="-129" y="47"/>
</view>
</objects>
</document>

Просмотреть файл

@ -0,0 +1,48 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "GroupPerson.h"
#import "PersonGroup.h"
@interface MPOAddPersonFaceController : UIViewController
@property (nonatomic, assign) BOOL * needTraining;
@property(nonatomic, retain) GroupPerson * person;
@property(nonatomic, retain) PersonGroup * group;
@property(nonatomic, retain) UIImage * image;
@property(nonatomic, retain) NSMutableArray * detectedFaces;
@end

Просмотреть файл

@ -0,0 +1,162 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOAddPersonFaceController.h"
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
#import "MBProgressHUD.h"
#import "MPOSimpleFaceCell.h"
#import "PersonFace.h"
#import "CommonUtil.h"
@interface MPOAddPersonFaceController () <UICollectionViewDelegate,UICollectionViewDataSource,UIAlertViewDelegate> {
UICollectionView *_facescollectionView;
NSInteger _selectedIndex;
}
@end
@implementation MPOAddPersonFaceController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"Add face";
[self buildMainUI];
_selectedIndex = -1;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)buildMainUI {
self.view.backgroundColor = [UIColor whiteColor];
UILabel * label = [[UILabel alloc] init];
label.text = @"Select faces to add to person:";
label.font = [UIFont systemFontOfSize:14];
label.left = 10;
label.top = 30;
[label sizeToFit];
[self.view addSubview:label];
UICollectionViewFlowLayout *flowLayout =[[UICollectionViewFlowLayout alloc]init];
_facescollectionView =[[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_facescollectionView.width = SCREEN_WIDTH - 20;
_facescollectionView.height = self.view.height - NAVIGATION_BAR_HEIGHT - STATUS_BAR_HEIGHT - label.bottom - 40;
_facescollectionView.left = 10;
_facescollectionView.top = label.bottom + 20;
_facescollectionView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_facescollectionView registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_facescollectionView.dataSource = self;
_facescollectionView.delegate = self;
[self.view addSubview:_facescollectionView];
[_facescollectionView reloadData];
}
- (void)addFace:(PersonFace*)face {
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Adding faces";
[HUD show: YES];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
NSData *data = UIImageJPEGRepresentation(self.image, 0.8);
[client addPersonFaceWithPersonGroupId:self.group.groupId personId:self.person.personId data:data userData:nil faceRectangle:face.face.faceRectangle completionBlock:^(MPOAddPersistedFaceResult *addPersistedFaceResult, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Failed in adding face" forController:self.navigationController];
return;
}
[CommonUtil showSimpleHUD:@"Face added to this person" forController:self.navigationController];
face.faceId = addPersistedFaceResult.persistedFaceId;
[self.detectedFaces removeObject:face];
[self.person.faces addObject:face];
[_facescollectionView reloadData];
*self.needTraining = YES;
}];
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (self.detectedFaces == nil) {
return 0;
}
return self.detectedFaces.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MPOSimpleFaceCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"faceCell" forIndexPath:indexPath];
[cell.imageView setImage:[(PersonFace*)self.detectedFaces[indexPath.row] image]];
cell.imageView.tag = indexPath.row;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(_facescollectionView.width / 3 - 10, _facescollectionView.width / 3 - 10);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Hint"
message:@"Do you want to add this face?"
delegate:self
cancelButtonTitle:@"No"
otherButtonTitles:@"Yes", nil];
[alertView show];
_selectedIndex = indexPath.row;
}
#pragma mark - UIAlertViewDelegate
- (void)alertViewCancel:(UIAlertView *)alertView {
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
[self addFace:self.detectedFaces[_selectedIndex]];
}
}
@end

Просмотреть файл

@ -29,10 +29,27 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@import UIKit;
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
static NSString *const ProjectOxfordFaceSubscriptionKey = @"Your Subscription Key";
@interface MPOAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (retain, nonatomic) NSData * mdl;
@property (retain, nonatomic) NSData * recomdl;
@property (assign, nonatomic) intptr_t jdaDetector;
@property (assign, nonatomic) intptr_t recognizer;
@property (retain, nonatomic) NSMutableArray * groups;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
@end

Просмотреть файл

@ -1,69 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOAppDelegate.h"
@implementation MPOAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end

Просмотреть файл

@ -0,0 +1,146 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOAppDelegate.h"
@implementation MPOAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_jdaDetector = 0;
_groups = [[NSMutableArray alloc] init];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
#pragma mark - Core Data stack
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "ms.FaceSdkSample" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"FaceSdkSample" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"FaceSdkSample.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
@end

Просмотреть файл

@ -1,35 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef MPODemoConstants_h
#define MPODemoConstants_h
static NSString *const ProjectOxfordFaceSubscriptionKey = @"INSERT YOUR SUBSCRIPTION KEY HERE";
#endif /* MPODemoConstants_h */

Просмотреть файл

@ -1,69 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPODemoViewController.h"
#import "MPODemoConstants.h"
@interface MPODemoViewController ()
@end
@implementation MPODemoViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if ([ProjectOxfordFaceSubscriptionKey isEqualToString:@"INSERT YOUR SUBSCRIPTION KEY HERE"]) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Project Oxford Subscription Key Not Entered"
message:@"Please obtain an subscription key from http://projectoxford.ai and enter it in the MPODemoConstants.h file"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil];
[alertController addAction:okAction];
[self presentViewController:alertController animated:YES completion:nil];
}
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end

Просмотреть файл

@ -0,0 +1,43 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface MPODetectionCell : UITableViewCell
@property (nonatomic, retain) NSString *ageText;
@property (nonatomic, retain) NSString *genderText;
@property (nonatomic, retain) NSString *headPoseText;
@property (nonatomic, retain) NSString *moustacheText;
@property (nonatomic, retain) NSString *smileText;
@property (nonatomic, retain) UIImage *faceImage;
@end

Просмотреть файл

@ -0,0 +1,132 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPODetectionCell.h"
@implementation MPODetectionCell {
UILabel * ageLabel;
UILabel * genderLabel;
UILabel * headPoseLabel;
UILabel * moustacheLabel;
UILabel * smileLabel;
UIImageView * faceImageView;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
ageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
ageLabel.textColor = [UIColor grayColor];
ageLabel.textAlignment = NSTextAlignmentLeft;
ageLabel.font = [UIFont systemFontOfSize:14];
genderLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
genderLabel.textColor = [UIColor grayColor];
genderLabel.textAlignment = NSTextAlignmentLeft;
genderLabel.font = [UIFont systemFontOfSize:14];
headPoseLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
headPoseLabel.textColor = [UIColor grayColor];
headPoseLabel.textAlignment = NSTextAlignmentLeft;
headPoseLabel.font = [UIFont systemFontOfSize:12];
moustacheLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
moustacheLabel.textColor = [UIColor grayColor];
moustacheLabel.textAlignment = NSTextAlignmentLeft;
moustacheLabel.font = [UIFont systemFontOfSize:14];
smileLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
smileLabel.textColor = [UIColor grayColor];
smileLabel.textAlignment = NSTextAlignmentLeft;
smileLabel.font = [UIFont systemFontOfSize:14];
faceImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 45, 45)];
faceImageView.center = self.center;
faceImageView.top = 10;
faceImageView.left = 10;
faceImageView.clipsToBounds = YES;
faceImageView.contentMode = UIViewContentModeScaleAspectFill;
[self.contentView addSubview:ageLabel];
[self.contentView addSubview:genderLabel];
[self.contentView addSubview:headPoseLabel];
[self.contentView addSubview:moustacheLabel];
[self.contentView addSubview:faceImageView];
[self.contentView addSubview:smileLabel];
self.backgroundColor = [UIColor clearColor];
}
return self;
}
-(void)layoutSubviews{
[super layoutSubviews];
if (_ageText) {
ageLabel.text = _ageText;
}
[ageLabel sizeToFit];
ageLabel.left = faceImageView.right + 20;
ageLabel.top = 10;
if (_genderText) {
genderLabel.text = _genderText;
}
[genderLabel sizeToFit];
genderLabel.left = faceImageView.right + 20;
genderLabel.top = ageLabel.bottom + 5;
if (_headPoseText) {
headPoseLabel.text = _headPoseText;
}
[headPoseLabel sizeToFit];
headPoseLabel.left = faceImageView.right + 20;
headPoseLabel.top = genderLabel.bottom + 5;
if (_moustacheText) {
moustacheLabel.text = _moustacheText;
}
[moustacheLabel sizeToFit];
moustacheLabel.left = faceImageView.right + 20;
moustacheLabel.top = headPoseLabel.bottom + 5;
if (_smileText) {
smileLabel.text = _smileText;
}
[smileLabel sizeToFit];
smileLabel.left = faceImageView.right + 20;
smileLabel.top = moustacheLabel.bottom + 5;
if (_faceImage) {
faceImageView.image = _faceImage;
}
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end

Просмотреть файл

@ -31,10 +31,6 @@
#import <UIKit/UIKit.h>
@interface MPODetectionViewController : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (weak, nonatomic) IBOutlet UILabel *numberOfFacesDetectedLabel;
- (IBAction)selectImageButtonPressed:(id)sender;
- (IBAction)detectionButtonPressed:(id)sender;
@interface MPODetectionViewController : UIViewController
@end

Просмотреть файл

@ -30,12 +30,16 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPODetectionViewController.h"
#import "MPODetectionCollectionViewCell.h"
#import "UIImage+FixOrientation.h"
#import "UIImage+Crop.h"
#import "ImageHelper.h"
#import "PersonFace.h"
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
#import "MPOUtilities.h"
#import "MPODemoConstants.h"
#import "MPOActivityIndicatorViewController.h"
@interface MPODetectionFaceCellObject : NSObject
#import "MBProgressHUD.h"
#import "CommonUtil.h"
#import "MPODetectionCell.h"
@interface MPODetectionFaceObject : NSObject
@property (nonatomic, strong) UIImage *croppedFaceImage;
@property (nonatomic, strong) NSString *ageText;
@property (nonatomic, strong) NSString *genderText;
@ -44,148 +48,246 @@
@property (nonatomic, strong) NSString *smileText;
@end
@implementation MPODetectionFaceCellObject
@implementation MPODetectionFaceObject
@end
@interface MPODetectionViewController ()
@property (nonatomic, strong) NSMutableArray *faceCellObjects;
@interface MPODetectionViewController () <UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UITableViewDelegate,UITableViewDataSource> {
UIImage * _selectedImage;
UIView * _imageContainer;
UIButton * _detectBtn;
UITableView * _resultTableView;
NSMutableArray * _detectionFaces;
}
@end
@implementation MPODetectionViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.collectionView.dataSource = self;
self.collectionView.delegate = self;
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"Detection";
_selectedImage = nil;
_detectionFaces = [[NSMutableArray alloc] init];
[self buildMainUI];
}
- (void)chooseImage: (id)sender {
UIActionSheet * choose_photo_sheet = [[UIActionSheet alloc]
initWithTitle:@"Select Image"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Select from album", @"Take a photo",nil];
[choose_photo_sheet showInView:self.view];
}
- (void)pickImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)snapImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)detectAction: (id)sender {
self.faceCellObjects = [[NSMutableArray alloc] init];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
// Do any additional setup after loading the view.
NSData *data = UIImageJPEGRepresentation(_selectedImage, 0.8);
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"deteting faces";
[HUD show: YES];
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[@(MPOFaceAttributeTypeAge), @(MPOFaceAttributeTypeFacialHair), @(MPOFaceAttributeTypeHeadPose), @(MPOFaceAttributeTypeSmile), @(MPOFaceAttributeTypeGender)] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"detection failed" forController:self.navigationController];
return;
}
[_detectionFaces removeAllObjects];
for (MPOFace *face in collection) {
UIImage *croppedImage = [_selectedImage crop:CGRectMake(face.faceRectangle.left.floatValue, face.faceRectangle.top.floatValue, face.faceRectangle.width.floatValue, face.faceRectangle.height.floatValue)];
MPODetectionFaceObject *obj = [[MPODetectionFaceObject alloc] init];
obj.croppedFaceImage = croppedImage;
obj.ageText = [NSString stringWithFormat:@"Age: %@", face.attributes.age.stringValue];
obj.genderText = [NSString stringWithFormat:@"Gender: %@", face.attributes.gender];
obj.headPoseText = [NSString stringWithFormat:@"Head Pose(in degrees): roll(%@), yaw(%@)", face.attributes.headPose.roll.stringValue, face.attributes.headPose.yaw.stringValue];
obj.moustacheText = [NSString stringWithFormat:@"Moustache: %@, Beard %@", face.attributes.facialHair.mustache.stringValue, face.attributes.facialHair.beard.stringValue];
obj.smileText = [NSString stringWithFormat:@"Smile: %@", face.attributes.smile];
[_detectionFaces addObject:obj];
}
[_resultTableView reloadData];
if (collection.count == 0) {
[CommonUtil showSimpleHUD:@"No face detected." forController:self.navigationController];
}
}];
}
- (void)buildMainUI {
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-STATUS_BAR_HEIGHT-NAVIGATION_BAR_HEIGHT)];
UILabel * label = [[UILabel alloc] init];
label.text = @"Image:";
label.left = 20;
label.top = 20;
[label sizeToFit];
[scrollView addSubview:label];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * selectImgBtn = [UIButton buttonWithType:UIButtonTypeCustom];
selectImgBtn.titleLabel.numberOfLines = 0;
[selectImgBtn setTitle:@"Select Image" forState:UIControlStateNormal];
selectImgBtn.width = SCREEN_WIDTH / 3 - 20;
selectImgBtn.height = selectImgBtn.width * 3 / 7;
selectImgBtn.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
selectImgBtn.titleLabel.font = [UIFont systemFontOfSize:14];
[selectImgBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[selectImgBtn addTarget:self action:@selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
_imageContainer = [[UIView alloc] init];
_imageContainer.width = SCREEN_WIDTH - selectImgBtn.width - 20 - 10 - 20;
_imageContainer.height = _imageContainer.width * 4 / 5;
_imageContainer.top = 20;
_imageContainer.right = SCREEN_WIDTH - 20;
_imageContainer.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
selectImgBtn.center = _imageContainer.center;
selectImgBtn.left = 20;
[scrollView addSubview:selectImgBtn];
[scrollView addSubview:_imageContainer];
label = [[UILabel alloc] init];
label.text = @"Result:";
[label sizeToFit];
label.left = 20;
label.top = _imageContainer.bottom + 10;
[scrollView addSubview:label];
_detectBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_detectBtn.height = selectImgBtn.height;
_detectBtn.width = SCREEN_WIDTH - 40;
[_detectBtn setTitle:@"Detect" forState:UIControlStateNormal];
[_detectBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
_detectBtn.left = 20;
_detectBtn.bottom = self.view.height - NAVIGATION_BAR_HEIGHT - STATUS_BAR_HEIGHT - 20;
[_detectBtn addTarget:self action:@selector(detectAction:) forControlEvents:UIControlEventTouchUpInside];
_detectBtn.enabled = NO;
[scrollView addSubview:_detectBtn];
_resultTableView = [[UITableView alloc] init];
_resultTableView.width = SCREEN_WIDTH - 20 - 20;
_resultTableView.top = label.bottom + 5;
_resultTableView.left = 20;
_resultTableView.height = _detectBtn.top - _resultTableView.top - 20;
_resultTableView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
_resultTableView.delegate = self;
_resultTableView.dataSource = self;
_resultTableView.tableFooterView = [[UIView alloc] init];
[_resultTableView registerClass:[MPODetectionCell class] forCellReuseIdentifier:@"detectionCell"];
[scrollView addSubview:_resultTableView];
scrollView.contentSize = CGSizeMake(SCREEN_WIDTH, _detectBtn.bottom + 20);
[self.view addSubview:scrollView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark - UIActionSheetDelegate
- (IBAction)selectImageButtonPressed:(id)sender {
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"Select a photo" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
[self dismissViewControllerAnimated:YES completion:nil];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Use Camera" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self dismissViewControllerAnimated:YES completion:nil];
[self presentViewController:picker animated:YES completion:nil];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Use Gallery" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self dismissViewControllerAnimated:YES completion:nil];
[self presentViewController:picker animated:YES completion:nil];
}]];
// Present action sheet.
[self presentViewController:actionSheet animated:YES completion:nil];
}
- (void)runDetection {
//remove any existing faces, if we have run detection previously
[self.faceCellObjects removeAllObjects];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
NSData *data = UIImageJPEGRepresentation(self.imageView.image, 0.8);
//show loading indicator
MPOActivityIndicatorViewController *indicatorViewController = [[MPOActivityIndicatorViewController alloc] init];
[self presentViewController:indicatorViewController animated:YES completion:nil];
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[@(MPOFaceAttributeTypeAge), @(MPOFaceAttributeTypeFacialHair), @(MPOFaceAttributeTypeHeadPose), @(MPOFaceAttributeTypeSmile), @(MPOFaceAttributeTypeGender)] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
}
else {
self.numberOfFacesDetectedLabel.text = [NSString stringWithFormat:@"%@ face detected", @(collection.count)];
for (MPOFace *face in collection) {
UIImage *croppedImage = [MPOUtilities cropImageToFaceRectangle:self.imageView.image faceRectangle:face.faceRectangle];
MPODetectionFaceCellObject *obj = [[MPODetectionFaceCellObject alloc] init];
obj.croppedFaceImage = croppedImage;
obj.ageText = [NSString stringWithFormat:@"Age: %@", face.attributes.age.stringValue];
obj.genderText = [NSString stringWithFormat:@"Gender: %@", face.attributes.gender];
obj.headPoseText = [NSString stringWithFormat:@"Head Pose(in degrees): roll(%@), yaw(%@)", face.attributes.headPose.roll.stringValue, face.attributes.headPose.yaw.stringValue];
obj.moustacheText = [NSString stringWithFormat:@"Moustache: %@, Beard %@", face.attributes.facialHair.mustache.stringValue, face.attributes.facialHair.beard.stringValue];
obj.smileText = [NSString stringWithFormat:@"Smile: %@", face.attributes.smile];
[self.faceCellObjects addObject:obj];
}
[self.collectionView reloadData];
}
//hide loading indicator
[self dismissViewControllerAnimated:YES completion:nil];
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
self.imageView.image = chosenImage;
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)detectionButtonPressed:(id)sender {
if (self.imageView.image) {
[self runDetection];
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self pickImage];
} else if (buttonIndex == 1) {
[self snapImage];
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [self.faceCellObjects count];
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
if (info[UIImagePickerControllerEditedImage])
_selectedImage = info[UIImagePickerControllerEditedImage];
else
_selectedImage = info[UIImagePickerControllerOriginalImage];
[_selectedImage fixOrientation];
if ([_imageContainer viewWithTag:5])
[[_imageContainer viewWithTag:5] removeFromSuperview];
UIImageView *imageView = [[UIImageView alloc] initWithImage:_selectedImage];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.frame = _imageContainer.frame;
imageView.top = 0;
imageView.left = 0;
imageView.tag = 5;
imageView.clipsToBounds = YES;
[_imageContainer addSubview:imageView];
[picker dismissViewControllerAnimated:YES completion:nil];
_detectBtn.enabled = YES;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPODetectionCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
MPODetectionFaceCellObject *obj = [self.faceCellObjects objectAtIndex:indexPath.row];
cell.ageLabel.text = obj.ageText;
cell.genderLabel.text = obj.genderText;
cell.headPoseLabel.text = obj.headPoseText;
cell.moustacheLabel.text = obj.moustacheText;
cell.smileLabel.text = obj.smileText;
cell.imageView.image = obj.croppedFaceImage;
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
NSDictionary *dict = [NSDictionary dictionaryWithObject:image forKey:@"UIImagePickerControllerOriginalImage"];
[self imagePickerController:picker didFinishPickingMediaWithInfo:dict];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (!error){
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:@"Image written to photo album" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}else{
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"Error writing to photo album: %@",[error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}
}
#pragma mark - UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _detectionFaces.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 120;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"detectionCell";
MPODetectionCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[MPODetectionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
MPODetectionFaceObject * obj = _detectionFaces[indexPath.row];
cell.ageText = obj.ageText;
cell.genderText = obj.genderText;
cell.headPoseText = obj.headPoseText;
cell.moustacheText = obj.moustacheText;
cell.smileText = obj.smileText;
cell.faceImage = obj.croppedFaceImage;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(self.collectionView.frame.size.width, 140);
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
@end

Просмотреть файл

@ -31,7 +31,8 @@
#import <UIKit/UIKit.h>
@interface MPOActivityIndicatorViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIView *activityBackgroundView;
@interface MPOGroupSectionHeaderView : UICollectionReusableView
@property (nonatomic, retain) NSString * title;
@end

Просмотреть файл

@ -0,0 +1,60 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOGroupSectionHeaderView.h"
@implementation MPOGroupSectionHeaderView {
UILabel * label;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:16];
label.top = 5;
label.left = 10;
label.text = @"";
[label sizeToFit];
[self addSubview:label];
}
return self;
}
- (void)setTitle:(NSString *)title {
_title = title;
label.text = title;
[label sizeToFit];
label.top = (self.height - label.height) / 2;
}
@end

Просмотреть файл

@ -31,11 +31,6 @@
#import <UIKit/UIKit.h>
@interface MPOGroupingViewController : UIViewController <UICollectionViewDataSource, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property (weak, nonatomic) IBOutlet UILabel *numberOfFacesDetectedLabel;
@property (weak, nonatomic) IBOutlet UICollectionView *facesCollectionView;
- (IBAction)addFacesButtonPressed:(id)sender;
- (IBAction)groupButtonPressed:(id)sender;
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@interface MPOGroupingViewController : UIViewController
@end

Просмотреть файл

@ -29,229 +29,367 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOGroupingViewController.h"
#import "MPOUtilities.h"
#import "UIImage+FixOrientation.h"
#import "UIImage+Crop.h"
#import "ImageHelper.h"
#import "MBProgressHUD.h"
#import "PersonFace.h"
#import "MPOSimpleFaceCell.h"
#import "MPOGroupSectionHeaderView.h"
#import "PersonFace.h"
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
#import "MPOImageCollectionViewCell.h"
#import "MPOGroupingTableViewCell.h"
#import "MPOGroupingFaceCellObject.h"
#import "MPODemoConstants.h"
#import "MPOActivityIndicatorViewController.h"
@interface MPOGroupingViewController ()
@property (nonatomic, strong) NSMutableArray *faceCellObjects;
@property (nonatomic, strong) UIImage *lastSelectedImage;
@property (nonatomic, strong) NSMutableArray *groupingResults;
@property (nonatomic, assign) BOOL messyGroupExists;
@interface MPOGroupingViewController () <UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UICollectionViewDelegate, UICollectionViewDataSource> {
NSMutableArray * _faces;
UICollectionView * _imageContainer;
UICollectionView * _resultContainer;
UIButton * _groupBtn;
UILabel * _imageCountLabel;
BOOL _messyGroupExists;
NSMutableArray<NSArray *> * _resultGroups;
}
@end
@implementation MPOGroupingViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.facesCollectionView.dataSource = self;
self.tableView.dataSource = self;
self.faceCellObjects = [[NSMutableArray alloc] init];
self.groupingResults = [[NSMutableArray alloc] init];
self.numberOfFacesDetectedLabel.text = @"0 faces detected";
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"Grouping";
[self buildMainUI];
_faces = [[NSMutableArray alloc] init];
_resultGroups = [[NSMutableArray alloc] init];
_messyGroupExists = FALSE;
}
- (IBAction)addFacesButtonPressed:(id)sender {
[self displaySelectionImageActionSheet];
- (void)chooseImage: (id)sender {
UIActionSheet * choose_photo_sheet = [[UIActionSheet alloc]
initWithTitle:@"Select Image"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Select from album", @"Take a photo",nil];
[choose_photo_sheet showInView:self.view];
}
- (IBAction)groupButtonPressed:(id)sender {
//show loading indicator
MPOActivityIndicatorViewController *indicatorViewController = [[MPOActivityIndicatorViewController alloc] init];
[self presentViewController:indicatorViewController animated:YES completion:nil];
- (void)pickImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)snapImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)groupFaces: (id)sender {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Grouping faces";
[HUD show: YES];
NSMutableArray *faceIds = [[NSMutableArray alloc] init];
for (MPOGroupingFaceCellObject *obj in self.faceCellObjects) {
for (PersonFace *obj in _faces) {
[faceIds addObject:obj.face.faceId];
}
NSMutableArray *allGroups = [[NSMutableArray alloc] init];
[_resultGroups removeAllObjects];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
[client groupWithFaceIds:faceIds completionBlock:^(MPOGroupResult *groupResult, NSError *error) {
//add all of the normal group members if they exist
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Grouping failed" forController:self.navigationController];
return;
}
for (NSArray *group in groupResult.groups) {
NSMutableArray *currentGroup = [[NSMutableArray alloc] init];
for (NSString *faceId in group) {
[currentGroup addObject:[self cellForFaceId:faceId]];
[currentGroup addObject:[self faceForId:faceId]];
}
[allGroups addObject:currentGroup];
[_resultGroups addObject:currentGroup.copy];
}
//add all of the messey group members if they exist
if (groupResult.messeyGroup.count != 0) {
NSMutableArray *allGroupsMessyGroup = [[NSMutableArray alloc] init];
for (NSString *faceId in groupResult.messeyGroup) {
[allGroupsMessyGroup addObject:[self cellForFaceId:faceId]];
[allGroupsMessyGroup addObject:[self faceForId:faceId]];
}
[allGroups addObject:allGroupsMessyGroup];
self.messyGroupExists = TRUE;
[_resultGroups addObject:allGroupsMessyGroup.copy];
_messyGroupExists = TRUE;
}
else {
self.messyGroupExists = FALSE;
_messyGroupExists = FALSE;
}
self.groupingResults = allGroups;
[self.tableView reloadData];
//hide loading indicator
[self dismissViewControllerAnimated:YES completion:nil];
[_resultContainer reloadData];
}];
}
- (MPOGroupingFaceCellObject *)cellForFaceId:(NSString *)faceId {
MPOGroupingFaceCellObject *target = nil;
for (MPOGroupingFaceCellObject *obj in self.faceCellObjects) {
if ([obj.face.faceId isEqualToString:faceId]) {
target = obj;
- (PersonFace*)faceForId:(NSString*)faceId {
for (PersonFace * face in _faces) {
if ([face.face.faceId isEqualToString:faceId]) {
return face;
}
}
return target;
return nil;
}
- (void)runDetection {
//show loading indicator
MPOActivityIndicatorViewController *indicatorViewController = [[MPOActivityIndicatorViewController alloc] init];
[self presentViewController:indicatorViewController animated:YES completion:nil];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
NSData *data = UIImageJPEGRepresentation(self.lastSelectedImage, 0.8);
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
if (error) {
NSLog(@"Error: %@", error);
}
else {
for (MPOFace *face in collection) {
UIImage *croppedImage = [MPOUtilities cropImageToFaceRectangle:self.lastSelectedImage faceRectangle:face.faceRectangle];
MPOGroupingFaceCellObject *obj = [[MPOGroupingFaceCellObject alloc] init];
obj.croppedFaceImage = croppedImage;
obj.face = face;
[self.faceCellObjects addObject:obj];
}
self.numberOfFacesDetectedLabel.text = [NSString stringWithFormat:@"%@ faces detected", @(self.faceCellObjects.count)];
[self.facesCollectionView reloadData];
//hide loading indicator
[self dismissViewControllerAnimated:YES completion:nil];
}
}];
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
- (void)buildMainUI {
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-STATUS_BAR_HEIGHT-NAVIGATION_BAR_HEIGHT)];
UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
self.lastSelectedImage = chosenImage;
UILabel * label = [[UILabel alloc] init];
label.text = @"Face database:";
label.left = 20;
label.top = 20;
[scrollView addSubview:label];
[label sizeToFit];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * selectImgBtn = [UIButton buttonWithType:UIButtonTypeCustom];
selectImgBtn.titleLabel.numberOfLines = 0;
[selectImgBtn setTitle:@"Add Faces" forState:UIControlStateNormal];
selectImgBtn.width = SCREEN_WIDTH / 3 - 20;
selectImgBtn.height = selectImgBtn.width * 3 / 7;
selectImgBtn.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
selectImgBtn.titleLabel.font = [UIFont systemFontOfSize:14];
[selectImgBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[selectImgBtn addTarget:self action:@selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
label.width = selectImgBtn.width;
label.adjustsFontSizeToFitWidth = YES;
_imageCountLabel = [[UILabel alloc] init];
_imageCountLabel.text = @"0 faces in total";
_imageCountLabel.left = 20;
_imageCountLabel.top = label.bottom + 2;
[scrollView addSubview:_imageCountLabel];
[_imageCountLabel sizeToFit];
_imageCountLabel.width = selectImgBtn.width;
_imageCountLabel.adjustsFontSizeToFitWidth = YES;
UICollectionViewFlowLayout *flowLayout =[[UICollectionViewFlowLayout alloc] init];
_imageContainer = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_imageContainer.width = SCREEN_WIDTH - selectImgBtn.width - 20 - 10 - 20;
_imageContainer.height = _imageContainer.width * 4 / 5;
_imageContainer.top = 20;
_imageContainer.right = SCREEN_WIDTH - 20;
_imageContainer.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_imageContainer registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_imageContainer.dataSource = self;
_imageContainer.delegate = self;
selectImgBtn.center = _imageContainer.center;
selectImgBtn.left = 20;
[scrollView addSubview:selectImgBtn];
[scrollView addSubview:_imageContainer];
label = [[UILabel alloc] init];
label.text = @"Result:";
[label sizeToFit];
label.left = 20;
label.top = _imageContainer.bottom + 10;
[scrollView addSubview:label];
flowLayout =[[UICollectionViewFlowLayout alloc] init];
[flowLayout setSectionInset:UIEdgeInsetsMake(5, 5, 5, 5)];
_resultContainer = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_resultContainer.width = SCREEN_WIDTH - 20 - 20;
_resultContainer.top = label.bottom + 5;
_resultContainer.left = 20;
_resultContainer.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_resultContainer registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
[_resultContainer registerClass:[MPOGroupSectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"faceSectionHeader"];
_resultContainer.dataSource = self;
_resultContainer.delegate = self;
[scrollView addSubview:_resultContainer];
_groupBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_groupBtn.height = selectImgBtn.height;
_groupBtn.width = SCREEN_WIDTH - 40;
[_groupBtn setTitle:@"Grouping" forState:UIControlStateNormal];
[_groupBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
_groupBtn.left = 20;
_groupBtn.bottom = self.view.height - NAVIGATION_BAR_HEIGHT - STATUS_BAR_HEIGHT - 20;
_groupBtn.enabled = NO;
[_groupBtn addTarget:self action:@selector(groupFaces:) forControlEvents:UIControlEventTouchUpInside];
_resultContainer.height = _groupBtn.top - _resultContainer.top - 20;
[scrollView addSubview:_groupBtn];
scrollView.contentSize = CGSizeMake(SCREEN_WIDTH, _groupBtn.bottom + 20);
[self.view addSubview:scrollView];
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self pickImage];
} else if (buttonIndex == 1) {
[self snapImage];
}
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage * _selectedImage;
if (info[UIImagePickerControllerEditedImage])
_selectedImage = info[UIImagePickerControllerEditedImage];
else
_selectedImage = info[UIImagePickerControllerOriginalImage];
[_selectedImage fixOrientation];
[picker dismissViewControllerAnimated:YES completion:nil];
if (chosenImage != nil) {
[self runDetection];
}
}
- (void)displaySelectionImageActionSheet {
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"Select a photo" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
[self dismissViewControllerAnimated:YES completion:nil];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Use Camera" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self dismissViewControllerAnimated:YES completion:nil];
[self presentViewController:picker animated:YES completion:nil];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Use Gallery" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self dismissViewControllerAnimated:YES completion:nil];
[self presentViewController:picker animated:YES completion:nil];
}]];
// Present action sheet.
[self presentViewController:actionSheet animated:YES completion:nil];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"detecting faces";
[HUD show: YES];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
NSData *data = UIImageJPEGRepresentation(_selectedImage, 0.8);
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"detection failed" forController:self.navigationController];
return;
}
for (MPOFace *face in collection) {
UIImage *croppedImage = [_selectedImage crop:CGRectMake(face.faceRectangle.left.floatValue, face.faceRectangle.top.floatValue, face.faceRectangle.width.floatValue, face.faceRectangle.height.floatValue)];
PersonFace *obj = [[PersonFace alloc] init];
obj.image = croppedImage;
obj.face = face;
[_faces addObject:obj];
}
[_imageContainer reloadData];
if (_faces.count > 0) {
_groupBtn.enabled = YES;
}
_imageCountLabel.text = [NSString stringWithFormat:@"%d faces in total", (int32_t)_faces.count];
if (collection.count == 0) {
[CommonUtil showSimpleHUD:@"No face detected." forController:self.navigationController];
}
}];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [self.faceCellObjects count];
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
NSDictionary *dict = [NSDictionary dictionaryWithObject:image forKey:@"UIImagePickerControllerOriginalImage"];
[self imagePickerController:picker didFinishPickingMediaWithInfo:dict];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (!error){
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:@"Image written to photo album" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}else{
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"Error writing to photo album: %@",[error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}
}
#pragma mark -CollectionView datasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
if (collectionView == _imageContainer) {
return 1;
} else {
return _resultGroups.count;
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (collectionView == _imageContainer) {
return _faces.count;
} else {
return _resultGroups[section].count;
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPOImageCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
MPOGroupingFaceCellObject *obj = [self.faceCellObjects objectAtIndex:indexPath.row];
cell.imageView.image = obj.croppedFaceImage;
MPOSimpleFaceCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"faceCell" forIndexPath:indexPath];
if (collectionView == _imageContainer) {
cell.imageView.image = ((PersonFace*)_faces[indexPath.row]).image;
} else {
cell.imageView.image = ((PersonFace*)_resultGroups[indexPath.section][indexPath.row]).image;
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(70, 70);
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return [self.groupingResults count];
}
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection: (NSInteger)section
{
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (self.messyGroupExists && section == self.groupingResults.count - 1) {
return @"Messy Group";
}
else {
return [NSString stringWithFormat:@"Group %@", @(section)];
if (collectionView == _imageContainer) {
return CGSizeMake(_imageContainer.width / 3 - 10, _imageContainer.width / 3 - 10);
} else {
return CGSizeMake(_resultContainer.width / 5 - 10, _resultContainer.width / 5 - 10);
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MPOGroupingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
NSArray *currentGroup = [self.groupingResults objectAtIndex:indexPath.section];
cell.group = currentGroup;
[cell.collectionView reloadData];
return cell;
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
if (collectionView == _imageContainer) {
return CGSizeMake(0, 0);
}
return CGSizeMake(_resultContainer.width, 30);
}
- (UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView * reusableview = nil;
if (collectionView == _imageContainer) {
return nil;
}
if (kind == UICollectionElementKindSectionHeader) {
MPOGroupSectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"faceSectionHeader" forIndexPath:indexPath];
if (indexPath.section == _resultGroups.count - 1 && _messyGroupExists) {
headerView.title = @"Messy Group:";
} else {
headerView.title = [NSString stringWithFormat:@"Group %ld:", indexPath.section + 1];
}
reusableview = headerView;
}
return reusableview;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

Просмотреть файл

@ -29,10 +29,8 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "MPOGroupingFaceCellObject.h"
@implementation MPOGroupingFaceCellObject
@interface MPOIdentificationViewController : UIViewController
@end

Просмотреть файл

@ -0,0 +1,444 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOIdentificationViewController.h"
#import "UIImage+FixOrientation.h"
#import "UIImage+Crop.h"
#import "ImageHelper.h"
#import "MPOPersonGroupListController.h"
#import "PersonGroup.h"
#import "GroupPerson.h"
#import "PersonFace.h"
#import "MPOSimpleFaceCell.h"
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
#import "MBProgressHUD.h"
#define MAX_RESULT_COUNT 20
@interface MPOIdentificationViewController () <UITableViewDelegate, UITableViewDataSource, UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UICollectionViewDelegate, UICollectionViewDataSource> {
UITableView * _groupListView;
UITableView * _resultListView;
UICollectionView * _imageContainer;
UIButton * _identifyBtn;
NSMutableArray * _faces;
NSMutableArray * _results;
}
@end
@implementation MPOIdentificationViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"Identification";
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init];
backItem.title = @"back";
self.navigationItem.backBarButtonItem = backItem;
[self buildMainUI];
_results = [[NSMutableArray alloc] init];
_faces = [[NSMutableArray alloc] init];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[_groupListView reloadData];
}
- (void)identify:(id)sender {
NSIndexPath * indexPath = _groupListView.indexPathForSelectedRow;
if (indexPath == nil) {
[CommonUtil simpleDialog:@"please select a group"];
return;
}
NSMutableArray *faceIds = [[NSMutableArray alloc] init];
for (PersonFace *obj in _faces) {
[faceIds addObject:obj.face.faceId];
}
PersonGroup * group = GLOBAL.groups[indexPath.row];
//NSArray * results = [FaceSdkUtil getFaceIndentificationResultsFromPeople:groupPeople andFace:_faces[_selectedTargetIndex]];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Identifying faces";
[HUD show: YES];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
[client identifyWithPersonGroupId:group.groupId faceIds:faceIds maxNumberOfCandidates:group.people.count completionBlock:^(NSArray<MPOIdentifyResult *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Failed in Indentification" forController:self.navigationController];
return;
}
[_results removeAllObjects];
for (MPOIdentifyResult * idRestult in collection) {
PersonFace * face = [self getFaceByFaceId:idRestult.faceId];
for (MPOCandidate * candidate in idRestult.candidates) {
GroupPerson * person = [self getPersonInGroup:group withPersonId:candidate.personId];
[_results addObject:@{@"face" : face, @"personName": person.personName, @"confidence" : candidate.confidence}];
}
}
if (collection.count == 0) {
[CommonUtil showSimpleHUD:@"No result." forController:self.navigationController];
}
[_resultListView reloadData];
}];
}
- (PersonFace*) getFaceByFaceId: (NSString*) faceId {
for (PersonFace * face in _faces) {
if ([face.face.faceId isEqualToString:faceId]) {
return face;
}
}
return nil;
}
- (GroupPerson*) getPersonInGroup:(PersonGroup*)group withPersonId: (NSString*) personId {
for (GroupPerson * person in group.people) {
if ([person.personId isEqualToString:personId]) {
return person;
}
}
return nil;
}
- (void)chooseImage: (id)sender {
UIActionSheet * choose_photo_sheet = [[UIActionSheet alloc]
initWithTitle:@"Select Image"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Select from album", @"Take a photo",nil];
[choose_photo_sheet showInView:self.view];
}
- (void)pickImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)snapImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)ManagePersonGroupAction:(id)sender {
MPOPersonGroupListController * controller = [[MPOPersonGroupListController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)buildMainUI {
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-STATUS_BAR_HEIGHT-NAVIGATION_BAR_HEIGHT)];
UILabel * label = [[UILabel alloc] init];
label.text = @"Target Image:";
label.left = 20;
label.top = 20;
[scrollView addSubview:label];
[label sizeToFit];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * addFacesBtn = [UIButton buttonWithType:UIButtonTypeCustom];
addFacesBtn.titleLabel.numberOfLines = 0;
[addFacesBtn setTitle:@"Select Image" forState:UIControlStateNormal];
addFacesBtn.width = SCREEN_WIDTH / 3 - 20;
addFacesBtn.height = addFacesBtn.width * 3 / 7;
addFacesBtn.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
addFacesBtn.titleLabel.font = [UIFont systemFontOfSize:14];
[addFacesBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[addFacesBtn addTarget:self action:@selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
label.width = addFacesBtn.width;
label.adjustsFontSizeToFitWidth = YES;
UICollectionViewFlowLayout *flowLayout =[[UICollectionViewFlowLayout alloc] init];
_imageContainer = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_imageContainer.width = SCREEN_WIDTH - addFacesBtn.width - 20 - 10 - 20;
_imageContainer.height = _imageContainer.width * 3 / 5;
_imageContainer.top = 20;
_imageContainer.right = SCREEN_WIDTH - 20;
_imageContainer.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_imageContainer registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_imageContainer.dataSource = self;
_imageContainer.delegate = self;
addFacesBtn.center = _imageContainer.center;
addFacesBtn.left = 20;
[scrollView addSubview:addFacesBtn];
[scrollView addSubview:_imageContainer];
label = [[UILabel alloc] init];
label.text = @"Person group to use:";
label.left = 20;
label.top = _imageContainer.bottom + 10;
[scrollView addSubview:label];
[label sizeToFit];
UIButton * manageBtn = [UIButton buttonWithType:UIButtonTypeCustom];
manageBtn.titleLabel.numberOfLines = 0;
[manageBtn setTitle:@"Manage Person Groups" forState:UIControlStateNormal];
manageBtn.width = SCREEN_WIDTH / 3 - 20;
manageBtn.height = manageBtn.width * 4 / 7;
manageBtn.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
manageBtn.titleLabel.font = [UIFont systemFontOfSize:14];
[manageBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[manageBtn addTarget:self action:@selector(ManagePersonGroupAction:) forControlEvents:UIControlEventTouchUpInside];
label.width = manageBtn.width;
label.adjustsFontSizeToFitWidth = YES;
_groupListView = [[UITableView alloc] init];
_groupListView.width = SCREEN_WIDTH - manageBtn.width - 20 - 10 - 20;
_groupListView.height = _groupListView.width * 1 / 2;
_groupListView.top = label.top;
_groupListView.right = SCREEN_WIDTH - 20;
_groupListView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
_groupListView.tableFooterView = [[UIView alloc] init];
_groupListView.dataSource = self;
_groupListView.delegate = self;
manageBtn.center = _groupListView.center;
manageBtn.left = 20;
manageBtn.top += 10;
[scrollView addSubview:manageBtn];
[scrollView addSubview:_groupListView];
label = [[UILabel alloc] init];
label.text = @"Result:";
[label sizeToFit];
label.left = 20;
label.top = _groupListView.bottom + 10;
[scrollView addSubview:label];
_resultListView = [[UITableView alloc] init];
_resultListView.width = SCREEN_WIDTH - 20 - 20;
_resultListView.height = _imageContainer.width * 5 / 7;
_resultListView.top = label.bottom + 5;
_resultListView.left = 20;
_resultListView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
_resultListView.tableFooterView = [[UIView alloc] init];
_resultListView.dataSource = self;
_resultListView.delegate = self;
_resultListView.allowsSelection = NO;
[scrollView addSubview:_resultListView];
_identifyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_identifyBtn.height = addFacesBtn.height;
_identifyBtn.width = SCREEN_WIDTH - 40;
[_identifyBtn setTitle:@"Identify" forState:UIControlStateNormal];
[_identifyBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
_identifyBtn.left = 20;
_identifyBtn.top = _resultListView.bottom + 30;
_identifyBtn.enabled = NO;
[_identifyBtn addTarget:self action:@selector(identify:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:_identifyBtn];
scrollView.contentSize = CGSizeMake(SCREEN_WIDTH, _identifyBtn.bottom + 20);
[self.view addSubview:scrollView];
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self pickImage];
} else if (buttonIndex == 1) {
[self snapImage];
}
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage * image;
if (info[UIImagePickerControllerEditedImage]) {
image = info[UIImagePickerControllerEditedImage];
} else {
image = info[UIImagePickerControllerOriginalImage];
}
[image fixOrientation];
[picker dismissViewControllerAnimated:YES completion:nil];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"detecting faces";
[HUD show: YES];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
NSData *data = UIImageJPEGRepresentation(image, 0.8);
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"detection failed" forController:self.navigationController];
return;
}
[_faces removeAllObjects];
for (MPOFace *face in collection) {
UIImage *croppedImage = [image crop:CGRectMake(face.faceRectangle.left.floatValue, face.faceRectangle.top.floatValue, face.faceRectangle.width.floatValue, face.faceRectangle.height.floatValue)];
PersonFace *obj = [[PersonFace alloc] init];
obj.image = croppedImage;
obj.face = face;
[_faces addObject:obj];
}
_identifyBtn.enabled = NO;
[_imageContainer reloadData];
if (collection.count == 0) {
[CommonUtil showSimpleHUD:@"No face detected." forController:self.navigationController];
}
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
NSDictionary *dict = [NSDictionary dictionaryWithObject:image forKey:@"UIImagePickerControllerOriginalImage"];
[self imagePickerController:picker didFinishPickingMediaWithInfo:dict];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (!error){
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:@"Image written to photo album" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}else{
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"Error writing to photo album: %@",[error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == _groupListView)
return GLOBAL.groups.count;
else
return _results.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == _groupListView)
return 35;
else
return 40;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * groupCellIdentifier = @"groupCell";
static NSString * resultCellIdentifier = @"resultCell";
if (tableView == _groupListView) {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:groupCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:groupCellIdentifier];
}
cell.textLabel.text = ((PersonGroup*)GLOBAL.groups[indexPath.row]).groupName;
cell.backgroundColor = [UIColor clearColor];
return cell;
} else {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:resultCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:groupCellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:@"%@ : %@", _results[indexPath.row][@"personName"], _results[indexPath.row][@"confidence"]];
cell.imageView.image = ((PersonFace*)_results[indexPath.row][@"face"]).image;
cell.backgroundColor = [UIColor clearColor];
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == _groupListView && _faces.count > 0) {
_identifyBtn.enabled = YES;
}
}
#pragma mark -CollectionView datasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _faces.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPOSimpleFaceCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"faceCell" forIndexPath:indexPath];
cell.imageView.image = ((PersonFace*)_faces[indexPath.row]).image;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(collectionView.width / 3 - 10, collectionView.width / 3 - 10);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

Просмотреть файл

@ -28,7 +28,9 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPODetectionCollectionViewCell.h"
@implementation MPODetectionCollectionViewCell
#import <UIKit/UIKit.h>
@interface MPOMainNavigationController : UINavigationController
@end

Просмотреть файл

@ -29,32 +29,18 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOMainNavigationController.h"
#import "UIViewController+BackButtonHandler.h"
#import "MPOActivityIndicatorViewController.h"
@interface MPOActivityIndicatorViewController ()
@interface MPOMainNavigationController ()
@end
@implementation MPOActivityIndicatorViewController
- (id)init
{
self = [super initWithNibName:@"MPOActivityIndicatorViewController" bundle:nil];
if (self) {
self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
}
return self;
}
@implementation MPOMainNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
self.activityBackgroundView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
[self.activityBackgroundView.layer setCornerRadius:15];
// Do any additional setup after loading the view from its nib.
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
@ -62,14 +48,34 @@
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem*)item {
if([self.viewControllers count] < [navigationBar.items count]) {
return YES;
}
BOOL shouldPop = YES;
UIViewController* vc = [self topViewController];
if([vc respondsToSelector:@selector(navigationShouldPopOnBackButton)]) {
shouldPop = [vc navigationShouldPopOnBackButton];
}
if(shouldPop) {
dispatch_async(dispatch_get_main_queue(), ^{
[self popViewControllerAnimated:YES];
});
} else {
// Workaround for iOS7.1. Thanks to @boliva - http://stackoverflow.com/posts/comments /34452906
for(UIView *subview in [navigationBar subviews]) {
if(subview.alpha < 1.) {
[UIView animateWithDuration:.25 animations:^{
subview.alpha = 1.;
}];
}
}
}
return NO;
}
*/
@end

Просмотреть файл

@ -29,8 +29,10 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@import UIKit;
#import <UIKit/UIKit.h>
@interface MPOMainViewController : UIViewController
@interface MPODemoViewController : UIViewController
@end

Просмотреть файл

@ -0,0 +1,196 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOMainViewController.h"
#import "MPODetectionViewController.h"
#import "MPOVerificationViewController.h"
#import "MPOGroupingViewController.h"
#import "MPOSimilarFaceViewController.h"
#import "MPOIdentificationViewController.h"
@interface MPOMainViewController () <UIActionSheetDelegate>
@end
@implementation MPOMainViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init];
backItem.title = @"back";
self.navigationItem.backBarButtonItem = backItem;
[self buildMainUI];
}
- (void)buildMainUI {
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-STATUS_BAR_HEIGHT-NAVIGATION_BAR_HEIGHT)];
UIButton * detectionBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIButton * verificationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIButton * groupingBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIButton * similarFaceBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIButton * identificationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UILabel * detectionLabel = [[UILabel alloc] init];
UILabel * verificationLabel = [[UILabel alloc] init];
UILabel * groupingLabel = [[UILabel alloc] init];
UILabel * similarLabel = [[UILabel alloc] init];
UILabel * identificationLabel = [[UILabel alloc] init];
UILabel * descriptionLabel = [[UILabel alloc] init];
NSString * detectionHint = @"Detect faces, face landmarks, pose, gender, and age.";
NSString * verificationHint = @"Check if two faces belong to the same person.";
NSString * groupingHint = @"Group faces based on similarity.";
NSString * SimilarFaceHint = @"Search for similar-looking faces.";
NSString * identificationHint = @"Identify the person from a face.";
NSString * descriptionHint = @"Microsoft will receive the images you upload and may use them to improve Face API and related services. By submitting an image, you confirm that you have consent from everyone in it.";
CGFloat btnWidth = SCREEN_WIDTH / 2 - 20;
CGFloat btnHeight = btnWidth / 3;
detectionBtn.width = verificationBtn.width = groupingBtn.width = similarFaceBtn.width = identificationBtn.width = btnWidth;
detectionBtn.height = verificationBtn.height = groupingBtn.height = similarFaceBtn.height = identificationBtn.height = btnHeight;
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
[detectionBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[verificationBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[groupingBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[similarFaceBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[identificationBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[detectionBtn setTitle:@"DETECTION" forState:UIControlStateNormal];
[verificationBtn setTitle:@"VERIFICATION" forState:UIControlStateNormal];
[groupingBtn setTitle:@"GROUPING" forState:UIControlStateNormal];
[similarFaceBtn setTitle:@"FIND SIMILAR FACES" forState:UIControlStateNormal];
similarFaceBtn.titleLabel.adjustsFontSizeToFitWidth = YES;
[identificationBtn setTitle:@"IDENTIFICATION" forState:UIControlStateNormal];
detectionBtn.right = verificationBtn.right = groupingBtn.right = similarFaceBtn.right = identificationBtn.right = scrollView.width - 20;
detectionLabel.top = detectionBtn.top = 20;
verificationLabel.top = verificationBtn.top = detectionBtn.bottom + 20;
groupingLabel.top = groupingBtn.top = verificationBtn.bottom + 20;
similarLabel.top = similarFaceBtn.top = groupingBtn.bottom + 20;
identificationLabel.top = identificationBtn.top = similarFaceBtn.bottom + 20;
[detectionLabel setText:detectionHint];
[verificationLabel setText:verificationHint];
[groupingLabel setText:groupingHint];
[similarLabel setText:SimilarFaceHint];
[identificationLabel setText:identificationHint];
[descriptionLabel setText:descriptionHint];
descriptionLabel.numberOfLines = detectionLabel.numberOfLines = verificationLabel.numberOfLines = groupingLabel.numberOfLines = similarLabel.numberOfLines = identificationLabel.numberOfLines = 0;
descriptionLabel.font = detectionLabel.font = verificationLabel.font = groupingLabel.font = similarLabel.font = identificationLabel.font = descriptionLabel.font = [UIFont systemFontOfSize:12];
detectionLabel.width = verificationLabel.width = groupingLabel.width = similarLabel.width = identificationLabel.width = btnWidth - 10;
detectionLabel.height = verificationLabel.height = groupingLabel.height = similarLabel.height = identificationLabel.height = btnHeight;
detectionLabel.left = verificationLabel.left = groupingLabel.left = similarLabel.left = identificationLabel.left = 20;
descriptionLabel.width = SCREEN_WIDTH - 20 * 2;
[descriptionLabel sizeToFit];
descriptionLabel.top = identificationBtn.bottom + 20;
descriptionLabel.left = 20;
[detectionBtn addTarget:self action:@selector(detectionAction:) forControlEvents:UIControlEventTouchUpInside];
[verificationBtn addTarget:self action:@selector(verificationAction:) forControlEvents:UIControlEventTouchUpInside];
[groupingBtn addTarget:self action:@selector(groupingAction:) forControlEvents:UIControlEventTouchUpInside];
[similarFaceBtn addTarget:self action:@selector(similarFaceAction:) forControlEvents:UIControlEventTouchUpInside];
[identificationBtn addTarget:self action:@selector(identificationAction:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:detectionBtn];
[scrollView addSubview:verificationBtn];
[scrollView addSubview:groupingBtn];
[scrollView addSubview:similarFaceBtn];
[scrollView addSubview:identificationBtn];
[scrollView addSubview:detectionLabel];
[scrollView addSubview:verificationLabel];
[scrollView addSubview:groupingLabel];
[scrollView addSubview:similarLabel];
[scrollView addSubview:identificationLabel];
[scrollView addSubview:descriptionLabel];
scrollView.contentSize = CGSizeMake(scrollView.width, identificationBtn.bottom + 20);
[self.view addSubview:scrollView];
if ([ProjectOxfordFaceSubscriptionKey isEqualToString:@"Your Subscription Key"]) {
detectionBtn.enabled = NO;
verificationBtn.enabled = NO;
groupingBtn.enabled = NO;
similarFaceBtn.enabled = NO;
identificationBtn.enabled = NO;
[CommonUtil simpleDialog:@"You haven't input the subscription key. Please specify the subscription key in MPOAppDelegate.h"];
}
}
- (void)detectionAction:(id)sender {
UIViewController * controller = [[MPODetectionViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
}
- (void)verificationAction:(id)sender {
UIActionSheet * verification_type_sheet = [[UIActionSheet alloc]
initWithTitle:@"Choose verification type"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"face and face", @"face and person",nil];
[verification_type_sheet showInView:self.view];
}
- (void)groupingAction:(id)sender {
UIViewController * controller = [[MPOGroupingViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
}
- (void)similarFaceAction:(id)sender {
UIViewController * controller = [[MPOSimilarFaceViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
}
- (void)identificationAction:(id)sender {
UIViewController * controller = [[MPOIdentificationViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
UIViewController * controller = [[MPOVerificationViewController alloc] initWithVerificationType:VerificationTypeFaceAndFace];
[self.navigationController pushViewController:controller animated:YES];
} else if (buttonIndex == 1) {
UIViewController * controller = [[MPOVerificationViewController alloc] initWithVerificationType:VerificationTypeFaceAndPerson];
[self.navigationController pushViewController:controller animated:YES];
}
}
@end

Просмотреть файл

@ -29,10 +29,10 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface MPOGroupingTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (strong, nonatomic) NSArray *group;
@interface MPOPersonFaceCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UIImageView *faceImageView;
@property (weak, nonatomic) IBOutlet UILabel *personName;
@end

Просмотреть файл

@ -0,0 +1,53 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOPersonFaceCell.h"
@implementation MPOPersonFaceCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"MPOPersonFaceCell" owner:self options:nil];
if (arrayOfViews.count < 1)
{
return nil;
}
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]])
{
return nil;
}
self = [arrayOfViews objectAtIndex:0];
}
return self;
}
@end

Просмотреть файл

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="faceCell" id="N8t-oZ-XGY" customClass="MPOPersonFaceCell">
<rect key="frame" x="0.0" y="0.0" width="144" height="168"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="144" height="168"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="SJW-Ns-koe">
<rect key="frame" x="10" y="10" width="124" height="124"/>
<constraints>
<constraint firstAttribute="width" secondItem="SJW-Ns-koe" secondAttribute="height" multiplier="1:1" id="P38-q0-ksJ"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gvx-zp-lYk">
<rect key="frame" x="56" y="139" width="33" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstItem="gvx-zp-lYk" firstAttribute="top" secondItem="SJW-Ns-koe" secondAttribute="bottom" constant="5" id="bJF-UU-Q9k"/>
<constraint firstItem="SJW-Ns-koe" firstAttribute="leading" secondItem="N8t-oZ-XGY" secondAttribute="leading" constant="10" id="hTw-L9-rBB"/>
<constraint firstItem="SJW-Ns-koe" firstAttribute="top" secondItem="N8t-oZ-XGY" secondAttribute="top" constant="10" id="i7L-Lr-Gsc"/>
<constraint firstItem="gvx-zp-lYk" firstAttribute="centerX" secondItem="SJW-Ns-koe" secondAttribute="centerX" id="vfm-Dn-vQH"/>
<constraint firstAttribute="trailing" secondItem="SJW-Ns-koe" secondAttribute="trailing" constant="10" id="yTT-om-ET4"/>
</constraints>
<size key="customSize" width="144" height="168"/>
<connections>
<outlet property="faceImageView" destination="SJW-Ns-koe" id="tMB-I3-hrM"/>
<outlet property="personName" destination="gvx-zp-lYk" id="Xca-BC-evy"/>
</connections>
<point key="canvasLocation" x="265" y="61"/>
</collectionViewCell>
</objects>
</document>

Просмотреть файл

@ -30,13 +30,19 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "GroupPerson.h"
#import "PersonGroup.h"
@interface MPODetectionCollectionViewCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UILabel *ageLabel;
@property (weak, nonatomic) IBOutlet UILabel *genderLabel;
@property (weak, nonatomic) IBOutlet UILabel *headPoseLabel;
@property (weak, nonatomic) IBOutlet UILabel *moustacheLabel;
@property (weak, nonatomic) IBOutlet UILabel *smileLabel;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@interface MPOPersonFacesController : UIViewController
@property(nonatomic, retain) GroupPerson * person;
@property(nonatomic, retain) PersonGroup * group;
@property (nonatomic, assign) BOOL * needTraining;
- (instancetype) initWithGroup:(PersonGroup*) group;
- (instancetype) initWithGroup:(PersonGroup *)group andPerson:(GroupPerson*)person;
@end

Просмотреть файл

@ -0,0 +1,440 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOPersonFacesController.h"
#import "UIViewController+DismissKeyboard.h"
#import "ImageHelper.h"
#import "UIImage+Crop.h"
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
#import "MBProgressHUD.h"
#import "MPOPersonFaceCell.h"
#import "PersonFace.h"
#import "MPOAddPersonFaceController.h"
#define INTENSION_SAVE_PERSON 0
#define INTENSION_ADD_FACE 1
@interface MPOPersonFacesController () <UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UICollectionViewDelegate,UICollectionViewDataSource,UIAlertViewDelegate> {
UITextField * _personNameField;
UICollectionView *_facescollectionView;
NSInteger _selectFaceIndex;
NSMutableArray * _detectedFaces;
int _intension;
}
@end
@implementation MPOPersonFacesController
- (void)viewDidLoad {
[super viewDidLoad];
_detectedFaces = [[NSMutableArray alloc] init];
[self buildMainUI];
self.navigationItem.title = @"Person";
_intension = INTENSION_SAVE_PERSON;
[self setupForDismissKeyboard];
}
- (instancetype) initWithGroup:(PersonGroup*) group {
self = [super init];
self.group = group;
return self;
}
- (instancetype) initWithGroup:(PersonGroup *)group andPerson:(GroupPerson*)person {
self = [super init];
self.group = group;
self.person = person;
return self;
}
- (void)chooseImage: (id)sender {
if (_personNameField.text.length == 0) {
[CommonUtil simpleDialog:@"please input the person's name."];
return;
}
if (!self.person) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Hint"
message:@"Do you want to create this new person?"
delegate:self
cancelButtonTitle:@"No"
otherButtonTitles:@"Yes", nil];
_intension = INTENSION_ADD_FACE;
[alertView show];
return;
}
UIActionSheet * choose_photo_sheet = [[UIActionSheet alloc]
initWithTitle:@"Select Image"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Select from album", @"Take a photo",nil];
choose_photo_sheet.tag = 0;
[choose_photo_sheet showInView:self.view];
}
- (void)longPressAction: (UIGestureRecognizer *) gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
_selectFaceIndex = gestureRecognizer.view.tag;
UIActionSheet * confirm_sheet = [[UIActionSheet alloc]
initWithTitle:@"Do you want to remove this face?"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Yes",nil];
confirm_sheet.tag = 1;
[confirm_sheet showInView:self.view];
}
}
- (void)save: (id)sender {
if (_personNameField.text.length == 0) {
[CommonUtil simpleDialog:@"please input the person's name"];
return;
}
if (!self.person) {
_intension = INTENSION_SAVE_PERSON;
[self createPerson];
} else {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Updating person";
[HUD show: YES];
[client updatePersonWithPersonGroupId:self.group.groupId personId:self.person.personId name:_personNameField.text userData:nil completionBlock:^(NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil simpleDialog:@"Failed in updating person."];
return;
}
self.person.personName = _personNameField.text;
[_facescollectionView reloadData];
}];
}
}
- (void)pickImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)snapImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)buildMainUI {
self.view.backgroundColor = [UIColor whiteColor];
UILabel * label = [[UILabel alloc] init];
label.text = @"Person name:";
label.font = [UIFont systemFontOfSize:14];
label.left = 10;
label.top = 30;
[label sizeToFit];
[self.view addSubview:label];
_personNameField = [[UITextField alloc] init];
_personNameField.width = SCREEN_WIDTH - label.right - 20;
_personNameField.height = label.height * 2;
_personNameField.center = label.center;
_personNameField.left = label.right + 10;
_personNameField.borderStyle = UITextBorderStyleLine;
if (self.person)
_personNameField.text = self.person.personName;
[self.view addSubview:_personNameField];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * addBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIButton * saveBtn = [UIButton buttonWithType:UIButtonTypeCustom];
addBtn.height = 50;
saveBtn.height = 50;
addBtn.width = SCREEN_WIDTH / 2 - 25;
saveBtn.width = addBtn.width;
addBtn.left = 20;
saveBtn.left = addBtn.right + 10;
addBtn.bottom = self.view.height - NAVIGATION_BAR_HEIGHT - STATUS_BAR_HEIGHT - 20;
saveBtn.bottom = self.view.height - NAVIGATION_BAR_HEIGHT - STATUS_BAR_HEIGHT - 20;
[addBtn setTitle:@"Add Face" forState:UIControlStateNormal];
[saveBtn setTitle:@"Save" forState:UIControlStateNormal];
[addBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[saveBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[addBtn addTarget:self action:@selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
[saveBtn addTarget:self action:@selector(save:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:saveBtn];
[self.view addSubview:addBtn];
label = [[UILabel alloc] init];
label.text = @"- Long press a face to delete.";
label.font = [UIFont systemFontOfSize:12];
[label sizeToFit];
label.bottom = addBtn.top - 10;
label.left = addBtn.left;
[self.view addSubview:label];
UICollectionViewFlowLayout *flowLayout =[[UICollectionViewFlowLayout alloc]init];
_facescollectionView =[[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_facescollectionView.width = SCREEN_WIDTH - 20;
_facescollectionView.height = label.top - _personNameField.bottom - 30;
_facescollectionView.left = 10;
_facescollectionView.top = _personNameField.bottom + 10;
_facescollectionView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_facescollectionView registerNib:[UINib nibWithNibName:@"MPOPersonFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_facescollectionView.dataSource = self;
_facescollectionView.delegate = self;
[self.view addSubview:_facescollectionView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[_facescollectionView reloadData];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if (![self.group.people containsObject:self.person] && self.person.faces.count > 0) {
[self.group.people addObject:self.person];
}
}
- (void)createPerson {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"creating person";
[HUD show: YES];
[client createPersonWithPersonGroupId:self.group.groupId name:_personNameField.text userData:nil completionBlock:^(MPOCreatePersonResult *createPersonResult, NSError *error) {
[HUD removeFromSuperview];
if (error || !createPersonResult.personId) {
[CommonUtil showSimpleHUD:@"Failed in creating person." forController:self.navigationController];
return;
}
self.person = [[GroupPerson alloc] init];
self.person.personName = _personNameField.text;
self.person.personId = createPersonResult.personId;
if (_intension == INTENSION_ADD_FACE) {
[self chooseImage:nil];
} else {
[CommonUtil showSuccessHUD:@"Person created" forController:self.navigationController];
}
}];
}
#pragma mark - UIAlertViewDelegate
- (void)alertViewCancel:(UIAlertView *)alertView {
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
[self createPerson];
}
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (actionSheet.tag == 0) {
if (buttonIndex == 0) {
[self pickImage];
} else if (buttonIndex == 1) {
[self snapImage];
}
} else if (actionSheet.tag == 1) {
if (buttonIndex == 0) {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Deleting this face";
[HUD show: YES];
[client deletePersonFaceWithPersonGroupId:self.group.groupId personId:self.person.personId persistedFaceId:((PersonFace*)self.person.faces[_selectFaceIndex]).faceId completionBlock:^(NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Failed in deleting this face" forController:self.navigationController];
return;
}
[self.person.faces removeObjectAtIndex:_selectFaceIndex];
[_facescollectionView reloadData];
}];
}
}
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage * selectedImage;
if (info[UIImagePickerControllerEditedImage]) {
selectedImage = info[UIImagePickerControllerEditedImage];
} else {
selectedImage = info[UIImagePickerControllerOriginalImage];
}
[picker dismissViewControllerAnimated:YES completion:^(void) {}];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"detecting faces";
[HUD show: YES];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
NSData *data = UIImageJPEGRepresentation(selectedImage, 0.8);
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Detection failed" forController:self.navigationController];
return;
}
[_detectedFaces removeAllObjects];
for (MPOFace *face in collection) {
UIImage *croppedImage = [selectedImage crop:CGRectMake(face.faceRectangle.left.floatValue, face.faceRectangle.top.floatValue, face.faceRectangle.width.floatValue, face.faceRectangle.height.floatValue)];
PersonFace *obj = [[PersonFace alloc] init];
obj.image = croppedImage;
obj.face = face;
[_detectedFaces addObject:obj];
}
if (_detectedFaces.count == 0) {
[CommonUtil showSimpleHUD:@"No face detected" forController:self.navigationController];
} else if (_detectedFaces.count == 1) {
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Adding faces";
[HUD show: YES];
[client addPersonFaceWithPersonGroupId:self.group.groupId personId:self.person.personId data:data userData:nil faceRectangle:collection[0].faceRectangle completionBlock:^(MPOAddPersistedFaceResult *addPersistedFaceResult, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Failed in adding face" forController:self.navigationController];
return;
}
((PersonFace*)_detectedFaces[0]).faceId = addPersistedFaceResult.persistedFaceId;
[self.person.faces addObject:_detectedFaces[0]];
[_facescollectionView reloadData];
*self.needTraining = YES;
}];
} else {
MPOAddPersonFaceController * controller = [[MPOAddPersonFaceController alloc] init];
controller.group = self.group;
controller.person = self.person;
controller.detectedFaces = _detectedFaces;
controller.image = selectedImage;
controller.needTraining = self.needTraining;
[self.navigationController pushViewController:controller animated:YES];
}
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
NSDictionary *dict = [NSDictionary dictionaryWithObject:image forKey:@"UIImagePickerControllerOriginalImage"];
[self imagePickerController:picker didFinishPickingMediaWithInfo:dict];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (!error){
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:@"Image written to photo album" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}else{
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"Error writing to photo album: %@",[error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (self.person == nil) {
return 0;
}
return self.person.faces.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPOPersonFaceCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"faceCell" forIndexPath:indexPath];
[cell.faceImageView setImage:[(PersonFace*)self.person.faces[indexPath.row] image]];
cell.faceImageView.tag = indexPath.row;
if (cell.faceImageView.gestureRecognizers.count == 0) {
[cell.faceImageView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)]];
}
[cell.personName setText: self.person.personName];
cell.faceImageView.userInteractionEnabled = YES;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(_facescollectionView.width / 3 - 10, (_facescollectionView.width / 3 - 10) * 4 / 3);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "PersonGroup.h"
@interface MPOPersonGroupController : UIViewController
@property (nonatomic, retain) PersonGroup * group;
@property (nonatomic, assign) BOOL * needTraining;
@property (nonatomic, assign) BOOL isForVarification;
- (instancetype) initWithGroup: (PersonGroup*) group;
@end

Просмотреть файл

@ -0,0 +1,403 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOPersonGroupController.h"
#import "UIViewController+DismissKeyboard.h"
#import "MPOPersonFacesController.h"
#import "PersonGroup.h"
#import "MPOPersonFaceCell.h"
#import "PersonFace.h"
#import "MBProgressHUD.h"
#import "CommonUtil.h"
#import "MPOVerificationViewController.h"
#define INTENSION_SAVE_GROUP 0
#define INTENSION_ADD_PERSON 1
@interface MPOPersonGroupController () <UICollectionViewDelegate, UICollectionViewDataSource, UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIAlertViewDelegate> {
UITextField * _groupNameField;
UICollectionView *_facesCollectionView;
NSInteger _selectedPersonIndex;
BOOL _shouldExit;
int _intension;
}
@end
@implementation MPOPersonGroupController
- (void)viewDidLoad {
[super viewDidLoad];
[self buildMainUI];
self.navigationItem.title = @"Person Group";
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init];
backItem.title = @"back";
self.needTraining = (BOOL*)malloc(sizeof(BOOL));
*self.needTraining = NO;
self.navigationItem.backBarButtonItem = backItem;
[self setupForDismissKeyboard];
}
- (instancetype) initWithGroup: (PersonGroup*) group {
self = [super init];
self.group = group;
return self;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[_facesCollectionView reloadData];
}
- (void)longPressAction: (UIGestureRecognizer *) gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
_selectedPersonIndex = gestureRecognizer.view.tag;
UIActionSheet * confirm_sheet = [[UIActionSheet alloc]
initWithTitle:@"Do you want to remove all of this person's faces?"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Yes",nil];
confirm_sheet.tag = 0;
[confirm_sheet showInView:self.view];
}
}
- (void)addPerson: (id)sender {
if (!self.group && _groupNameField.text.length == 0) {
[CommonUtil simpleDialog:@"please input the group name"];
return;
}
if (!self.group) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Hint"
message:@"Do you want to create this new group?"
delegate:self
cancelButtonTitle:@"No"
otherButtonTitles:@"Yes", nil];
_intension = INTENSION_ADD_PERSON;
alertView.tag = 0;
[alertView show];
return;
}
MPOPersonFacesController * controller = [[MPOPersonFacesController alloc] initWithGroup:self.group];
controller.needTraining = self.needTraining;
[self.navigationController pushViewController:controller animated:YES];
}
- (void)save: (id)sender {
if (_groupNameField.text.length == 0) {
[CommonUtil simpleDialog:@"please input the group name"];
return;
}
if (!self.group) {
[self createNewGroup];
} else {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"saving group";
[HUD show: YES];
[client updatePersonGroupWithPersonGroupId:self.group.groupId name:_groupNameField.text userData:nil completionBlock:^(NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil simpleDialog:@"Failed in updating group."];
return;
}
self.group.groupName = _groupNameField.text;
_shouldExit = NO;
[self trainGroup];
}];
}
}
- (void)buildMainUI {
self.view.backgroundColor = [UIColor whiteColor];
UILabel * label = [[UILabel alloc] init];
label.text = @"Person group name:";
label.font = [UIFont systemFontOfSize:14];
label.left = 10;
label.top = 30;
[label sizeToFit];
[self.view addSubview:label];
_groupNameField = [[UITextField alloc] init];
_groupNameField.width = SCREEN_WIDTH - label.right - 20;
_groupNameField.height = label.height * 2;
_groupNameField.center = label.center;
_groupNameField.left = label.right + 10;
_groupNameField.borderStyle = UITextBorderStyleLine;
if (self.group)
_groupNameField.text = self.group.groupName;
[self.view addSubview:_groupNameField];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * addBtn = [UIButton buttonWithType:UIButtonTypeCustom];
UIButton * saveBtn = [UIButton buttonWithType:UIButtonTypeCustom];
addBtn.height = 50;
saveBtn.height = 50;
addBtn.width = SCREEN_WIDTH / 2 - 25;
saveBtn.width = addBtn.width;
addBtn.left = 20;
saveBtn.left = addBtn.right + 10;
addBtn.bottom = self.view.height - NAVIGATION_BAR_HEIGHT - STATUS_BAR_HEIGHT - 20;
saveBtn.bottom = self.view.height - NAVIGATION_BAR_HEIGHT - STATUS_BAR_HEIGHT - 20;
[addBtn setTitle:@"Add Person" forState:UIControlStateNormal];
[saveBtn setTitle:@"Save" forState:UIControlStateNormal];
[addBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[saveBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
[addBtn addTarget:self action:@selector(addPerson:) forControlEvents:UIControlEventTouchUpInside];
[saveBtn addTarget:self action:@selector(save:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:saveBtn];
[self.view addSubview:addBtn];
label = [[UILabel alloc] init];
label.text = @"- Long press to delete.";
label.font = [UIFont systemFontOfSize:12];
[label sizeToFit];
label.bottom = addBtn.top - 10;
label.left = addBtn.left;
CGFloat temp = label.top;
[self.view addSubview:label];
label = [[UILabel alloc] init];
label.text = @"- Tap on a person to edit";
label.font = [UIFont systemFontOfSize:12];
[label sizeToFit];
label.left = addBtn.left;
label.bottom = temp - 2;
[self.view addSubview:label];
UICollectionViewFlowLayout *flowLayout =[[UICollectionViewFlowLayout alloc]init];
_facesCollectionView =[[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_facesCollectionView.width = SCREEN_WIDTH - 20;
_facesCollectionView.height = label.top - _groupNameField.bottom - 30;
_facesCollectionView.left = 10;
_facesCollectionView.top = _groupNameField.bottom + 10;
_facesCollectionView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_facesCollectionView registerNib:[UINib nibWithNibName:@"MPOPersonFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_facesCollectionView.dataSource = self;
_facesCollectionView.delegate = self;
[self.view addSubview:_facesCollectionView];
}
- (void)createNewGroup {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Creating group";
[HUD show: YES];
NSString * uuid = [[[NSUUID UUID] UUIDString] lowercaseString];
[client createPersonGroupWithId:uuid name:_groupNameField.text userData:nil completionBlock:^(NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil simpleDialog:@"Failed in creating group."];
NSLog(@"%@", error);
return;
}
self.group = [[PersonGroup alloc] init];
self.group.groupName = _groupNameField.text;
self.group.groupId = uuid;
[GLOBAL.groups addObject:self.group];
if (_intension == INTENSION_ADD_PERSON) {
MPOPersonFacesController * controller = [[MPOPersonFacesController alloc] initWithGroup:self.group];
controller.needTraining = self.needTraining;
[self.navigationController pushViewController:controller animated:YES];
} else {
[CommonUtil showSimpleHUD:@"Group created" forController:self.navigationController];
}
}];
}
- (void)trainGroup {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Training group";
[HUD show: YES];
[client trainPersonGroupWithPersonGroupId:self.group.groupId completionBlock:^(NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Failed in training group." forController:self.navigationController];
} else {
[CommonUtil showSimpleHUD:@"This group is trained." forController:self.navigationController];
}
if (_shouldExit) {
[self.navigationController popViewControllerAnimated:YES];
}
}];
}
- (BOOL)navigationShouldPopOnBackButton {
if (*self.needTraining) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Hint"
message:@"Do you want to train this group?"
delegate:self
cancelButtonTitle:@"No"
otherButtonTitles:@"Yes", nil];
alertView.tag = 1;
_shouldExit = YES;
[alertView show];
return NO;
}
return YES;
}
#pragma mark - UIAlertViewDelegate
- (void)alertViewCancel:(UIAlertView *)alertView {
if (alertView.tag == 1) {
[self.navigationController popViewControllerAnimated:YES];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.tag == 0) {
if (buttonIndex == 1) {
[self createNewGroup];
}
} else {
if (buttonIndex == 1) {
[self trainGroup];
}
}
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (actionSheet.tag == 0) {
if (buttonIndex == 0) {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Deleting this person";
[HUD show: YES];
[client deletePersonWithPersonGroupId:self.group.groupId personId:((GroupPerson*)self.group.people[_selectedPersonIndex]).personId completionBlock:^(NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Failed in deleting this person" forController:self.navigationController];
return;
}
[self.group.people removeObjectAtIndex:_selectedPersonIndex];
[_facesCollectionView reloadData];
}];
}
} else {
if (buttonIndex == 0) {
UIViewController * verificationController = nil;
for (UIViewController * controller in self.navigationController.viewControllers) {
if ([controller isKindOfClass:[MPOVerificationViewController class]]) {
verificationController = controller;
[(MPOVerificationViewController *)controller didSelectPerson: (GroupPerson*)self.group.people[_selectedPersonIndex] inGroup:self.group];
}
}
[self.navigationController popToViewController:verificationController animated:YES];
} else if (buttonIndex == 1) {
MPOPersonFacesController * controller = [[MPOPersonFacesController alloc] initWithGroup:self.group andPerson:self.group.people[_selectedPersonIndex]];
controller.needTraining = self.needTraining;
[self.navigationController pushViewController:controller animated:YES];
}
}
}
#pragma mark -CollectionView datasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return self.group ? self.group.people.count : 0;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [[(GroupPerson*)self.group.people[section] faces] count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPOPersonFaceCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"faceCell" forIndexPath:indexPath];
GroupPerson * person = self.group.people[indexPath.section];
[cell.faceImageView setImage: [(PersonFace*)person.faces[indexPath.row] image]];
cell.faceImageView.tag = indexPath.section;
[cell.personName setText:person.personName];
cell.faceImageView.userInteractionEnabled = YES;
if (cell.faceImageView.gestureRecognizers.count == 0) {
[cell.faceImageView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)]];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(_facesCollectionView.width / 3 - 10, (_facesCollectionView.width / 3 - 10) * 4 / 3);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
_selectedPersonIndex = indexPath.section;
if (self.isForVarification) {
UIActionSheet * use_person_sheet = [[UIActionSheet alloc]
initWithTitle:@"Hint"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Use this person for verification", @"Edit this person", nil];
use_person_sheet.tag = 1;
[use_person_sheet showInView:self.view];
return;
}
MPOPersonFacesController * controller = [[MPOPersonFacesController alloc] initWithGroup:self.group andPerson:self.group.people[indexPath.section]];
controller.needTraining = self.needTraining;
[self.navigationController pushViewController:controller animated:YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface MPOPersonGroupListController : UIViewController
@property (nonatomic, assign) BOOL isForVarification;
@end

Просмотреть файл

@ -0,0 +1,133 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOPersonGroupListController.h"
#import "MPOPersonGroupController.h"
@interface MPOPersonGroupListController () <UITableViewDelegate, UITableViewDataSource> {
UITableView * _groupListView;
}
@end
@implementation MPOPersonGroupListController
- (void)viewDidLoad {
[super viewDidLoad];
[self buildMainUI];
self.navigationItem.title = @"Person Group List";
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init];
backItem.title = @"back";
self.navigationItem.backBarButtonItem = backItem;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[_groupListView reloadData];
}
- (void)addGroupAction: (id)sender {
MPOPersonGroupController * controller = [[MPOPersonGroupController alloc] init];
controller.isForVarification = self.isForVarification;
[self.navigationController pushViewController:controller animated:YES];
}
- (void)buildMainUI {
self.view.backgroundColor = [UIColor whiteColor];
_groupListView = [[UITableView alloc] init];
_groupListView.width = SCREEN_WIDTH - 20 - 20;
_groupListView.height = (self.view.height - NAVIGATION_BAR_HEIGHT) * 3 / 4;
_groupListView.top = 20;
_groupListView.left = 20;
_groupListView.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[self.view addSubview:_groupListView];
_groupListView.delegate = self;
_groupListView.dataSource = self;
_groupListView.tableFooterView = [[UIView alloc] init];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * addBtn = [UIButton buttonWithType:UIButtonTypeCustom];
addBtn.height = (self.view.height - NAVIGATION_BAR_HEIGHT) *3 / 32;
addBtn.width = SCREEN_WIDTH - 40;
[addBtn setTitle:@"Add Group" forState:UIControlStateNormal];
[addBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
addBtn.left = 20;
addBtn.top = _groupListView.bottom + 20;
[addBtn addTarget:self action:@selector(addGroupAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:addBtn];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return GLOBAL.groups.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 40;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * showUserInfoCellIdentifier = @"ShowUserInfoCell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:showUserInfoCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:showUserInfoCellIdentifier];
}
cell.textLabel.text = ((PersonGroup*)GLOBAL.groups[indexPath.row]).groupName;
cell.backgroundColor = [UIColor clearColor];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MPOPersonGroupController * controller = [[MPOPersonGroupController alloc] initWithGroup:GLOBAL.groups[indexPath.row]];
controller.isForVarification = YES;
[self.navigationController pushViewController:controller animated:YES];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

Просмотреть файл

@ -29,8 +29,8 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOImageCollectionViewCell.h"
#import <UIKit/UIKit.h>
@implementation MPOImageCollectionViewCell
@interface MPOSimilarFaceViewController : UIViewController
@end

Просмотреть файл

@ -0,0 +1,406 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOSimilarFaceViewController.h"
#import "UIImage+FixOrientation.h"
#import "UIImage+Crop.h"
#import "ImageHelper.h"
#import "PersonFace.h"
#import "MPOSimpleFaceCell.h"
#import "MBProgressHUD.h"
#import "PersonFace.h"
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
@interface MPOSimilarFaceViewController () <UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UICollectionViewDelegate, UICollectionViewDataSource> {
NSMutableArray<PersonFace*> * _selectedFaces;
NSMutableArray<PersonFace*> * _baseFaces;
UICollectionView * _imageContainer0;
UICollectionView * _imageContainer1;
UIScrollView * _resultContainer;
UIButton * _findBtn;
UILabel * _imageCountLabel;
NSInteger _selectIndex;
NSInteger _selectedTargetIndex;
}
@end
@implementation MPOSimilarFaceViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"Find Similar Faces";
[self buildMainUI];
_baseFaces = [[NSMutableArray alloc] init];
_selectedFaces = [[NSMutableArray alloc] init];
_selectedTargetIndex = -1;
}
- (void)chooseImage: (id)sender {
_selectIndex = [(UIView*)sender tag];
UIActionSheet * choose_photo_sheet = [[UIActionSheet alloc]
initWithTitle:@"Select Image"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Select from album", @"Take a photo",nil];
[choose_photo_sheet showInView:self.view];
}
- (void)pickImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)snapImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)findSimilarFace: (id)sender {
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Finding similar faces";
[HUD show: YES];
NSMutableArray *faceIds = [[NSMutableArray alloc] init];
for (PersonFace *obj in _selectedFaces) {
[faceIds addObject:obj.face.faceId];
}
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
[client findSimilarWithFaceId:_baseFaces[_selectedTargetIndex].face.faceId faceIds:faceIds completionBlock:^(NSArray<MPOSimilarFace *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Failed to find similar faces" forController:self.navigationController];
return;
}
for (UIView * v in _resultContainer.subviews) {
[v removeFromSuperview];
}
for (int i = 0; i < collection.count; i++) {
MPOSimilarFace * result = collection[i];
UIImageView * imageView = [[UIImageView alloc] initWithImage:((PersonFace*)[self faceForId:result.faceId]).image];
imageView.width = _resultContainer.width / 6;
imageView.height = imageView.width;
imageView.left = 5;
imageView.top = 5 + (imageView.height + 5) * i;
imageView.clipsToBounds = YES;
imageView.contentMode = UIViewContentModeScaleAspectFit;
UILabel * label = [[UILabel alloc] init];
label.text = [NSString stringWithFormat:@"confidence: %f", result.confidence.floatValue];
[label sizeToFit];
label.center = imageView.center;
label.left = imageView.right + 30;
[_resultContainer addSubview:imageView];
[_resultContainer addSubview:label];
}
_resultContainer.contentSize = CGSizeMake(_resultContainer.width, 5 + collection.count * (5 + _resultContainer.width / 6));
if (collection.count == 0) {
[CommonUtil showSimpleHUD:@"No similar faces." forController:self.navigationController];
}
}];
}
- (PersonFace*)faceForId:(NSString*)faceId {
for (PersonFace * face in _selectedFaces) {
if ([face.face.faceId isEqualToString:faceId]) {
return face;
}
}
return nil;
}
- (void)buildMainUI {
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-STATUS_BAR_HEIGHT-NAVIGATION_BAR_HEIGHT)];
UILabel * label = [[UILabel alloc] init];
label.text = @"Face database:";
label.left = 20;
label.top = 20;
[scrollView addSubview:label];
[label sizeToFit];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * addFacesBtn = [UIButton buttonWithType:UIButtonTypeCustom];
addFacesBtn.titleLabel.numberOfLines = 0;
[addFacesBtn setTitle:@"Add Faces" forState:UIControlStateNormal];
addFacesBtn.width = SCREEN_WIDTH / 3 - 20;
addFacesBtn.height = addFacesBtn.width * 3 / 7;
addFacesBtn.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
addFacesBtn.titleLabel.font = [UIFont systemFontOfSize:14];
[addFacesBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
label.width = addFacesBtn.width;
label.adjustsFontSizeToFitWidth = YES;
_imageCountLabel = [[UILabel alloc] init];
_imageCountLabel.text = @"0 faces in total";
_imageCountLabel.left = 20;
_imageCountLabel.top = label.bottom;
[scrollView addSubview:_imageCountLabel];
[_imageCountLabel sizeToFit];
_imageCountLabel.width = addFacesBtn.width;
_imageCountLabel.adjustsFontSizeToFitWidth = YES;
UICollectionViewFlowLayout *flowLayout =[[UICollectionViewFlowLayout alloc] init];
_imageContainer0 = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_imageContainer0.width = SCREEN_WIDTH - addFacesBtn.width - 20 - 10 - 20;
_imageContainer0.height = _imageContainer0.width * 3 / 5;
_imageContainer0.top = 20;
_imageContainer0.right = SCREEN_WIDTH - 20;
_imageContainer0.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_imageContainer0 registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_imageContainer0.dataSource = self;
_imageContainer0.delegate = self;
addFacesBtn.center = _imageContainer0.center;
addFacesBtn.left = 20;
addFacesBtn.tag = 0;
[addFacesBtn addTarget:self action:@selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:addFacesBtn];
[scrollView addSubview:_imageContainer0];
label = [[UILabel alloc] init];
label.text = @"Target face:";
label.left = 20;
label.top = _imageContainer0.bottom + 10;
[scrollView addSubview:label];
[label sizeToFit];
UIButton * selectImgBtn = [UIButton buttonWithType:UIButtonTypeCustom];
selectImgBtn.titleLabel.numberOfLines = 0;
[selectImgBtn setTitle:@"Select Image" forState:UIControlStateNormal];
selectImgBtn.width = SCREEN_WIDTH / 3 - 20;
selectImgBtn.height = selectImgBtn.width * 3 / 7;
selectImgBtn.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
selectImgBtn.titleLabel.font = [UIFont systemFontOfSize:14];
[selectImgBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
selectImgBtn.tag = 1;
[selectImgBtn addTarget:self action:@selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
label.width = selectImgBtn.width;
label.adjustsFontSizeToFitWidth = YES;
flowLayout =[[UICollectionViewFlowLayout alloc] init];
_imageContainer1 = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_imageContainer1.width = SCREEN_WIDTH - selectImgBtn.width - 20 - 10 - 20;
_imageContainer1.height = _imageContainer1.width * 1 / 2;
_imageContainer1.top = label.top;
_imageContainer1.right = SCREEN_WIDTH - 20;
_imageContainer1.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_imageContainer1 registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_imageContainer1.dataSource = self;
_imageContainer1.delegate = self;
selectImgBtn.center = _imageContainer1.center;
selectImgBtn.left = 20;
[scrollView addSubview:selectImgBtn];
[scrollView addSubview:_imageContainer1];
label = [[UILabel alloc] init];
label.text = @"Result:";
[label sizeToFit];
label.left = 20;
label.top = _imageContainer1.bottom + 10;
[scrollView addSubview:label];
_resultContainer = [[UIScrollView alloc] init];
_resultContainer.width = SCREEN_WIDTH - 20 - 20;
_resultContainer.height = _imageContainer0.width * 5 / 7;
_resultContainer.top = label.bottom + 5;
_resultContainer.left = 20;
_resultContainer.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[scrollView addSubview:_resultContainer];
_findBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_findBtn.height = selectImgBtn.height;
_findBtn.width = SCREEN_WIDTH - 40;
[_findBtn setTitle:@"Find Similar Faces" forState:UIControlStateNormal];
[_findBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
_findBtn.left = 20;
_findBtn.top = _resultContainer.bottom + 30;
_findBtn.enabled = NO;
[_findBtn addTarget:self action:@selector(findSimilarFace:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:_findBtn];
scrollView.contentSize = CGSizeMake(SCREEN_WIDTH, _findBtn.bottom + 20);
[self.view addSubview:scrollView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
[self pickImage];
else if (buttonIndex == 1)
[self snapImage];
}
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage * _selectedImage;
if (info[UIImagePickerControllerEditedImage])
_selectedImage = info[UIImagePickerControllerEditedImage];
else
_selectedImage = info[UIImagePickerControllerOriginalImage];
[_selectedImage fixOrientation];
[picker dismissViewControllerAnimated:YES completion:nil];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"Detecting faces";
[HUD show: YES];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
NSData *data = UIImageJPEGRepresentation(_selectedImage, 0.8);
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"Detection failed" forController:self.navigationController];
return;
}
NSMutableArray * faces = [[NSMutableArray alloc] init];
for (MPOFace *face in collection) {
UIImage *croppedImage = [_selectedImage crop:CGRectMake(face.faceRectangle.left.floatValue, face.faceRectangle.top.floatValue, face.faceRectangle.width.floatValue, face.faceRectangle.height.floatValue)];
PersonFace *obj = [[PersonFace alloc] init];
obj.image = croppedImage;
obj.face = face;
[faces addObject:obj];
}
if (_selectIndex == 0) {
[_selectedFaces addObjectsFromArray:faces];
} else {
[_baseFaces removeAllObjects];
[_baseFaces addObjectsFromArray:faces];
_findBtn.enabled = NO;
_selectedTargetIndex = -1;
}
_imageCountLabel.text = [NSString stringWithFormat:@"%ld faces in total", _selectedFaces.count];
[_imageContainer0 reloadData];
[_imageContainer1 reloadData];
if (collection.count == 0) {
[CommonUtil showSimpleHUD:@"No face detected." forController:self.navigationController];
}
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
NSDictionary *dict = [NSDictionary dictionaryWithObject:image forKey:@"UIImagePickerControllerOriginalImage"];
[self imagePickerController:picker didFinishPickingMediaWithInfo:dict];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (!error){
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:@"Image written to photo album" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}else{
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"Error writing to photo album: %@",[error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}
}
#pragma mark -CollectionView datasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return collectionView == _imageContainer0 ? _selectedFaces.count : _baseFaces.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPOSimpleFaceCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"faceCell" forIndexPath:indexPath];
cell.layer.borderWidth = 0;
NSArray * faces = (collectionView == _imageContainer0) ? _selectedFaces : _baseFaces;
cell.imageView.image = ((PersonFace*)faces[indexPath.row]).image;
if (collectionView == _imageContainer1 && indexPath.row == _selectedTargetIndex) {
cell.layer.borderWidth = 2;
cell.layer.borderColor = [[UIColor redColor] CGColor];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(collectionView.width / 3 - 10, collectionView.width / 3 - 10);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
_selectedTargetIndex = indexPath.row;
[_imageContainer1 reloadData];
if (_selectedFaces.count > 0) {
_findBtn.enabled = YES;
}
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end

Просмотреть файл

@ -28,8 +28,10 @@
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface MPOImageCollectionViewCell : UICollectionViewCell
@interface MPOSimpleFaceCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end

Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOSimpleFaceCell.h"
@implementation MPOSimpleFaceCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"MPOSimpleFaceCell" owner:self options:nil];
if (arrayOfViews.count < 1)
{
return nil;
}
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]])
{
return nil;
}
self = [arrayOfViews objectAtIndex:0];
}
return self;
}
@end

Просмотреть файл

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="faceCell" id="gTV-IL-0wX" customClass="MPOSimpleFaceCell">
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
<subviews>
<imageView clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="vnB-Bo-Bjn">
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstAttribute="bottom" secondItem="vnB-Bo-Bjn" secondAttribute="bottom" id="aRE-CC-1jv"/>
<constraint firstItem="vnB-Bo-Bjn" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="bdD-YX-BAc"/>
<constraint firstItem="vnB-Bo-Bjn" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="iGS-T0-rtI"/>
<constraint firstAttribute="trailing" secondItem="vnB-Bo-Bjn" secondAttribute="trailing" id="ncg-3p-9gg"/>
</constraints>
<size key="customSize" width="100" height="100"/>
<connections>
<outlet property="imageView" destination="vnB-Bo-Bjn" id="icQ-6N-ZcV"/>
</connections>
<point key="canvasLocation" x="318" y="255"/>
</collectionViewCell>
</objects>
</document>

Просмотреть файл

@ -1,49 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOUtilities.h"
@implementation MPOUtilities
+ (UIImage *)cropImageToFaceRectangle:(UIImage *)image faceRectangle:(MPOFaceRectangle *)faceRectangle {
CGRect rect = CGRectMake(0, 0, 0, 0);
rect.size.width = [faceRectangle.width integerValue];
rect.size.height = [faceRectangle.height integerValue];
rect.origin.y = [faceRectangle.top integerValue];
rect.origin.x = [faceRectangle.left integerValue];
CGImageRef imageRef = CGImageCreateWithImageInRect ([image CGImage], rect);
UIImage *croppedImage = [UIImage imageWithCGImage: imageRef];
CGImageRelease (imageRef);
return croppedImage;
}
@end

Просмотреть файл

@ -30,14 +30,20 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
#import "GroupPerson.h"
#import "PersonGroup.h"
@interface MPOVerificationViewController : UIViewController <UIImagePickerControllerDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UINavigationControllerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *firstFaceImageView;
@property (weak, nonatomic) IBOutlet UIImageView *secondFaceImageView;
@property (weak, nonatomic) IBOutlet UICollectionView *firstFaceCollectionView;
@property (weak, nonatomic) IBOutlet UICollectionView *secondFaceCollectionView;
- (IBAction)firstFaceSelectImageButtonPressed:(id)sender;
- (IBAction)secondFaceSelectImageButtonPressed:(id)sender;
- (IBAction)verifyButtonPressed:(id)sender;
typedef enum {
VerificationTypeFaceAndFace = 0,
VerificationTypeFaceAndPerson = 1
} VerificationType;
@interface MPOVerificationViewController : UIViewController
@property(nonatomic, assign) VerificationType verificationType;
- (instancetype) initWithVerificationType: (VerificationType) type;
- (void) didSelectPerson: (GroupPerson*)person inGroup: (PersonGroup*)group;
@end

Просмотреть файл

@ -30,36 +30,253 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "MPOVerificationViewController.h"
#import "MPOPersonGroupListController.h"
#import "UIImage+FixOrientation.h"
#import "UIImage+Crop.h"
#import "ImageHelper.h"
#import "MPOSimpleFaceCell.h"
#import "MBProgressHUD.h"
#import "PersonFace.h"
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
#import "MPOUtilities.h"
#import "MPOImageCollectionViewCell.h"
#import "MPODemoConstants.h"
#import "MPOActivityIndicatorViewController.h"
@interface MPOVerificationFaceCellObject : NSObject
@property (nonatomic, strong) MPOFace *face;
@property (nonatomic, strong) UIImage *croppedFaceImage;
@end
@implementation MPOVerificationFaceCellObject
@end
@interface MPOVerificationViewController () <UIActionSheetDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate, UICollectionViewDelegate, UICollectionViewDataSource> {
UICollectionView * _imageContainer0;
UIView * _imageContainer1;
UIButton * _verifyBtn;
UILabel * _personNameLabel;
NSInteger _selectIndex;
NSMutableArray * _faces0;
NSMutableArray * _faces1;
NSInteger _selectedFaceIndex0;
NSInteger _selectedFaceIndex1;
PersonGroup * _selectedGroup;
GroupPerson * _selectedPerson;
}
@interface MPOVerificationViewController ()
@property (nonatomic, assign) NSInteger imageViewIndexSelected;
@property (nonatomic, strong) NSMutableArray *firstFaceCellObjects;
@property (nonatomic, strong) NSMutableArray *secondFaceCellObjects;
@property (nonatomic, assign) NSInteger indexOfFirstSelectedFace;
@property (nonatomic, assign) NSInteger indexOfSecondSelectedFace;
@end
@implementation MPOVerificationViewController
- (instancetype) initWithVerificationType: (VerificationType) type {
self = [super init];
if (self) {
self.verificationType = type;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"Verification";
self.firstFaceCellObjects = [[NSMutableArray alloc] init];
self.secondFaceCellObjects = [[NSMutableArray alloc] init];
_faces0 = [[NSMutableArray alloc] init];
_faces1 = [[NSMutableArray alloc] init];
_selectedFaceIndex0 = -1;
_selectedFaceIndex1 = -1;
_selectedGroup = nil;
_selectedPerson = nil;
[self buildMainUI];
}
- (void)buildMainUI {
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-STATUS_BAR_HEIGHT-NAVIGATION_BAR_HEIGHT)];
UILabel * label = [[UILabel alloc] init];
label.text = @"Face1:";
label.left = 20;
label.top = 20;
[label sizeToFit];
[scrollView addSubview:label];
UIImage * btnBackImage = [CommonUtil imageWithColor:[UIColor robinEggColor]];
UIButton * selectImgBtn0 = [UIButton buttonWithType:UIButtonTypeCustom];
selectImgBtn0.titleLabel.numberOfLines = 0;
[selectImgBtn0 setTitle:@"Select Image" forState:UIControlStateNormal];
selectImgBtn0.width = SCREEN_WIDTH / 3 - 20;
selectImgBtn0.height = selectImgBtn0.width * 3 / 7;
selectImgBtn0.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
selectImgBtn0.titleLabel.font = [UIFont systemFontOfSize:14];
selectImgBtn0.tag = 0;
[selectImgBtn0 addTarget:self action:@selector(chooseImage:) forControlEvents:UIControlEventTouchUpInside];
[selectImgBtn0 setBackgroundImage:btnBackImage forState:UIControlStateNormal];
UICollectionViewFlowLayout *flowLayout =[[UICollectionViewFlowLayout alloc] init];
_imageContainer0 = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_imageContainer0.width = SCREEN_WIDTH - selectImgBtn0.width - 20 - 10 - 20;
_imageContainer0.height = _imageContainer0.width * 4 / 5;
_imageContainer0.top = label.top;
_imageContainer0.right = SCREEN_WIDTH - 20;
_imageContainer0.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[_imageContainer0 registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
_imageContainer0.dataSource = self;
_imageContainer0.delegate = self;
selectImgBtn0.center = _imageContainer0.center;
selectImgBtn0.left = 20;
[scrollView addSubview:selectImgBtn0];
[scrollView addSubview:_imageContainer0];
label = [[UILabel alloc] init];
label.text = (_verificationType == VerificationTypeFaceAndFace) ? @"Face2:" : @"Person2:";
[label sizeToFit];
label.left = 20;
label.top = _imageContainer0.bottom + 10;
[scrollView addSubview:label];
UIButton * selectImgBtn1 = [UIButton buttonWithType:UIButtonTypeCustom];
selectImgBtn1.titleLabel.numberOfLines = 0;
[selectImgBtn1 setTitle: (_verificationType == VerificationTypeFaceAndFace) ? @"Select Image" : @"Select Person"
forState:UIControlStateNormal];
selectImgBtn1.width = SCREEN_WIDTH / 3 - 20;
selectImgBtn1.height = selectImgBtn1.width * 3 / 7;
selectImgBtn1.titleEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
selectImgBtn1.titleLabel.font = [UIFont systemFontOfSize:13];
selectImgBtn1.tag = 1;
[selectImgBtn1 addTarget:self action: (_verificationType == VerificationTypeFaceAndFace) ? @selector(chooseImage:) : @selector(choosePerson:)
forControlEvents:UIControlEventTouchUpInside];
[selectImgBtn1 setBackgroundImage:btnBackImage forState:UIControlStateNormal];
if (_verificationType == VerificationTypeFaceAndFace) {
flowLayout = [[UICollectionViewFlowLayout alloc]init];
_imageContainer1 = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
_imageContainer1.width = SCREEN_WIDTH - selectImgBtn1.width - 20 - 10 - 20;
_imageContainer1.height = _imageContainer1.width * 4 / 5;
_imageContainer1.top = label.top;
_imageContainer1.right = SCREEN_WIDTH - 20;
_imageContainer1.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
[(UICollectionView*)_imageContainer1 registerNib:[UINib nibWithNibName:@"MPOSimpleFaceCell" bundle:nil] forCellWithReuseIdentifier:@"faceCell"];
((UICollectionView*)_imageContainer1).dataSource = self;
((UICollectionView*)_imageContainer1).delegate = self;
selectImgBtn1.center = _imageContainer1.center;
selectImgBtn1.left = 20;
} else {
_imageContainer1 = [[UIView alloc] init];
_imageContainer1.width = SCREEN_WIDTH - selectImgBtn1.width - 20 - 10 - 20;
_imageContainer1.height = selectImgBtn1.height;
_imageContainer1.top = label.top;
_imageContainer1.right = SCREEN_WIDTH - 20;
_imageContainer1.backgroundColor = [UIColor colorWithWhite:0.95 alpha:1];
_personNameLabel = [[UILabel alloc] init];
_personNameLabel.font = [UIFont systemFontOfSize:14];
_personNameLabel.left = 10;
_personNameLabel.top = 10;
[_imageContainer1 addSubview:_personNameLabel];
selectImgBtn1.center = _imageContainer1.center;
selectImgBtn1.left = 20;
}
[scrollView addSubview:selectImgBtn1];
[scrollView addSubview:_imageContainer1];
_verifyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_verifyBtn.height = selectImgBtn0.height;
_verifyBtn.width = SCREEN_WIDTH - 40;
[_verifyBtn setTitle:@"Verify" forState:UIControlStateNormal];
[_verifyBtn setBackgroundImage:btnBackImage forState:UIControlStateNormal];
_verifyBtn.left = 20;
_verifyBtn.enabled = NO;
[_verifyBtn addTarget:self action:@selector(verify:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:_verifyBtn];
_verifyBtn.top = _imageContainer1.bottom + 30;
scrollView.contentSize = CGSizeMake(SCREEN_WIDTH, _verifyBtn.bottom + 20);
[self.view addSubview:scrollView];
}
- (void)didSelectPerson: (GroupPerson*)person inGroup: (PersonGroup*)group {
_selectedGroup = group;
_selectedPerson = person;
_personNameLabel.text = person.personName;
[_personNameLabel sizeToFit];
if (_selectedFaceIndex0 >= 0) {
_verifyBtn.enabled = YES;
}
}
- (void)choosePerson: (id)sender {
MPOPersonGroupListController * controller = [[MPOPersonGroupListController alloc] init];
controller.isForVarification = YES;
[self.navigationController pushViewController:controller animated:YES];
}
- (void)chooseImage: (id)sender {
_selectIndex = [(UIView*)sender tag];
UIActionSheet * choose_photo_sheet = [[UIActionSheet alloc]
initWithTitle:@"Select Image"
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Select from album", @"Take a photo",nil];
[choose_photo_sheet showInView:self.view];
}
- (void)pickImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)snapImage {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentViewController:ipc animated:YES completion:nil];
}
- (void)verify: (id)sender {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"verifying faces";
[HUD show: YES];
void (^completionBlock)(MPOVerifyResult *, NSError *) = ^(MPOVerifyResult *verifyResult, NSError *error){
[HUD removeFromSuperview];
if (error) {
[CommonUtil showSimpleHUD:@"verification failed" forController:self.navigationController];
return;
}
if (verifyResult.isIdentical) {
NSString * message = nil;
if (self.verificationType == VerificationTypeFaceAndFace) {
message = [NSString stringWithFormat:@"Two faces are from one person. The confidence is %@.", verifyResult.confidence];
} else {
message = [NSString stringWithFormat:@"This face is belong to this person. The confidence is %@.", verifyResult.confidence];
}
[CommonUtil simpleDialog:message];
} else {
NSString * message = nil;
if (self.verificationType == VerificationTypeFaceAndFace) {
message = @"Two faces are not from one person.";
} else {
message = @"This face is not belong to this person.";
}
[CommonUtil simpleDialog:message];
}
};
PersonFace *firstSelectedFaceObject = _faces0[_selectedFaceIndex0];
if (self.verificationType == VerificationTypeFaceAndFace) {
PersonFace *secondSelectedFaceObject = _faces1[_selectedFaceIndex1];
[client verifyWithFirstFaceId:firstSelectedFaceObject.face.faceId faceId2:secondSelectedFaceObject.face.faceId completionBlock:completionBlock];
} else {
[client verifyWithFaceId:firstSelectedFaceObject.face.faceId personId:_selectedPerson.personId personGroupId:_selectedGroup.groupId completionBlock:completionBlock];
}
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
@ -67,226 +284,138 @@
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
#pragma mark - UIActionSheetDelegate
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
- (IBAction)verifyButtonPressed:(id)sender {
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
if ([self.firstFaceCellObjects count] != 0 && [self.secondFaceCellObjects count] != 0 ) {
//show loading indicator
MPOActivityIndicatorViewController *indicatorViewController = [[MPOActivityIndicatorViewController alloc] init];
[self presentViewController:indicatorViewController animated:YES completion:nil];
MPOVerificationFaceCellObject *firstSelectedFaceCellObject = self.firstFaceCellObjects[self.indexOfFirstSelectedFace];
MPOVerificationFaceCellObject *secondSelectedFaceCellObject = self.secondFaceCellObjects[self.indexOfSecondSelectedFace];
[client verifyWithFirstFaceId:firstSelectedFaceCellObject.face.faceId faceId2:secondSelectedFaceCellObject.face.faceId completionBlock:^(MPOVerifyResult *verifyResult, NSError *error) {
//hide loading indicator
[self dismissViewControllerAnimated:YES completion:nil];
if (error) {
NSLog(@"Error: %@", error);
}
else {
NSString *message;
if (verifyResult.isIdentical) {
message = [NSString stringWithFormat:@"The person is the same. The confidence is %@", verifyResult.confidence];
}
else {
message = [NSString stringWithFormat:@"The person is not the same. The confidence is %@", verifyResult.confidence];
}
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Verification Result"
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil];
[alertController addAction:okAction];
[self presentViewController:alertController animated:YES completion:nil];
}
}];
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
[self pickImage];
} else if (buttonIndex == 1) {
[self snapImage];
}
}
- (IBAction)firstFaceSelectImageButtonPressed:(id)sender {
self.imageViewIndexSelected = 0;
[self displaySelectionImageActionSheet];
[self.firstFaceCellObjects removeAllObjects];
}
#pragma mark - UIImagePickerControllerDelegate
- (IBAction)secondFaceSelectImageButtonPressed:(id)sender {
self.imageViewIndexSelected = 1;
[self displaySelectionImageActionSheet];
[self.secondFaceCellObjects removeAllObjects];
}
- (void)displaySelectionImageActionSheet {
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage * _selectedImage;
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:@"Select a photo" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
[self dismissViewControllerAnimated:YES completion:nil];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Use Camera" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self dismissViewControllerAnimated:YES completion:nil];
[self presentViewController:picker animated:YES completion:nil];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:@"Use Gallery" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self dismissViewControllerAnimated:YES completion:nil];
[self presentViewController:picker animated:YES completion:nil];
}]];
// Present action sheet.
[self presentViewController:actionSheet animated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
if (self.imageViewIndexSelected == 0) {
self.firstFaceImageView.image = chosenImage;
}
else if (self.imageViewIndexSelected == 1) {
self.secondFaceImageView.image = chosenImage;
if (info[UIImagePickerControllerEditedImage]) {
_selectedImage = info[UIImagePickerControllerEditedImage];
} else {
_selectedImage = info[UIImagePickerControllerOriginalImage];
}
[_selectedImage fixOrientation];
[picker dismissViewControllerAnimated:YES completion:nil];
[self runDetection];
}
- (void)runDetection {
NSMutableArray * faceArray = (_selectIndex == 0) ? _faces0 : _faces1;
//show loading indicator
MPOActivityIndicatorViewController *indicatorViewController = [[MPOActivityIndicatorViewController alloc] init];
[self presentViewController:indicatorViewController animated:YES completion:nil];
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.labelText = @"deteting faces";
[HUD show: YES];
MPOFaceServiceClient *client = [[MPOFaceServiceClient alloc] initWithSubscriptionKey:ProjectOxfordFaceSubscriptionKey];
UIImage *currentImage;
if (self.imageViewIndexSelected == 0) {
currentImage = self.firstFaceImageView.image;
}
else if (self.imageViewIndexSelected == 1) {
currentImage = self.secondFaceImageView.image;
}
NSData *data = UIImageJPEGRepresentation(currentImage, 0.8);
NSData *data = UIImageJPEGRepresentation(_selectedImage, 0.8);
[client detectWithData:data returnFaceId:YES returnFaceLandmarks:YES returnFaceAttributes:@[] completionBlock:^(NSArray<MPOFace *> *collection, NSError *error) {
[HUD removeFromSuperview];
if (error) {
NSLog(@"Error: %@", error);
[CommonUtil showSimpleHUD:@"detection failed" forController:self.navigationController];
return;
}
else {
for (MPOFace *face in collection) {
UIImage *croppedImage = [MPOUtilities cropImageToFaceRectangle:currentImage faceRectangle:face.faceRectangle];
MPOVerificationFaceCellObject *obj = [[MPOVerificationFaceCellObject alloc] init];
obj.croppedFaceImage = croppedImage;
obj.face = face;
if (self.imageViewIndexSelected == 0) {
[self.firstFaceCellObjects addObject:obj];
}
else if (self.imageViewIndexSelected == 1) {
[self.secondFaceCellObjects addObject:obj];
}
}
if (self.imageViewIndexSelected == 0) {
[self.firstFaceCollectionView reloadData];
}
else if (self.imageViewIndexSelected == 1) {
[self.secondFaceCollectionView reloadData];
}
[faceArray removeAllObjects];
for (MPOFace *face in collection) {
UIImage *croppedImage = [_selectedImage crop:CGRectMake(face.faceRectangle.left.floatValue, face.faceRectangle.top.floatValue, face.faceRectangle.width.floatValue, face.faceRectangle.height.floatValue)];
PersonFace * personFace = [[PersonFace alloc] init];
personFace.image = croppedImage;
personFace.face = face;
[faceArray addObject:personFace];
}
[_imageContainer0 reloadData];
if (_verificationType == VerificationTypeFaceAndFace) {
[(UICollectionView*)_imageContainer1 reloadData];
}
_verifyBtn.enabled = NO;
_selectedFaceIndex0 = -1;
_selectedFaceIndex1 = -1;
//hide loading indicator
[self dismissViewControllerAnimated:YES completion:nil];
if (collection.count == 0) {
[CommonUtil showSimpleHUD:@"No face detected." forController:self.navigationController];
}
}];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (collectionView == self.firstFaceCollectionView) {
return [self.firstFaceCellObjects count];
}
else {
return [self.secondFaceCellObjects count];
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo{
NSDictionary *dict = [NSDictionary dictionaryWithObject:image forKey:@"UIImagePickerControllerOriginalImage"];
[self imagePickerController:picker didFinishPickingMediaWithInfo:dict];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (!error){
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:@"Image written to photo album" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}else{
UIAlertView *av=[[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:@"Error writing to photo album: %@",[error localizedDescription]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[av show];
}
}
#pragma mark -CollectionView datasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
if (collectionView == _imageContainer0) {
return _faces0.count;
} else {
return _faces1.count;
}
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPOImageCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
MPOVerificationFaceCellObject *obj;
NSInteger selectedIndex;
MPOSimpleFaceCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"faceCell" forIndexPath:indexPath];
cell.layer.borderWidth = 0;
if (collectionView == self.firstFaceCollectionView) {
obj = [self.firstFaceCellObjects objectAtIndex:indexPath.row];
selectedIndex = self.indexOfFirstSelectedFace;
if (collectionView == _imageContainer0) {
cell.imageView.image = ((PersonFace*)_faces0[indexPath.row]).image;
if (indexPath.row == _selectedFaceIndex0) {
cell.layer.borderColor = [[UIColor redColor] CGColor];
cell.layer.borderWidth = 2;
}
} else {
cell.imageView.image = ((PersonFace*)_faces1[indexPath.row]).image;
if (indexPath.row == _selectedFaceIndex1) {
cell.layer.borderColor = [[UIColor redColor] CGColor];
cell.layer.borderWidth = 2;
}
}
else {
obj = [self.secondFaceCellObjects objectAtIndex:indexPath.row];
selectedIndex = self.indexOfSecondSelectedFace;
}
if (indexPath.row == selectedIndex) {
cell.imageView.layer.borderWidth = 2;
cell.imageView.layer.borderColor = [UIColor redColor].CGColor;
}
else {
cell.imageView.layer.borderWidth = 0;
}
cell.imageView.image = obj.croppedFaceImage;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(self.firstFaceCollectionView.frame.size.width, 80);
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(_imageContainer0.width / 3 - 10, _imageContainer0.width / 3 - 10);
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (collectionView == self.firstFaceCollectionView) {
self.indexOfFirstSelectedFace = indexPath.row;
[self.firstFaceCollectionView reloadData];
}
else {
self.indexOfSecondSelectedFace = indexPath.row;
[self.secondFaceCollectionView reloadData];
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 10;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
collectionView == _imageContainer0 ? (_selectedFaceIndex0 = indexPath.row) : (_selectedFaceIndex1 = indexPath.row);
if (_selectedFaceIndex0 >= 0 && (_selectedFaceIndex1 >= 0 || _selectedPerson)) {
_verifyBtn.enabled = YES;
}
[collectionView reloadData];
}
@end

Просмотреть файл

@ -29,11 +29,13 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <ProjectOxfordFace/MPOFaceServiceClient.h>
@interface MPOGroupingFaceCellObject : NSObject
@property (nonatomic, strong) UIImage *croppedFaceImage;
@interface PersonFace : NSObject
@property (retain, nonatomic) NSString * faceId;
@property (nonatomic, strong) MPOFace *face;
@property (retain, nonatomic) UIImage * image;
@end

Просмотреть файл

@ -0,0 +1,43 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "PersonFace.h"
@implementation PersonFace
- (instancetype) initWithImage:(UIImage*)image andFace:(MPOFace*)face {
self = [super init];
self.image = image;
self.face = face;
return self;
}
@end

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
@interface PersonGroup : NSObject
@property (retain, nonatomic) NSString * groupName;
@property (retain, nonatomic) NSMutableArray * people;
@property (retain, nonatomic) NSString * groupId;
- (instancetype) initWithGroupName: (id)name;
@end

Просмотреть файл

@ -0,0 +1,49 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "PersonGroup.h"
@implementation PersonGroup
- (instancetype) init {
self = [super init];
_people = [[NSMutableArray alloc] init];
_groupName = @"";
return self;
}
- (instancetype) initWithGroupName: (id)name {
self = [self init];
self.groupName = name;
return self;
}
@end

Просмотреть файл

@ -35,8 +35,6 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>

Просмотреть файл

@ -11,6 +11,21 @@
#endif
#ifdef __OBJC__
@import UIKit;
@import Foundation;
//@import UIKit;
//@import Foundation;
#endif
#import "ViewUtils.h"
#import "CommonUtil.h"
#import "Colours.h"
#import "MPOAppDelegate.h"
#define GLOBAL ((MPOAppDelegate*)[UIApplication sharedApplication].delegate)
#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define IOS7_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)
#define STATUS_BAR_HEIGHT [[UIApplication sharedApplication] statusBarFrame].size.height
#define RGBACOLOR(r,g,b,a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)]
#define IS_IPHONE_5 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
#define NAVIGATION_BAR_HEIGHT (self.navigationController.navigationBar.frame.size.height)

524
Example/utils/Colours/Colours.h Executable file
Просмотреть файл

@ -0,0 +1,524 @@
// Copyright (C) 2013 by Benjamin Gordon
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and
// associated documentation files (the "Software"), to
// deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall
// be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "TargetConditionals.h"
#include <Foundation/Foundation.h>
#pragma mark - Static String Keys
static NSString * kColoursRGBA_R = @"RGBA-r";
static NSString * kColoursRGBA_G = @"RGBA-g";
static NSString * kColoursRGBA_B = @"RGBA-b";
static NSString * kColoursRGBA_A = @"RGBA-a";
static NSString * kColoursHSBA_H = @"HSBA-h";
static NSString * kColoursHSBA_S = @"HSBA-s";
static NSString * kColoursHSBA_B = @"HSBA-b";
static NSString * kColoursHSBA_A = @"HSBA-a";
static NSString * kColoursCIE_L = @"LABa-L";
static NSString * kColoursCIE_A = @"LABa-A";
static NSString * kColoursCIE_B = @"LABa-B";
static NSString * kColoursCIE_alpha = @"LABa-a";
static NSString * kColoursCMYK_C = @"CMYK-c";
static NSString * kColoursCMYK_M = @"CMYK-m";
static NSString * kColoursCMYK_Y = @"CMYK-y";
static NSString * kColoursCMYK_K = @"CMYK-k";
#pragma mark - Create correct iOS/OSX interface
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
@interface UIColor (Colours)
#elif TARGET_OS_MAC
#import <AppKit/AppKit.h>
@interface NSColor (Colours)
#endif
#pragma mark - Enums
// Color Scheme Generation Enum
typedef NS_ENUM(NSInteger, ColorScheme) {
ColorSchemeAnalagous,
ColorSchemeMonochromatic,
ColorSchemeTriad,
ColorSchemeComplementary
};
// ColorFormulation Type
typedef NS_ENUM(NSInteger, ColorFormulation) {
ColorFormulationRGBA,
ColorFormulationHSBA,
ColorFormulationLAB,
ColorFormulationCMYK
};
// ColorDistance
typedef NS_ENUM(NSInteger, ColorDistance) {
ColorDistanceCIE76,
ColorDistanceCIE94,
ColorDistanceCIE2000,
};
typedef NS_ENUM(NSInteger, ColorComparison) {
ColorComparisonDarkness,
ColorComparisonLightness,
ColorComparisonDesaturated,
ColorComparisonSaturated,
ColorComparisonRed,
ColorComparisonGreen,
ColorComparisonBlue
};
#pragma mark - Color from Hex/RGBA/HSBA/CIE_LAB/CMYK
/**
Creates a Color from a Hex representation string
@param hexString Hex string that looks like @"#FF0000" or @"FF0000"
@return Color
*/
+ (instancetype)colorFromHexString:(NSString *)hexString;
/**
Creates a Color from an array of 4 NSNumbers (r,g,b,a)
@param rgbaArray 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromRGBAArray:(NSArray *)rgbaArray;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursRGBA_R, kColoursRGBA_G, kColoursRGBA_B, kColoursRGBA_A
@param rgbaDictionary 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromRGBADictionary:(NSDictionary *)rgbaDict;
/**
Creates a Color from an array of 4 NSNumbers (h,s,b,a)
@param hsbaArray 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromHSBAArray:(NSArray *)hsbaArray;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursHSBA_H, kColoursHSBA_S, kColoursHSBA_B, kColoursHSBA_A
@param hsbaDictionary 4 NSNumbers for rgba between 0 - 1
@return Color
*/
+ (instancetype)colorFromHSBADictionary:(NSDictionary *)hsbaDict;
/**
Creates a Color from an array of 4 NSNumbers (L,a,b,alpha)
@param colors 4 NSNumbers for CIE_LAB between 0 - 1
@return Color
*/
+ (instancetype)colorFromCIE_LabArray:(NSArray *)colors;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursCIE_L, kColoursCIE_A, kColoursCIE_B, kColoursCIE_alpha
@param colors 4 NSNumbers for CIE_LAB between 0 - 1
@return Color
*/
+ (instancetype)colorFromCIE_LabDictionary:(NSDictionary *)colors;
/**
Creates a Color from an array of 4 NSNumbers (C,M,Y,K)
@param colors 4 NSNumbers for CMYK between 0 - 1
@return Color
*/
+ (instancetype)colorFromCMYKArray:(NSArray *)cmyk;
/**
Creates a Color from a dictionary of 4 NSNumbers
Keys: kColoursCMYK_C, kColoursCMYK_M, kColoursCMYK_Y, kColoursCMYK_K
@param colors 4 NSNumbers for CMYK between 0 - 1
@return Color
*/
+ (instancetype)colorFromCMYKDictionary:(NSDictionary *)cmyk;
#pragma mark - Hex/RGBA/HSBA/CIE_LAB/CMYK from Color
/**
Creates a Hex representation from a Color
@return NSString
*/
- (NSString *)hexString;
/**
Creates an array of 4 NSNumbers representing the float values of r, g, b, a in that order.
@return NSArray
*/
- (NSArray *)rgbaArray;
/**
Creates an array of 4 NSNumbers representing the float values of h, s, b, a in that order.
@return NSArray
*/
- (NSArray *)hsbaArray;
/**
Creates a dictionary of 4 NSNumbers representing float values with keys: kColoursRGBA_R, kColoursRGBA_G, kColoursRGBA_B, kColoursRGBA_A
@return NSDictionary
*/
- (NSDictionary *)rgbaDictionary;
/**
Creates a dictionary of 4 NSNumbers representing float values with keys: kColoursHSBA_H, kColoursHSBA_S, kColoursHSBA_B, kColoursHSBA_A
@return NSDictionary
*/
- (NSDictionary *)hsbaDictionary;
/**
* Creates an array of 4 NSNumbers representing the float values of L*, a, b, alpha in that order.
*
* @return NSArray
*/
- (NSArray *)CIE_LabArray;
/**
* Creates a dictionary of 4 NSNumbers representing the float values with keys: kColoursCIE_L, kColoursCIE_A, kColoursCIE_B, kColoursCIE_alpha
*
* @return NSDictionary
*/
- (NSDictionary *)CIE_LabDictionary;
/**
* Creates an array of 4 NSNumbers representing the float values of C, M, Y, K in that order.
*
* @return NSArray
*/
- (NSArray *)cmykArray;
/**
* Creates a dictionary of 4 NSNumbers representing the float values with keys: kColoursCMYK_C, kColoursCMYK_M, kColoursCMYK_Y, kColoursCMYK_K
*
* @return NSDictionary
*/
- (NSDictionary *)cmykDictionary;
#pragma mark - Color Components
/**
* Creates an NSDictionary with RGBA and HSBA color components inside.
*
* @return NSDictionary
*/
- (NSDictionary *)colorComponents;
/**
* Returns the red value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)red;
/**
* Returns the green value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)green;
/**
* Returns the blue value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)blue;
/**
* Returns the hue value from an HSBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)hue;
/**
* Returns the saturation value from an HSBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)saturation;
/**
* Returns the brightness value from an HSBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)brightness;
/**
* Returns the alpha value from an RGBA formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)alpha;
/**
* Returns the lightness value from a CIELAB formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)CIE_Lightness;
/**
* Returns the a value from a CIELAB formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)CIE_a;
/**
* Returns the b value from a CIELAB formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)CIE_b;
/**
* Returns the cyan value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)cyan;
/**
* Returns the magenta value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)magenta;
/**
* Returns the yellow value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)yellow;
/**
* Returns the black (K) value from a CMYK formulation of the UIColor.
*
* @return CGFloat
*/
- (CGFloat)keyBlack;
#pragma mark - Darken/Lighten
/**
* Darkens a color by changing the brightness by a percentage you pass in. If you want a 25% darker color, you pass in 0.25;
*
* @param percentage CGFloat
*
* @return Color
*/
- (instancetype)darken:(CGFloat)percentage;
/**
* Lightens a color by changing the brightness by a percentage you pass in. If you want a 25% lighter color, you pass in 0.25;
*
* @param percentage CGFloat
*
* @return Color
*/
- (instancetype)lighten:(CGFloat)percentage;
#pragma mark - 4 Color Scheme from Color
/**
Creates an NSArray of 4 Colors that complement the Color.
@param type ColorSchemeAnalagous, ColorSchemeMonochromatic, ColorSchemeTriad, ColorSchemeComplementary
@return NSArray
*/
- (NSArray *)colorSchemeOfType:(ColorScheme)type;
#pragma mark - Contrasting Color from Color
/**
Creates either [Color whiteColor] or [Color blackColor] depending on if the color this method is run on is dark or light.
@return Color
*/
- (instancetype)blackOrWhiteContrastingColor;
#pragma mark - Complementary Color
/**
Creates a complementary color - a color directly opposite it on the color wheel.
@return Color
*/
- (instancetype)complementaryColor;
#pragma mark - Distance between Colors
/**
* Returns a float of the distance between 2 colors. Defaults to the
* CIE94 specification found here: http://en.wikipedia.org/wiki/Color_difference
*
* @param color Color to check self with.
*
* @return CGFloat
*/
- (CGFloat)distanceFromColor:(id)color;
/**
* Returns a float of the distance between 2 colors, using one of
*
*
* @param color Color to check against
* @param distanceType Formula to calculate with
*
* @return CGFloat
*/
- (CGFloat)distanceFromColor:(id)color type:(ColorDistance)distanceType;
#pragma mark - Compare Colors
+ (NSArray *)sortColors:(NSArray *)colors withComparison:(ColorComparison)comparison;
+ (NSComparisonResult)compareColor:(id)colorA andColor:(id)colorB withComparison:(ColorComparison)comparison;
#pragma mark - Colors
// System Colors
+ (instancetype)infoBlueColor;
+ (instancetype)successColor;
+ (instancetype)warningColor;
+ (instancetype)dangerColor;
// Whites
+ (instancetype)antiqueWhiteColor;
+ (instancetype)oldLaceColor;
+ (instancetype)ivoryColor;
+ (instancetype)seashellColor;
+ (instancetype)ghostWhiteColor;
+ (instancetype)snowColor;
+ (instancetype)linenColor;
// Grays
+ (instancetype)black25PercentColor;
+ (instancetype)black50PercentColor;
+ (instancetype)black75PercentColor;
+ (instancetype)warmGrayColor;
+ (instancetype)coolGrayColor;
+ (instancetype)charcoalColor;
// Blues
+ (instancetype)tealColor;
+ (instancetype)steelBlueColor;
+ (instancetype)robinEggColor;
+ (instancetype)pastelBlueColor;
+ (instancetype)turquoiseColor;
+ (instancetype)skyBlueColor;
+ (instancetype)indigoColor;
+ (instancetype)denimColor;
+ (instancetype)blueberryColor;
+ (instancetype)cornflowerColor;
+ (instancetype)babyBlueColor;
+ (instancetype)midnightBlueColor;
+ (instancetype)fadedBlueColor;
+ (instancetype)icebergColor;
+ (instancetype)waveColor;
// Greens
+ (instancetype)emeraldColor;
+ (instancetype)grassColor;
+ (instancetype)pastelGreenColor;
+ (instancetype)seafoamColor;
+ (instancetype)paleGreenColor;
+ (instancetype)cactusGreenColor;
+ (instancetype)chartreuseColor;
+ (instancetype)hollyGreenColor;
+ (instancetype)oliveColor;
+ (instancetype)oliveDrabColor;
+ (instancetype)moneyGreenColor;
+ (instancetype)honeydewColor;
+ (instancetype)limeColor;
+ (instancetype)cardTableColor;
// Reds
+ (instancetype)salmonColor;
+ (instancetype)brickRedColor;
+ (instancetype)easterPinkColor;
+ (instancetype)grapefruitColor;
+ (instancetype)pinkColor;
+ (instancetype)indianRedColor;
+ (instancetype)strawberryColor;
+ (instancetype)coralColor;
+ (instancetype)maroonColor;
+ (instancetype)watermelonColor;
+ (instancetype)tomatoColor;
+ (instancetype)pinkLipstickColor;
+ (instancetype)paleRoseColor;
+ (instancetype)crimsonColor;
// Purples
+ (instancetype)eggplantColor;
+ (instancetype)pastelPurpleColor;
+ (instancetype)palePurpleColor;
+ (instancetype)coolPurpleColor;
+ (instancetype)violetColor;
+ (instancetype)plumColor;
+ (instancetype)lavenderColor;
+ (instancetype)raspberryColor;
+ (instancetype)fuschiaColor;
+ (instancetype)grapeColor;
+ (instancetype)periwinkleColor;
+ (instancetype)orchidColor;
// Yellows
+ (instancetype)goldenrodColor;
+ (instancetype)yellowGreenColor;
+ (instancetype)bananaColor;
+ (instancetype)mustardColor;
+ (instancetype)buttermilkColor;
+ (instancetype)goldColor;
+ (instancetype)creamColor;
+ (instancetype)lightCreamColor;
+ (instancetype)wheatColor;
+ (instancetype)beigeColor;
// Oranges
+ (instancetype)peachColor;
+ (instancetype)burntOrangeColor;
+ (instancetype)pastelOrangeColor;
+ (instancetype)cantaloupeColor;
+ (instancetype)carrotColor;
+ (instancetype)mandarinColor;
// Browns
+ (instancetype)chiliPowderColor;
+ (instancetype)burntSiennaColor;
+ (instancetype)chocolateColor;
+ (instancetype)coffeeColor;
+ (instancetype)cinnamonColor;
+ (instancetype)almondColor;
+ (instancetype)eggshellColor;
+ (instancetype)sandColor;
+ (instancetype)mudColor;
+ (instancetype)siennaColor;
+ (instancetype)dustColor;
@end

1394
Example/utils/Colours/Colours.m Executable file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

19
Example/utils/Colours/LICENSE Executable file
Просмотреть файл

@ -0,0 +1,19 @@
Copyright (C) 2013 by Benjamin Gordon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Просмотреть файл

@ -0,0 +1,41 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <Foundation/Foundation.h>
@interface CommonUtil : NSObject
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size;
+ (UIImage *)imageWithColor:(UIColor *)color;
+ (NSString*)DataToJsonString:(id)object;
+ (void)simpleDialog:(NSString*)message;
+ (void)showSuccessHUD:(NSString*)message forController:(UIViewController*)controller;
+ (void)showSimpleHUD:(NSString*)message forController:(UIViewController*)controller;
@end

101
Example/utils/CommonUtil.m Normal file
Просмотреть файл

@ -0,0 +1,101 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "CommonUtil.h"
#import "MBProgressHUD.h"
@implementation CommonUtil
+ (NSString*)DataToJsonString:(id)object
{
NSString *jsonString = nil;
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object
options:NSJSONWritingPrettyPrinted
error:&error];
if (! jsonData) {
NSLog(@"Got an error: %@", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return jsonString;
}
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size
{
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, (CGRect){.size = size});
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
+ (UIImage *)imageWithColor:(UIColor *)color
{
return [self imageWithColor:color size:CGSizeMake(1, 1)];
}
+ (void)simpleDialog:(NSString*)message
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Hint"
message:message
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:@"Yes", nil];
[alertView show];
}
+ (void)showSuccessHUD:(NSString*)message forController:(UIViewController*)controller
{
MBProgressHUD * HUD = [[MBProgressHUD alloc] initWithView:controller.view];
[controller.view addSubview:HUD];
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"37x-Checkmark.png"]] ;
HUD.mode = MBProgressHUDModeCustomView;
HUD.labelText = message;
[HUD show:YES];
[HUD hide:YES afterDelay:1.5];
}
+ (void)showSimpleHUD:(NSString*)message forController:(UIViewController*)controller
{
MBProgressHUD * HUD = [[MBProgressHUD alloc] initWithView:controller.view];
[controller.view addSubview:HUD];
HUD.mode = MBProgressHUDModeText;
HUD.labelText = message;
[HUD show:YES];
[HUD hide:YES afterDelay:1.5];
}
@end

Просмотреть файл

@ -0,0 +1,57 @@
/*
* The MIT License
*
* Copyright (c) 2011 Paul Solt, PaulSolt@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#import <Foundation/Foundation.h>
@interface ImageHelper : NSObject {
}
/** Converts a UIImage to RGBA8 bitmap.
@param image - a UIImage to be converted
@return a RGBA8 bitmap, or NULL if any memory allocation issues. Cleanup memory with free() when done.
*/
+ (unsigned char *) convertUIImageToBitmapRGBA8:(UIImage *)image;
+ (unsigned char *) convertUIImageToBitmapGray:(UIImage *)image;
/** A helper routine used to convert a RGBA8 to UIImage
@return a new context that is owned by the caller
*/
+ (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef)image;
+ (CGContextRef) newBitmapGrayContextFromImage:(CGImageRef)image;
/** Converts a RGBA8 bitmap to a UIImage.
@param buffer - the RGBA8 unsigned char * bitmap
@param width - the number of pixels wide
@param height - the number of pixels tall
@return a UIImage that is autoreleased or nil if memory allocation issues
*/
+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *)buffer
withWidth:(int)width
withHeight:(int)height;
@end

Просмотреть файл

@ -0,0 +1,317 @@
/*
* The MIT License
*
* Copyright (c) 2011 Paul Solt, PaulSolt@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#import "ImageHelper.h"
@implementation ImageHelper
+ (unsigned char *) convertUIImageToBitmapRGBA8:(UIImage *) image {
CGImageRef imageRef = image.CGImage;
// Create a bitmap context to draw the uiimage into
CGContextRef context = [self newBitmapRGBA8ContextFromImage:imageRef];
if(!context) {
return NULL;
}
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
CGRect rect = CGRectMake(0, 0, width, height);
// Draw image into the context to get the raw image data
CGContextDrawImage(context, rect, imageRef);
// Get a pointer to the data
unsigned char *bitmapData = (unsigned char *)CGBitmapContextGetData(context);
// Copy the data and release the memory (return memory allocated with new)
size_t bytesPerRow = CGBitmapContextGetBytesPerRow(context);
size_t bufferLength = bytesPerRow * height;
unsigned char *newBitmap = NULL;
if(bitmapData) {
newBitmap = (unsigned char *)malloc(sizeof(unsigned char) * bytesPerRow * height);
if(newBitmap) { // Copy the data
int j = 0;
for(int i = 0; i < bufferLength; i+=4) {
newBitmap[j] = bitmapData[i+2];
newBitmap[j+1] = bitmapData[i+1];
newBitmap[j+2] = bitmapData[i];
j+=3;
}
}
free(bitmapData);
} else {
NSLog(@"Error getting bitmap pixel data\n");
}
CGContextRelease(context);
return newBitmap;
}
+ (unsigned char *) convertUIImageToBitmapGray:(UIImage *) image {
CGImageRef imageRef = image.CGImage;
// Create a bitmap context to draw the uiimage into
CGContextRef context = [self newBitmapGrayContextFromImage:imageRef];
if(!context) {
return NULL;
}
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
CGRect rect = CGRectMake(0, 0, width, height);
// Draw image into the context to get the raw image data
CGContextDrawImage(context, rect, imageRef);
// Get a pointer to the data
unsigned char *bitmapData = (unsigned char *)CGBitmapContextGetData(context);
// Copy the data and release the memory (return memory allocated with new)
size_t bytesPerRow = CGBitmapContextGetBytesPerRow(context);
size_t bufferLength = bytesPerRow * height;
unsigned char *newBitmap = NULL;
if(bitmapData) {
newBitmap = (unsigned char *)malloc(sizeof(unsigned char) * bytesPerRow * height);
if(newBitmap) { // Copy the data
for(int i = 0; i < bufferLength; ++i) {
newBitmap[i] = bitmapData[i];
}
}
free(bitmapData);
} else {
NSLog(@"Error getting bitmap pixel data\n");
}
CGContextRelease(context);
return newBitmap;
}
+ (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image {
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
uint32_t *bitmapData;
size_t bitsPerPixel = 32;
size_t bitsPerComponent = 8;
size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
size_t bytesPerRow = width * bytesPerPixel;
size_t bufferLength = bytesPerRow * height;
colorSpace = CGColorSpaceCreateDeviceRGB();
if(!colorSpace) {
NSLog(@"Error allocating color space RGB\n");
return NULL;
}
// Allocate memory for image data
bitmapData = (uint32_t *)malloc(bufferLength);
if(!bitmapData) {
NSLog(@"Error allocating memory for bitmap\n");
CGColorSpaceRelease(colorSpace);
return NULL;
}
//Create bitmap context
context = CGBitmapContextCreate(bitmapData,
width,
height,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast); // RGBA
if(!context) {
free(bitmapData);
NSLog(@"Bitmap context not created");
}
CGColorSpaceRelease(colorSpace);
return context;
}
+ (CGContextRef) newBitmapGrayContextFromImage:(CGImageRef) image {
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
uint32_t *bitmapData;
size_t bitsPerPixel = 8;
size_t bitsPerComponent = 8;
size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
size_t bytesPerRow = width * bytesPerPixel;
size_t bufferLength = bytesPerRow * height;
colorSpace = CGColorSpaceCreateDeviceGray();
if(!colorSpace) {
NSLog(@"Error allocating color space RGB\n");
return NULL;
}
// Allocate memory for image data
bitmapData = (uint32_t *)malloc(bufferLength);
if(!bitmapData) {
NSLog(@"Error allocating memory for bitmap\n");
CGColorSpaceRelease(colorSpace);
return NULL;
}
//Create bitmap context
context = CGBitmapContextCreate(bitmapData,
width,
height,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaNone); // RGBA
if(!context) {
free(bitmapData);
NSLog(@"Bitmap context not created");
}
CGColorSpaceRelease(colorSpace);
return context;
}
+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer
withWidth:(int) width
withHeight:(int) height {
size_t bufferLength = width * height * 4;
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, bufferLength, NULL);
size_t bitsPerComponent = 8;
size_t bitsPerPixel = 32;
size_t bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
if(colorSpaceRef == NULL) {
NSLog(@"Error allocating color space");
CGDataProviderRelease(provider);
return nil;
}
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef iref = CGImageCreate(width,
height,
bitsPerComponent,
bitsPerPixel,
bytesPerRow,
colorSpaceRef,
bitmapInfo,
provider, // data provider
NULL, // decode
YES, // should interpolate
renderingIntent);
uint32_t* pixels = (uint32_t*)malloc(bufferLength);
if(pixels == NULL) {
NSLog(@"Error: Memory not allocated for bitmap");
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpaceRef);
CGImageRelease(iref);
return nil;
}
CGContextRef context = CGBitmapContextCreate(pixels,
width,
height,
bitsPerComponent,
bytesPerRow,
colorSpaceRef,
bitmapInfo);
if(context == NULL) {
NSLog(@"Error context not created");
free(pixels);
}
UIImage *image = nil;
if(context) {
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref);
CGImageRef imageRef = CGBitmapContextCreateImage(context);
// Support both iPad 3.2 and iPhone 4 Retina displays with the correct scale
if([UIImage respondsToSelector:@selector(imageWithCGImage:scale:orientation:)]) {
float scale = [[UIScreen mainScreen] scale];
image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
} else {
image = [UIImage imageWithCGImage:imageRef];
}
CGImageRelease(imageRef);
CGContextRelease(context);
}
CGColorSpaceRelease(colorSpaceRef);
CGImageRelease(iref);
CGDataProviderRelease(provider);
if(pixels) {
free(pixels);
}
return image;
}
@end

Просмотреть файл

@ -0,0 +1,515 @@
//
// MBProgressHUD.h
// Version 0.9.1
// Created by Matej Bukovinski on 2.4.09.
//
// This code is distributed under the terms and conditions of the MIT license.
// Copyright (c) 2009-2015 Matej Bukovinski
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreGraphics/CoreGraphics.h>
@protocol MBProgressHUDDelegate;
typedef NS_ENUM(NSInteger, MBProgressHUDMode) {
/** Progress is shown using an UIActivityIndicatorView. This is the default. */
MBProgressHUDModeIndeterminate,
/** Progress is shown using a round, pie-chart like, progress view. */
MBProgressHUDModeDeterminate,
/** Progress is shown using a horizontal progress bar */
MBProgressHUDModeDeterminateHorizontalBar,
/** Progress is shown using a ring-shaped progress view. */
MBProgressHUDModeAnnularDeterminate,
/** Shows a custom view */
MBProgressHUDModeCustomView,
/** Shows only labels */
MBProgressHUDModeText
};
typedef NS_ENUM(NSInteger, MBProgressHUDAnimation) {
/** Opacity animation */
MBProgressHUDAnimationFade,
/** Opacity + scale animation */
MBProgressHUDAnimationZoom,
MBProgressHUDAnimationZoomOut = MBProgressHUDAnimationZoom,
MBProgressHUDAnimationZoomIn
};
#ifndef MB_INSTANCETYPE
#if __has_feature(objc_instancetype)
#define MB_INSTANCETYPE instancetype
#else
#define MB_INSTANCETYPE id
#endif
#endif
#ifndef MB_STRONG
#if __has_feature(objc_arc)
#define MB_STRONG strong
#else
#define MB_STRONG retain
#endif
#endif
#ifndef MB_WEAK
#if __has_feature(objc_arc_weak)
#define MB_WEAK weak
#elif __has_feature(objc_arc)
#define MB_WEAK unsafe_unretained
#else
#define MB_WEAK assign
#endif
#endif
#if NS_BLOCKS_AVAILABLE
typedef void (^MBProgressHUDCompletionBlock)();
#endif
/**
* Displays a simple HUD window containing a progress indicator and two optional labels for short messages.
*
* This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class.
* The MBProgressHUD window spans over the entire space given to it by the initWithFrame constructor and catches all
* user input on this region, thereby preventing the user operations on components below the view. The HUD itself is
* drawn centered as a rounded semi-transparent view which resizes depending on the user specified content.
*
* This view supports four modes of operation:
* - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView
* - MBProgressHUDModeDeterminate - shows a custom round progress indicator
* - MBProgressHUDModeAnnularDeterminate - shows a custom annular progress indicator
* - MBProgressHUDModeCustomView - shows an arbitrary, user specified view (@see customView)
*
* All three modes can have optional labels assigned:
* - If the labelText property is set and non-empty then a label containing the provided content is placed below the
* indicator view.
* - If also the detailsLabelText property is set then another label is placed below the first label.
*/
@interface MBProgressHUD : UIView
/**
* Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:.
*
* @param view The view that the HUD will be added to
* @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use
* animations while appearing.
* @return A reference to the created HUD.
*
* @see hideHUDForView:animated:
* @see animationType
*/
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;
/**
* Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:.
*
* @param view The view that is going to be searched for a HUD subview.
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
* animations while disappearing.
* @return YES if a HUD was found and removed, NO otherwise.
*
* @see showHUDAddedTo:animated:
* @see animationType
*/
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated;
/**
* Finds all the HUD subviews and hides them.
*
* @param view The view that is going to be searched for HUD subviews.
* @param animated If set to YES the HUDs will disappear using the current animationType. If set to NO the HUDs will not use
* animations while disappearing.
* @return the number of HUDs found and removed.
*
* @see hideHUDForView:animated:
* @see animationType
*/
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated;
/**
* Finds the top-most HUD subview and returns it.
*
* @param view The view that is going to be searched.
* @return A reference to the last HUD subview discovered.
*/
+ (MB_INSTANCETYPE)HUDForView:(UIView *)view;
/**
* Finds all HUD subviews and returns them.
*
* @param view The view that is going to be searched.
* @return All found HUD views (array of MBProgressHUD objects).
*/
+ (NSArray *)allHUDsForView:(UIView *)view;
/**
* A convenience constructor that initializes the HUD with the window's bounds. Calls the designated constructor with
* window.bounds as the parameter.
*
* @param window The window instance that will provide the bounds for the HUD. Should be the same instance as
* the HUD's superview (i.e., the window that the HUD will be added to).
*/
- (id)initWithWindow:(UIWindow *)window;
/**
* A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with
* view.bounds as the parameter
*
* @param view The view instance that will provide the bounds for the HUD. Should be the same instance as
* the HUD's superview (i.e., the view that the HUD will be added to).
*/
- (id)initWithView:(UIView *)view;
/**
* Display the HUD. You need to make sure that the main thread completes its run loop soon after this method call so
* the user interface can be updated. Call this method when your task is already set-up to be executed in a new thread
* (e.g., when using something like NSOperation or calling an asynchronous call like NSURLRequest).
*
* @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use
* animations while appearing.
*
* @see animationType
*/
- (void)show:(BOOL)animated;
/**
* Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
* hide the HUD when your task completes.
*
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
* animations while disappearing.
*
* @see animationType
*/
- (void)hide:(BOOL)animated;
/**
* Hide the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
* hide the HUD when your task completes.
*
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
* animations while disappearing.
* @param delay Delay in seconds until the HUD is hidden.
*
* @see animationType
*/
- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay;
/**
* Shows the HUD while a background task is executing in a new thread, then hides the HUD.
*
* This method also takes care of autorelease pools so your method does not have to be concerned with setting up a
* pool.
*
* @param method The method to be executed while the HUD is shown. This method will be executed in a new thread.
* @param target The object that the target method belongs to.
* @param object An optional object to be passed to the method.
* @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will not use
* animations while (dis)appearing.
*/
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated;
#if NS_BLOCKS_AVAILABLE
/**
* Shows the HUD while a block is executing on a background queue, then hides the HUD.
*
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block;
/**
* Shows the HUD while a block is executing on a background queue, then hides the HUD.
*
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion;
/**
* Shows the HUD while a block is executing on the specified dispatch queue, then hides the HUD.
*
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue;
/**
* Shows the HUD while a block is executing on the specified dispatch queue, executes completion block on the main queue, and then hides the HUD.
*
* @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will
* not use animations while (dis)appearing.
* @param block The block to be executed while the HUD is shown.
* @param queue The dispatch queue on which the block should be executed.
* @param completion The block to be executed on completion.
*
* @see completionBlock
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
completionBlock:(MBProgressHUDCompletionBlock)completion;
/**
* A block that gets called after the HUD was completely hidden.
*/
@property (copy) MBProgressHUDCompletionBlock completionBlock;
#endif
/**
* MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate.
*
* @see MBProgressHUDMode
*/
@property (assign) MBProgressHUDMode mode;
/**
* The animation type that should be used when the HUD is shown and hidden.
*
* @see MBProgressHUDAnimation
*/
@property (assign) MBProgressHUDAnimation animationType;
/**
* The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView.
* For best results use a 37 by 37 pixel view (so the bounds match the built in indicator bounds).
*/
@property (MB_STRONG) UIView *customView;
/**
* The HUD delegate object.
*
* @see MBProgressHUDDelegate
*/
@property (MB_WEAK) id<MBProgressHUDDelegate> delegate;
/**
* An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit
* the entire text. If the text is too long it will get clipped by displaying "..." at the end. If left unchanged or
* set to @"", then no message is displayed.
*/
@property (copy) NSString *labelText;
/**
* An optional details message displayed below the labelText message. This message is displayed only if the labelText
* property is also set and is different from an empty string (@""). The details text can span multiple lines.
*/
@property (copy) NSString *detailsLabelText;
/**
* The opacity of the HUD window. Defaults to 0.8 (80% opacity).
*/
@property (assign) float opacity;
/**
* The color of the HUD window. Defaults to black. If this property is set, color is set using
* this UIColor and the opacity property is not used. using retain because performing copy on
* UIColor base colors (like [UIColor greenColor]) cause problems with the copyZone.
*/
@property (MB_STRONG) UIColor *color;
/**
* The x-axis offset of the HUD relative to the centre of the superview.
*/
@property (assign) float xOffset;
/**
* The y-axis offset of the HUD relative to the centre of the superview.
*/
@property (assign) float yOffset;
/**
* The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views).
* Defaults to 20.0
*/
@property (assign) float margin;
/**
* The corner radius for the HUD
* Defaults to 10.0
*/
@property (assign) float cornerRadius;
/**
* Cover the HUD background view with a radial gradient.
*/
@property (assign) BOOL dimBackground;
/*
* Grace period is the time (in seconds) that the invoked method may be run without
* showing the HUD. If the task finishes before the grace time runs out, the HUD will
* not be shown at all.
* This may be used to prevent HUD display for very short tasks.
* Defaults to 0 (no grace time).
* Grace time functionality is only supported when the task status is known!
* @see taskInProgress
*/
@property (assign) float graceTime;
/**
* The minimum time (in seconds) that the HUD is shown.
* This avoids the problem of the HUD being shown and than instantly hidden.
* Defaults to 0 (no minimum show time).
*/
@property (assign) float minShowTime;
/**
* Indicates that the executed operation is in progress. Needed for correct graceTime operation.
* If you don't set a graceTime (different than 0.0) this does nothing.
* This property is automatically set when using showWhileExecuting:onTarget:withObject:animated:.
* When threading is done outside of the HUD (i.e., when the show: and hide: methods are used directly),
* you need to set this property when your task starts and completes in order to have normal graceTime
* functionality.
*/
@property (assign) BOOL taskInProgress;
/**
* Removes the HUD from its parent view when hidden.
* Defaults to NO.
*/
@property (assign) BOOL removeFromSuperViewOnHide;
/**
* Font to be used for the main label. Set this property if the default is not adequate.
*/
@property (MB_STRONG) UIFont* labelFont;
/**
* Color to be used for the main label. Set this property if the default is not adequate.
*/
@property (MB_STRONG) UIColor* labelColor;
/**
* Font to be used for the details label. Set this property if the default is not adequate.
*/
@property (MB_STRONG) UIFont* detailsLabelFont;
/**
* Color to be used for the details label. Set this property if the default is not adequate.
*/
@property (MB_STRONG) UIColor* detailsLabelColor;
/**
* The color of the activity indicator. Defaults to [UIColor whiteColor]
* Does nothing on pre iOS 5.
*/
@property (MB_STRONG) UIColor *activityIndicatorColor;
/**
* The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0.
*/
@property (assign) float progress;
/**
* The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size).
*/
@property (assign) CGSize minSize;
/**
* The actual size of the HUD bezel.
* You can use this to limit touch handling on the bezel aria only.
* @see https://github.com/jdg/MBProgressHUD/pull/200
*/
@property (atomic, assign, readonly) CGSize size;
/**
* Force the HUD dimensions to be equal if possible.
*/
@property (assign, getter = isSquare) BOOL square;
@end
@protocol MBProgressHUDDelegate <NSObject>
@optional
/**
* Called after the HUD was fully hidden from the screen.
*/
- (void)hudWasHidden:(MBProgressHUD *)hud;
@end
/**
* A progress view for showing definite progress by filling up a circle (pie chart).
*/
@interface MBRoundProgressView : UIView
/**
* Progress (0.0 to 1.0)
*/
@property (nonatomic, assign) float progress;
/**
* Indicator progress color.
* Defaults to white [UIColor whiteColor]
*/
@property (nonatomic, MB_STRONG) UIColor *progressTintColor;
/**
* Indicator background (non-progress) color.
* Defaults to translucent white (alpha 0.1)
*/
@property (nonatomic, MB_STRONG) UIColor *backgroundTintColor;
/*
* Display mode - NO = round or YES = annular. Defaults to round.
*/
@property (nonatomic, assign, getter = isAnnular) BOOL annular;
@end
/**
* A flat bar progress view.
*/
@interface MBBarProgressView : UIView
/**
* Progress (0.0 to 1.0)
*/
@property (nonatomic, assign) float progress;
/**
* Bar border line color.
* Defaults to white [UIColor whiteColor].
*/
@property (nonatomic, MB_STRONG) UIColor *lineColor;
/**
* Bar background color.
* Defaults to clear [UIColor clearColor];
*/
@property (nonatomic, MB_STRONG) UIColor *progressRemainingColor;
/**
* Bar progress color.
* Defaults to white [UIColor whiteColor].
*/
@property (nonatomic, MB_STRONG) UIColor *progressColor;
@end

Разница между файлами не показана из-за своего большого размера Загрузить разницу

13
Example/utils/UIImage+Crop.h Executable file
Просмотреть файл

@ -0,0 +1,13 @@
//
// UIImage+Crop.h
// LLSimpleCamera
//
// Created by Ömer Faruk Gül on 27/10/14.
// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIImage(CropCategory)
- (UIImage *)crop:(CGRect)rect;
@end

24
Example/utils/UIImage+Crop.m Executable file
Просмотреть файл

@ -0,0 +1,24 @@
//
// UIImage+Crop.m
// LLSimpleCamera
//
// Created by Ömer Faruk Gül on 27/10/14.
// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved.
//
#import "UIImage+Crop.h"
@implementation UIImage(CropCategory)
- (UIImage *)crop:(CGRect)rect {
rect = CGRectMake(rect.origin.x * self.scale,
rect.origin.y * self.scale,
rect.size.width * self.scale,
rect.size.height * self.scale);
CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
CGImageRelease(imageRef);
return result;
}
@end

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface UIImage(fixOrientation)
- (UIImage *)fixOrientation;
@end

Просмотреть файл

@ -0,0 +1,109 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "UIImage+FixOrientation.h"
@implementation UIImage (fixOrientation)
- (UIImage *)fixOrientation {
if (self.imageOrientation == UIImageOrientationUp) return self;
CGAffineTransform transform = CGAffineTransformIdentity;
switch (self.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, self.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
break;
}
switch (self.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationUp:
case UIImageOrientationDown:
case UIImageOrientationLeft:
case UIImageOrientationRight:
break;
}
CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
CGImageGetBitsPerComponent(self.CGImage), 0,
CGImageGetColorSpace(self.CGImage),
CGImageGetBitmapInfo(self.CGImage));
CGContextConcatCTM(ctx, transform);
switch (self.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
break;
default:
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
break;
}
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
return img;
}
@end

36
Example/utils/UIImage+Resize.h Executable file
Просмотреть файл

@ -0,0 +1,36 @@
/***********************************************************************************
*
* Copyright (c) 2010 Olivier Halligon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
***********************************************************************************
*
* Any comment or suggestion welcome. Referencing this project in your AboutBox is appreciated.
* Please tell me if you use this class so we can cross-reference our projects.
*
***********************************************************************************/
#import <UIKit/UIKit.h>
@interface UIImage(ResizeCategory)
-(UIImage*)resizedImageToSize:(CGSize)dstSize;
-(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale;
@end

153
Example/utils/UIImage+Resize.m Executable file
Просмотреть файл

@ -0,0 +1,153 @@
//
// UIImage+Resize.m
//
// Created by Olivier Halligon on 12/08/09.
// Copyright 2009 AliSoftware. All rights reserved.
//
#import "UIImage+Resize.h"
@implementation UIImage (ResizeCategory)
-(UIImage*)resizedImageToSize:(CGSize)dstSize
{
CGImageRef imgRef = self.CGImage;
// the below values are regardless of orientation : for UIImages from Camera, width>height (landscape)
CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which is dependant on the imageOrientation)!
/* Don't resize if we already meet the required destination size. */
if (CGSizeEqualToSize(srcSize, dstSize)) {
return self;
}
CGFloat scaleRatio = dstSize.width / srcSize.width;
UIImageOrientation orient = self.imageOrientation;
CGAffineTransform transform = CGAffineTransformIdentity;
switch(orient) {
case UIImageOrientationUp: //EXIF = 1
transform = CGAffineTransformIdentity;
break;
case UIImageOrientationUpMirrored: //EXIF = 2
transform = CGAffineTransformMakeTranslation(srcSize.width, 0.0);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
break;
case UIImageOrientationDown: //EXIF = 3
transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationDownMirrored: //EXIF = 4
transform = CGAffineTransformMakeTranslation(0.0, srcSize.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
break;
case UIImageOrientationLeftMirrored: //EXIF = 5
dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2);
break;
case UIImageOrientationLeft: //EXIF = 6
dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeTranslation(0.0, srcSize.width);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2);
break;
case UIImageOrientationRightMirrored: //EXIF = 7
dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeScale(-1.0, 1.0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight: //EXIF = 8
dstSize = CGSizeMake(dstSize.height, dstSize.width);
transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
default:
[NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
}
/////////////////////////////////////////////////////////////////////////////
// The actual resize: draw the image on a new context, applying a transform matrix
UIGraphicsBeginImageContextWithOptions(dstSize, NO, self.scale);
CGContextRef context = UIGraphicsGetCurrentContext();
if (!context) {
return nil;
}
if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
CGContextScaleCTM(context, -scaleRatio, scaleRatio);
CGContextTranslateCTM(context, -srcSize.height, 0);
} else {
CGContextScaleCTM(context, scaleRatio, -scaleRatio);
CGContextTranslateCTM(context, 0, -srcSize.height);
}
CGContextConcatCTM(context, transform);
// we use srcSize (and not dstSize) as the size to specify is in user space (and we use the CTM to apply a scaleRatio)
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, srcSize.width, srcSize.height), imgRef);
UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resizedImage;
}
/////////////////////////////////////////////////////////////////////////////
-(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale
{
// get the image size (independant of imageOrientation)
CGImageRef imgRef = self.CGImage;
CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which depends on the imageOrientation)!
// adjust boundingSize to make it independant on imageOrientation too for farther computations
UIImageOrientation orient = self.imageOrientation;
switch (orient) {
case UIImageOrientationLeft:
case UIImageOrientationRight:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
boundingSize = CGSizeMake(boundingSize.height, boundingSize.width);
break;
default:
// NOP
break;
}
// Compute the target CGRect in order to keep aspect-ratio
CGSize dstSize;
if ( !scale && (srcSize.width < boundingSize.width) && (srcSize.height < boundingSize.height) ) {
//NSLog(@"Image is smaller, and we asked not to scale it in this case (scaleIfSmaller:NO)");
dstSize = srcSize; // no resize (we could directly return 'self' here, but we draw the image anyway to take image orientation into account)
} else {
CGFloat wRatio = boundingSize.width / srcSize.width;
CGFloat hRatio = boundingSize.height / srcSize.height;
if (wRatio < hRatio) {
//NSLog(@"Width imposed, Height scaled ; ratio = %f",wRatio);
dstSize = CGSizeMake(boundingSize.width, floorf(srcSize.height * wRatio));
} else {
//NSLog(@"Height imposed, Width scaled ; ratio = %f",hRatio);
dstSize = CGSizeMake(floorf(srcSize.width * hRatio), boundingSize.height);
}
}
return [self resizedImageToSize:dstSize];
}
@end

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
@protocol BackButtonHandlerProtocol <NSObject>
@optional
// Override this method in UIViewController derived class to handle 'Back' button click
-(BOOL)navigationShouldPopOnBackButton;
@end
@interface UIViewController (BackButtonHandler) <BackButtonHandlerProtocol>
@end

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "UIViewController+BackButtonHandler.h"
@implementation UIViewController (BackButtonHandler)
@end

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Cognitive Services (formerly Project Oxford): https://www.microsoft.com/cognitive-services
//
// Microsoft Cognitive Services (formerly Project Oxford) GitHub:
// https://github.com/Microsoft/Cognitive-Face-iOS
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import <UIKit/UIKit.h>
@interface UIViewController (DismissKeyboard)
-(void)setupForDismissKeyboard;
@end

Просмотреть файл

@ -29,27 +29,34 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#import "UIViewController+DismissKeyboard.h"
#import "MPOGroupingTableViewCell.h"
#import "MPOImageCollectionViewCell.h"
#import "MPOGroupingFaceCellObject.h"
@implementation MPOGroupingTableViewCell
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [self.group count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MPOImageCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"groupCell" forIndexPath:indexPath];
@implementation UIViewController (DismissKeyboard)
- (void)setupForDismissKeyboard {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
UITapGestureRecognizer *singleTapGR =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(tapAnywhereToDismissKeyboard:)];
MPOGroupingFaceCellObject *obj = [self.group objectAtIndex:indexPath.row];
__weak UIViewController *weakSelf = self;
NSOperationQueue *mainQuene =[NSOperationQueue mainQueue];
[nc addObserverForName:UIKeyboardWillShowNotification
object:nil
queue:mainQuene
usingBlock:^(NSNotification *note){
[weakSelf.view addGestureRecognizer:singleTapGR];
}];
[nc addObserverForName:UIKeyboardWillHideNotification
object:nil
queue:mainQuene
usingBlock:^(NSNotification *note){
[weakSelf.view removeGestureRecognizer:singleTapGR];
}];
}
cell.imageView.image = obj.croppedFaceImage;
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(70, self.collectionView.frame.size.height);
- (void)tapAnywhereToDismissKeyboard:(UIGestureRecognizer *)gestureRecognizer {
[self.view endEditing:YES];
}
@end

103
Example/utils/ViewUtils.h Executable file
Просмотреть файл

@ -0,0 +1,103 @@
//
// ViewUtils.h
//
// Version 1.1.2
//
// Created by Nick Lockwood on 19/11/2011.
// Copyright (c) 2011 Charcoal Design
//
// Distributed under the permissive zlib License
// Get the latest version from here:
//
// https://github.com/nicklockwood/ViewUtils
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import <UIKit/UIKit.h>
@interface UIView (ViewUtils)
//nib loading
+ (id)instanceWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil owner:(id)owner;
- (void)loadContentsWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil;
//hierarchy
- (UIView *)viewMatchingPredicate:(NSPredicate *)predicate;
- (UIView *)viewWithTag:(NSInteger)tag ofClass:(Class)viewClass;
- (UIView *)viewOfClass:(Class)viewClass;
- (NSArray *)viewsMatchingPredicate:(NSPredicate *)predicate;
- (NSArray *)viewsWithTag:(NSInteger)tag;
- (NSArray *)viewsWithTag:(NSInteger)tag ofClass:(Class)viewClass;
- (NSArray *)viewsOfClass:(Class)viewClass;
- (UIView *)firstSuperviewMatchingPredicate:(NSPredicate *)predicate;
- (UIView *)firstSuperviewOfClass:(Class)viewClass;
- (UIView *)firstSuperviewWithTag:(NSInteger)tag;
- (UIView *)firstSuperviewWithTag:(NSInteger)tag ofClass:(Class)viewClass;
- (BOOL)viewOrAnySuperviewMatchesPredicate:(NSPredicate *)predicate;
- (BOOL)viewOrAnySuperviewIsKindOfClass:(Class)viewClass;
- (BOOL)isSuperviewOfView:(UIView *)view;
- (BOOL)isSubviewOfView:(UIView *)view;
- (UIViewController *)firstViewController;
- (UIView *)firstResponder;
//frame accessors
@property (nonatomic, assign) CGPoint origin;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, assign) CGFloat top;
@property (nonatomic, assign) CGFloat left;
@property (nonatomic, assign) CGFloat bottom;
@property (nonatomic, assign) CGFloat right;
@property (nonatomic, assign) CGFloat width;
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, assign) CGFloat x;
@property (nonatomic, assign) CGFloat y;
//bounds accessors
@property (nonatomic, assign) CGSize boundsSize;
@property (nonatomic, assign) CGFloat boundsWidth;
@property (nonatomic, assign) CGFloat boundsHeight;
//content getters
@property (nonatomic, readonly) CGRect contentBounds;
@property (nonatomic, readonly) CGPoint contentCenter;
//additional frame setters
- (void)setLeft:(CGFloat)left right:(CGFloat)right;
- (void)setWidth:(CGFloat)width right:(CGFloat)right;
- (void)setTop:(CGFloat)top bottom:(CGFloat)bottom;
- (void)setHeight:(CGFloat)height bottom:(CGFloat)bottom;
//animation
- (void)crossfadeWithDuration:(NSTimeInterval)duration;
- (void)crossfadeWithDuration:(NSTimeInterval)duration completion:(void (^)(void))completion;
@end

479
Example/utils/ViewUtils.m Executable file
Просмотреть файл

@ -0,0 +1,479 @@
//
// ViewUtils.m
//
// Version 1.1.2
//
// Created by Nick Lockwood on 19/11/2011.
// Copyright (c) 2011 Charcoal Design
//
// Distributed under the permissive zlib License
// Get the latest version from here:
//
// https://github.com/nicklockwood/ViewUtils
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import "ViewUtils.h"
#import <QuartzCore/QuartzCore.h>
#pragma GCC diagnostic ignored "-Wgnu"
@implementation UIView (ViewUtils)
//nib loading
+ (id)instanceWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil owner:(id)owner
{
//default values
NSString *nibName = nibNameOrNil ?: NSStringFromClass(self);
NSBundle *bundle = bundleOrNil ?: [NSBundle mainBundle];
//cache nib to prevent unnecessary filesystem access
static NSCache *nibCache = nil;
if (nibCache == nil)
{
nibCache = [[NSCache alloc] init];
}
NSString *pathKey = [NSString stringWithFormat:@"%@.%@", bundle.bundleIdentifier, nibName];
UINib *nib = [nibCache objectForKey:pathKey];
if (nib == nil)
{
NSString *nibPath = [bundle pathForResource:nibName ofType:@"nib"];
if (nibPath) nib = [UINib nibWithNibName:nibName bundle:bundle];
[nibCache setObject:nib ?: [NSNull null] forKey:pathKey];
}
else if ([nib isKindOfClass:[NSNull class]])
{
nib = nil;
}
if (nib)
{
//attempt to load from nib
NSArray *contents = [nib instantiateWithOwner:owner options:nil];
UIView *view = [contents count]? [contents objectAtIndex:0]: nil;
NSAssert ([view isKindOfClass:self], @"First object in nib '%@' was '%@'. Expected '%@'", nibName, view, self);
return view;
}
//return empty view
return [[[self class] alloc] init];
}
- (void)loadContentsWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil
{
NSString *nibName = nibNameOrNil ?: NSStringFromClass([self class]);
UIView *view = [UIView instanceWithNibName:nibName bundle:bundleOrNil owner:self];
if (view)
{
if (CGSizeEqualToSize(self.frame.size, CGSizeZero))
{
//if we have zero size, set size from content
self.size = view.size;
}
else
{
//otherwise set content size to match our size
view.frame = self.contentBounds;
}
[self addSubview:view];
}
}
//view searching
- (UIView *)viewMatchingPredicate:(NSPredicate *)predicate
{
if ([predicate evaluateWithObject:self])
{
return self;
}
for (UIView *view in self.subviews)
{
UIView *match = [view viewMatchingPredicate:predicate];
if (match) return match;
}
return nil;
}
- (UIView *)viewWithTag:(NSInteger)tag ofClass:(Class)viewClass
{
return [self viewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused NSDictionary *bindings) {
return [evaluatedObject tag] == tag && [evaluatedObject isKindOfClass:viewClass];
}]];
}
- (UIView *)viewOfClass:(Class)viewClass
{
return [self viewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused NSDictionary *bindings) {
return [evaluatedObject isKindOfClass:viewClass];
}]];
}
- (NSArray *)viewsMatchingPredicate:(NSPredicate *)predicate
{
NSMutableArray *matches = [NSMutableArray array];
if ([predicate evaluateWithObject:self])
{
[matches addObject:self];
}
for (UIView *view in self.subviews)
{
//check for subviews
//avoid creating unnecessary array
if ([view.subviews count])
{
[matches addObjectsFromArray:[view viewsMatchingPredicate:predicate]];
}
else if ([predicate evaluateWithObject:view])
{
[matches addObject:view];
}
}
return matches;
}
- (NSArray *)viewsWithTag:(NSInteger)tag
{
return [self viewsMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) {
return [evaluatedObject tag] == tag;
}]];
}
- (NSArray *)viewsWithTag:(NSInteger)tag ofClass:(Class)viewClass
{
return [self viewsMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) {
return [evaluatedObject tag] == tag && [evaluatedObject isKindOfClass:viewClass];
}]];
}
- (NSArray *)viewsOfClass:(Class)viewClass
{
return [self viewsMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) {
return [evaluatedObject isKindOfClass:viewClass];
}]];
}
- (UIView *)firstSuperviewMatchingPredicate:(NSPredicate *)predicate
{
if ([predicate evaluateWithObject:self])
{
return self;
}
return [self.superview firstSuperviewMatchingPredicate:predicate];
}
- (UIView *)firstSuperviewOfClass:(Class)viewClass
{
return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) {
return [superview isKindOfClass:viewClass];
}]];
}
- (UIView *)firstSuperviewWithTag:(NSInteger)tag
{
return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) {
return superview.tag == tag;
}]];
}
- (UIView *)firstSuperviewWithTag:(NSInteger)tag ofClass:(Class)viewClass
{
return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) {
return superview.tag == tag && [superview isKindOfClass:viewClass];
}]];
}
- (BOOL)viewOrAnySuperviewMatchesPredicate:(NSPredicate *)predicate
{
if ([predicate evaluateWithObject:self])
{
return YES;
}
return [self.superview viewOrAnySuperviewMatchesPredicate:predicate];
}
- (BOOL)viewOrAnySuperviewIsKindOfClass:(Class)viewClass
{
return [self viewOrAnySuperviewMatchesPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) {
return [superview isKindOfClass:viewClass];
}]];
}
- (BOOL)isSuperviewOfView:(UIView *)view
{
return [self firstSuperviewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *superview, __unused id bindings) {
return superview == view;
}]] != nil;
}
- (BOOL)isSubviewOfView:(UIView *)view
{
return [view isSuperviewOfView:self];
}
//responder chain
- (UIViewController *)firstViewController
{
id responder = self;
while ((responder = [responder nextResponder]))
{
if ([responder isKindOfClass:[UIViewController class]])
{
return responder;
}
}
return nil;
}
- (UIView *)firstResponder
{
return [self viewMatchingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, __unused id bindings) {
return [evaluatedObject isFirstResponder];
}]];
}
//frame accessors
- (CGPoint)origin
{
return self.frame.origin;
}
- (void)setOrigin:(CGPoint)origin
{
CGRect frame = self.frame;
frame.origin = origin;
self.frame = frame;
}
- (CGSize)size
{
return self.frame.size;
}
- (void)setSize:(CGSize)size
{
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
- (CGFloat)top
{
return self.origin.y;
}
- (void)setTop:(CGFloat)top
{
CGRect frame = self.frame;
frame.origin.y = top;
self.frame = frame;
}
- (CGFloat)left
{
return self.origin.x;
}
- (void)setLeft:(CGFloat)left
{
CGRect frame = self.frame;
frame.origin.x = left;
self.frame = frame;
}
- (CGFloat)right
{
return self.left + self.width;
}
- (void)setRight:(CGFloat)right
{
CGRect frame = self.frame;
frame.origin.x = right - frame.size.width;
self.frame = frame;
}
- (CGFloat)bottom
{
return self.top + self.height;
}
- (void)setBottom:(CGFloat)bottom
{
CGRect frame = self.frame;
frame.origin.y = bottom - frame.size.height;
self.frame = frame;
}
- (CGFloat)width
{
return self.size.width;
}
- (void)setWidth:(CGFloat)width
{
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}
- (CGFloat)height
{
return self.size.height;
}
- (void)setHeight:(CGFloat)height
{
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (CGFloat)x
{
return self.center.x;
}
- (void)setX:(CGFloat)x
{
self.center = CGPointMake(x, self.center.y);
}
- (CGFloat)y
{
return self.center.y;
}
- (void)setY:(CGFloat)y
{
self.center = CGPointMake(self.center.x, y);
}
//bounds accessors
- (CGSize)boundsSize
{
return self.bounds.size;
}
- (void)setBoundsSize:(CGSize)size
{
CGRect bounds = self.bounds;
bounds.size = size;
self.bounds = bounds;
}
- (CGFloat)boundsWidth
{
return self.boundsSize.width;
}
- (void)setBoundsWidth:(CGFloat)width
{
CGRect bounds = self.bounds;
bounds.size.width = width;
self.bounds = bounds;
}
- (CGFloat)boundsHeight
{
return self.boundsSize.height;
}
- (void)setBoundsHeight:(CGFloat)height
{
CGRect bounds = self.bounds;
bounds.size.height = height;
self.bounds = bounds;
}
//content getters
- (CGRect)contentBounds
{
return CGRectMake(0.0f, 0.0f, self.boundsWidth, self.boundsHeight);
}
- (CGPoint)contentCenter
{
return CGPointMake(self.boundsWidth/2.0f, self.boundsHeight/2.0f);
}
//additional frame setters
- (void)setLeft:(CGFloat)left right:(CGFloat)right
{
CGRect frame = self.frame;
frame.origin.x = left;
frame.size.width = right - left;
self.frame = frame;
}
- (void)setWidth:(CGFloat)width right:(CGFloat)right
{
CGRect frame = self.frame;
frame.origin.x = right - width;
frame.size.width = width;
self.frame = frame;
}
- (void)setTop:(CGFloat)top bottom:(CGFloat)bottom
{
CGRect frame = self.frame;
frame.origin.y = top;
frame.size.height = bottom - top;
self.frame = frame;
}
- (void)setHeight:(CGFloat)height bottom:(CGFloat)bottom
{
CGRect frame = self.frame;
frame.origin.y = bottom - height;
frame.size.height = height;
self.frame = frame;
}
//animation
- (void)crossfadeWithDuration:(NSTimeInterval)duration
{
//jump through a few hoops to avoid QuartzCore framework dependency
CAAnimation *animation = [NSClassFromString(@"CATransition") animation];
[animation setValue:@"kCATransitionFade" forKey:@"type"];
animation.duration = duration;
[self.layer addAnimation:animation forKey:nil];
}
- (void)crossfadeWithDuration:(NSTimeInterval)duration completion:(void (^)(void))completion
{
[self crossfadeWithDuration:duration];
if (completion)
{
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC));
dispatch_after(time, dispatch_get_main_queue(), completion);
}
}
@end

Просмотреть файл

@ -16,22 +16,26 @@ The easiest way to consume the iOS client library is via CocoaPods. To install v
The sample app demonstrates the use of the Microsoft Face API iOS client library. The sample shows scenarios such as face detection, face verification, and face grouping.
### Requirements
iOS must be version 9.0 or higher.
iOS must be version 8.1 or higher.
### Building and running the sample
The sample app should already have the necessary Pods shipped with it. Open the `ProjectOxfordFace.xcworkspace` in Xcode and build.
1. First, you must obtain a Face API subscription key by [following the instructions on our website](<https://www.microsoft.com/cognitive-services/en-us/sign-up>).
2. Once in Xcode, under the example subdirectory, navigate to the file `MPODemoConstants.h` and insert your subscription key for the Face API
2. Once in Xcode, under the example subdirectory, navigate to the file `MPOAppDelegate.h` and insert your subscription key for the Face API
3. To run the sample app, ensure that the target on top left side of Xcode is selected as `ProjectOxfordFace-Example` and select the play button or select Product > Run on the menu bar
4. Once the app is launched, click on the buttons to try out the different scenarios.
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.
<img src="SampleScreenshots/SampleScreenshot1.png" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot2.png" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot3.png" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot4.png" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot1.jpg" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot2.jpg" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot3.jpg" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot4.jpg" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot5.jpg" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot6.jpg" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot7.jpg" width="30%"/>
<img src="SampleScreenshots/SampleScreenshot8.jpg" width="30%"/>
### Having issues?
@ -39,7 +43,7 @@ Microsoft will receive the images you upload and may use them to improve Face AP
2. Make sure you have included the subscription key in `MPOTestConstants.h`.
3. Make sure you have opened the `.xcworkspace` file and not the `.xcodeproj` file in Xcode.
4. Make sure you have used the correct `Deployment Team` profile.
5. Make sure you are running iOS 9.0 or higher
5. Make sure you are running iOS 8.1 or higher
### Running and exploring the unit tests

Двоичные данные
SampleScreenshots/SampleScreenshot1.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 115 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot1.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 167 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot2.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 58 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot2.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 109 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot3.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 137 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot3.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 949 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot4.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 98 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot4.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.0 MiB

Двоичные данные
SampleScreenshots/SampleScreenshot5.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 122 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot6.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 128 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot7.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 102 KiB

Двоичные данные
SampleScreenshots/SampleScreenshot8.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 73 KiB