1. Detecting facial expressions from images#

Written by Jin Hyun Cheong and Eshin Jolly

In this tutorial we’ll explore the Detector class in more depth, demonstrating how to detect faces, facial landmarks, action units, and emotions from images. You can try it out interactively in Google Collab: Open In Colab

# Uncomment the line below and run this only if you're using Google Collab
# !pip install -q py-feat

1.1 Downloading models from HuggingFace and setting up a Detector#

A Detector is a swiss-army-knife class that “glues” together a combination of pre-trained Face, Emotion, Pose, etc detection models into a single Python object. This allows us to provide a very easy-to-use high-level API, e.g. detector.detect('my_image.jpg',data_type='image'), which will automatically make use of the correct underlying model to solve the sub-tasks of identifying face locations, getting landmarks, extracting action units, etc.

The first time you initialize a Detector instance on your computer will take a moment as Py-Feat will automatically download required pretrained model weights for you from our HuggingFace Repository and save them to disk. Everytime after that it will use existing model weights.

You can find a list of default models on this page.

from feat import Detector

detector = Detector()
detector

# You can change which models you want during initialization, e.g.
# detector = Detector(emotion_model='svm')
/Users/esh/miniconda3/envs/py-feat/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
/Users/esh/miniconda3/envs/py-feat/lib/python3.11/site-packages/kornia/feature/lightglue.py:44: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead.
  @torch.cuda.amp.custom_fwd(cast_inputs=torch.float32)
Detector(face_model=img2pose, landmark_model=mobilefacenet, au_model=xgb, emotion_model=resmasknet, facepose_model=img2pose, identity_model=facenet)

1.2 Processing a single image#

Let’s process a single image with a single face. Py-feat includes a demo image for this purpose called single_face.jpg so lets use that. You can also use the convenient imshow function which will automatically load an image into a numpy array if provided a path unlike matplotlib:

from feat.utils.io import get_test_data_path
from feat.plotting import imshow
import os

# Helper to point to the test data folder
test_data_dir = get_test_data_path()

# Get the full path
single_face_img_path = os.path.join(test_data_dir, "single_face.jpg")

# Plot it
imshow(single_face_img_path)
../_images/cd2590afb69dbcfd5174d9c00c359a19891c3beb2e2cc52e3f1aaec23dc0f92b.png

Now we use our initialized detector instance to make predictions with the detect_image() method. This is the main workhorse method that will perform face, landmark, au, and emotion detection using the loaded models. It always returns a Fex data instance:

single_face_prediction = detector.detect(single_face_img_path, data_type="image")

type(single_face_prediction)  # instace of a Fex class

# Show results
single_face_prediction
  0%|          | 0/1 [00:00<?, ?it/s]
100%|██████████| 1/1 [00:00<00:00,  1.65it/s]
feat.data.Fex
FaceRectX FaceRectY FaceRectWidth FaceRectHeight FaceScore x_0 x_1 x_2 x_3 x_4 ... Identity_508 Identity_509 Identity_510 Identity_511 Identity_512 input frame FrameHeight FrameWidth Identity
0 163.0 131.0 246.0 307.0 0.999693 188.409531 190.76413 193.926575 197.980225 206.38916 ... 0.0302 0.10436 -0.00073 -0.014038 0.044818 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 562.0 572.0 Person_0

1 rows × 691 columns

1.3 Working with Fex outputs#

The output of any detection always returns a Fex data class instance. This class is a lightweight wrapper around a pandas dataframe that contains columns with values for detection type.

So you can use any pandas methods you’re already familiar with:

# We always return a dataframe even if there's just a single row,
# i.e. no Series
single_face_prediction.head()
FaceRectX FaceRectY FaceRectWidth FaceRectHeight FaceScore x_0 x_1 x_2 x_3 x_4 ... Identity_508 Identity_509 Identity_510 Identity_511 Identity_512 input frame FrameHeight FrameWidth Identity
0 163.0 131.0 246.0 307.0 0.999693 188.409531 190.76413 193.926575 197.980225 206.38916 ... 0.0302 0.10436 -0.00073 -0.014038 0.044818 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 562.0 572.0 Person_0

1 rows × 691 columns

Fex provides convenient attributes to access specific groups of columns so you don’t have to write a bunch of pandas code to get the data you need:

single_face_prediction.faceboxes
FaceRectX FaceRectY FaceRectWidth FaceRectHeight FaceScore
0 163.0 131.0 246.0 307.0 0.999693
single_face_prediction.aus
AU01 AU02 AU04 AU05 AU06 AU07 AU09 AU10 AU11 AU12 AU14 AU15 AU17 AU20 AU23 AU24 AU25 AU26 AU28 AU43
0 0.292286 0.352024 0.092464 0.323836 0.859788 1.0 0.375797 0.009637 1.0 0.920121 0.643604 0.056617 0.371272 1.0 0.113789 0.207406 0.996272 0.243547 0.029547 0.645135
single_face_prediction.emotions
anger disgust fear happiness sadness surprise neutral
0 0.000315 0.00002 0.000017 0.992122 0.006474 0.000746 0.000306
single_face_prediction.poses
Pitch Roll Yaw X Y Z
0 0.153656 0.146084 -0.032639 -0.025715 0.136259 8.532812
single_face_prediction.identities
0    Person_0
Name: Identity, dtype: object

1.4 Saving and Loading detections from a file#

Since a Fex object is just a sub-classed DataFrames we can use the .to_csv method to save our detections toa file:

single_face_prediction.to_csv("output.csv", index=False)

To create a new Fex instance from a csv file use our custom read_feat() function instead pf pd.read_csv:

from feat.utils.io import read_feat

input_prediction = read_feat("output.csv")

# We we can quick access features like beofre
input_prediction.aus
AU01 AU02 AU04 AU05 AU06 AU07 AU09 AU10 AU11 AU12 AU14 AU15 AU17 AU20 AU23 AU24 AU25 AU26 AU28 AU43
0 0.292286 0.352024 0.092464 0.323836 0.859788 1.0 0.375797 0.009637 1.0 0.920121 0.643604 0.056617 0.371272 1.0 0.113789 0.207406 0.996272 0.243547 0.029547 0.645135

Real-time saving during detection (low-memory mode)#

You can also write Fex outputs to a file during detection by passing a save argument to detect. This will save the Fex output to a csv file every time a face is detected.

This can be useful when processing multiple images or videos (as we’ll see later).

fex = detector.detect(inputs=single_face_img_path, data_type="image", save='detections.csv')

fex.head()
  0%|          | 0/1 [00:00<?, ?it/s]
100%|██████████| 1/1 [00:00<00:00,  1.80it/s]
FaceRectX FaceRectY FaceRectWidth FaceRectHeight FaceScore x_0 x_1 x_2 x_3 x_4 ... Identity_508 Identity_509 Identity_510 Identity_511 Identity_512 input frame FrameHeight FrameWidth Identity
0 163.0 131.0 246.0 307.0 0.999693 188.40953 190.76413 193.92657 197.98022 206.38916 ... 0.0302 0.10436 -0.00073 -0.014038 0.044818 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 562.0 572.0 Person_0

1 rows × 691 columns

We can use our terminal to see that detections.csv exists and contains the same content as fex

%%bash 
head detections.csv
FaceRectX,FaceRectY,FaceRectWidth,FaceRectHeight,FaceScore,x_0,x_1,x_2,x_3,x_4,x_5,x_6,x_7,x_8,x_9,x_10,x_11,x_12,x_13,x_14,x_15,x_16,x_17,x_18,x_19,x_20,x_21,x_22,x_23,x_24,x_25,x_26,x_27,x_28,x_29,x_30,x_31,x_32,x_33,x_34,x_35,x_36,x_37,x_38,x_39,x_40,x_41,x_42,x_43,x_44,x_45,x_46,x_47,x_48,x_49,x_50,x_51,x_52,x_53,x_54,x_55,x_56,x_57,x_58,x_59,x_60,x_61,x_62,x_63,x_64,x_65,x_66,x_67,y_0,y_1,y_2,y_3,y_4,y_5,y_6,y_7,y_8,y_9,y_10,y_11,y_12,y_13,y_14,y_15,y_16,y_17,y_18,y_19,y_20,y_21,y_22,y_23,y_24,y_25,y_26,y_27,y_28,y_29,y_30,y_31,y_32,y_33,y_34,y_35,y_36,y_37,y_38,y_39,y_40,y_41,y_42,y_43,y_44,y_45,y_46,y_47,y_48,y_49,y_50,y_51,y_52,y_53,y_54,y_55,y_56,y_57,y_58,y_59,y_60,y_61,y_62,y_63,y_64,y_65,y_66,y_67,Pitch,Roll,Yaw,X,Y,Z,AU01,AU02,AU04,AU05,AU06,AU07,AU09,AU10,AU11,AU12,AU14,AU15,AU17,AU20,AU23,AU24,AU25,AU26,AU28,AU43,anger,disgust,fear,happiness,sadness,surprise,neutral,Identity_1,Identity_2,Identity_3,Identity_4,Identity_5,Identity_6,Identity_7,Identity_8,Identity_9,Identity_10,Identity_11,Identity_12,Identity_13,Identity_14,Identity_15,Identity_16,Identity_17,Identity_18,Identity_19,Identity_20,Identity_21,Identity_22,Identity_23,Identity_24,Identity_25,Identity_26,Identity_27,Identity_28,Identity_29,Identity_30,Identity_31,Identity_32,Identity_33,Identity_34,Identity_35,Identity_36,Identity_37,Identity_38,Identity_39,Identity_40,Identity_41,Identity_42,Identity_43,Identity_44,Identity_45,Identity_46,Identity_47,Identity_48,Identity_49,Identity_50,Identity_51,Identity_52,Identity_53,Identity_54,Identity_55,Identity_56,Identity_57,Identity_58,Identity_59,Identity_60,Identity_61,Identity_62,Identity_63,Identity_64,Identity_65,Identity_66,Identity_67,Identity_68,Identity_69,Identity_70,Identity_71,Identity_72,Identity_73,Identity_74,Identity_75,Identity_76,Identity_77,Identity_78,Identity_79,Identity_80,Identity_81,Identity_82,Identity_83,Identity_84,Identity_85,Identity_86,Identity_87,Identity_88,Identity_89,Identity_90,Identity_91,Identity_92,Identity_93,Identity_94,Identity_95,Identity_96,Identity_97,Identity_98,Identity_99,Identity_100,Identity_101,Identity_102,Identity_103,Identity_104,Identity_105,Identity_106,Identity_107,Identity_108,Identity_109,Identity_110,Identity_111,Identity_112,Identity_113,Identity_114,Identity_115,Identity_116,Identity_117,Identity_118,Identity_119,Identity_120,Identity_121,Identity_122,Identity_123,Identity_124,Identity_125,Identity_126,Identity_127,Identity_128,Identity_129,Identity_130,Identity_131,Identity_132,Identity_133,Identity_134,Identity_135,Identity_136,Identity_137,Identity_138,Identity_139,Identity_140,Identity_141,Identity_142,Identity_143,Identity_144,Identity_145,Identity_146,Identity_147,Identity_148,Identity_149,Identity_150,Identity_151,Identity_152,Identity_153,Identity_154,Identity_155,Identity_156,Identity_157,Identity_158,Identity_159,Identity_160,Identity_161,Identity_162,Identity_163,Identity_164,Identity_165,Identity_166,Identity_167,Identity_168,Identity_169,Identity_170,Identity_171,Identity_172,Identity_173,Identity_174,Identity_175,Identity_176,Identity_177,Identity_178,Identity_179,Identity_180,Identity_181,Identity_182,Identity_183,Identity_184,Identity_185,Identity_186,Identity_187,Identity_188,Identity_189,Identity_190,Identity_191,Identity_192,Identity_193,Identity_194,Identity_195,Identity_196,Identity_197,Identity_198,Identity_199,Identity_200,Identity_201,Identity_202,Identity_203,Identity_204,Identity_205,Identity_206,Identity_207,Identity_208,Identity_209,Identity_210,Identity_211,Identity_212,Identity_213,Identity_214,Identity_215,Identity_216,Identity_217,Identity_218,Identity_219,Identity_220,Identity_221,Identity_222,Identity_223,Identity_224,Identity_225,Identity_226,Identity_227,Identity_228,Identity_229,Identity_230,Identity_231,Identity_232,Identity_233,Identity_234,Identity_235,Identity_236,Identity_237,Identity_238,Identity_239,Identity_240,Identity_241,Identity_242,Identity_243,Identity_244,Identity_245,Identity_246,Identity_247,Identity_248,Identity_249,Identity_250,Identity_251,Identity_252,Identity_253,Identity_254,Identity_255,Identity_256,Identity_257,Identity_258,Identity_259,Identity_260,Identity_261,Identity_262,Identity_263,Identity_264,Identity_265,Identity_266,Identity_267,Identity_268,Identity_269,Identity_270,Identity_271,Identity_272,Identity_273,Identity_274,Identity_275,Identity_276,Identity_277,Identity_278,Identity_279,Identity_280,Identity_281,Identity_282,Identity_283,Identity_284,Identity_285,Identity_286,Identity_287,Identity_288,Identity_289,Identity_290,Identity_291,Identity_292,Identity_293,Identity_294,Identity_295,Identity_296,Identity_297,Identity_298,Identity_299,Identity_300,Identity_301,Identity_302,Identity_303,Identity_304,Identity_305,Identity_306,Identity_307,Identity_308,Identity_309,Identity_310,Identity_311,Identity_312,Identity_313,Identity_314,Identity_315,Identity_316,Identity_317,Identity_318,Identity_319,Identity_320,Identity_321,Identity_322,Identity_323,Identity_324,Identity_325,Identity_326,Identity_327,Identity_328,Identity_329,Identity_330,Identity_331,Identity_332,Identity_333,Identity_334,Identity_335,Identity_336,Identity_337,Identity_338,Identity_339,Identity_340,Identity_341,Identity_342,Identity_343,Identity_344,Identity_345,Identity_346,Identity_347,Identity_348,Identity_349,Identity_350,Identity_351,Identity_352,Identity_353,Identity_354,Identity_355,Identity_356,Identity_357,Identity_358,Identity_359,Identity_360,Identity_361,Identity_362,Identity_363,Identity_364,Identity_365,Identity_366,Identity_367,Identity_368,Identity_369,Identity_370,Identity_371,Identity_372,Identity_373,Identity_374,Identity_375,Identity_376,Identity_377,Identity_378,Identity_379,Identity_380,Identity_381,Identity_382,Identity_383,Identity_384,Identity_385,Identity_386,Identity_387,Identity_388,Identity_389,Identity_390,Identity_391,Identity_392,Identity_393,Identity_394,Identity_395,Identity_396,Identity_397,Identity_398,Identity_399,Identity_400,Identity_401,Identity_402,Identity_403,Identity_404,Identity_405,Identity_406,Identity_407,Identity_408,Identity_409,Identity_410,Identity_411,Identity_412,Identity_413,Identity_414,Identity_415,Identity_416,Identity_417,Identity_418,Identity_419,Identity_420,Identity_421,Identity_422,Identity_423,Identity_424,Identity_425,Identity_426,Identity_427,Identity_428,Identity_429,Identity_430,Identity_431,Identity_432,Identity_433,Identity_434,Identity_435,Identity_436,Identity_437,Identity_438,Identity_439,Identity_440,Identity_441,Identity_442,Identity_443,Identity_444,Identity_445,Identity_446,Identity_447,Identity_448,Identity_449,Identity_450,Identity_451,Identity_452,Identity_453,Identity_454,Identity_455,Identity_456,Identity_457,Identity_458,Identity_459,Identity_460,Identity_461,Identity_462,Identity_463,Identity_464,Identity_465,Identity_466,Identity_467,Identity_468,Identity_469,Identity_470,Identity_471,Identity_472,Identity_473,Identity_474,Identity_475,Identity_476,Identity_477,Identity_478,Identity_479,Identity_480,Identity_481,Identity_482,Identity_483,Identity_484,Identity_485,Identity_486,Identity_487,Identity_488,Identity_489,Identity_490,Identity_491,Identity_492,Identity_493,Identity_494,Identity_495,Identity_496,Identity_497,Identity_498,Identity_499,Identity_500,Identity_501,Identity_502,Identity_503,Identity_504,Identity_505,Identity_506,Identity_507,Identity_508,Identity_509,Identity_510,Identity_511,Identity_512,input,frame,FrameHeight,FrameWidth,Identity
163.0,131.0,246.0,307.0,0.99969316,188.40953,190.76413,193.92657,197.98022,206.38916,220.74722,238.36206,256.7828,277.77484,299.8479,320.87454,340.44565,356.25153,365.82883,370.70142,374.08484,376.37054,198.10739,208.38081,222.62196,237.8277,252.49493,283.76196,299.9295,317.01276,333.90036,347.87152,268.09308,267.61554,267.14215,266.80994,249.79395,258.9277,269.23865,280.417,290.94995,217.13168,228.21112,238.38293,248.04413,238.11713,227.94595,295.2691,305.27124,315.88086,327.75458,316.5935,306.00256,236.0275,248.95493,262.61887,272.71973,283.52176,300.15088,317.08646,302.72534,287.20755,274.6589,263.326,249.24263,239.99454,262.97412,273.33585,284.6719,312.88202,285.63177,273.77365,262.81494,244.48196,271.12164,297.76517,324.81076,349.48724,369.27686,384.58582,397.36432,401.75122,397.47537,384.9442,369.73724,349.34174,323.66803,294.62152,265.1725,234.83054,228.96255,217.83733,214.79831,216.87204,222.80917,219.8603,213.42084,210.87857,214.08641,224.20898,242.13986,259.63266,276.0241,292.73285,304.05994,307.85236,310.3473,306.73895,302.58554,247.69589,244.60455,244.59006,249.1573,250.52448,250.23914,247.66129,241.98993,241.72916,244.24142,247.71545,248.65668,329.82343,323.80548,320.6712,322.44998,319.64227,321.34018,326.36212,344.4939,353.8432,355.6458,354.35446,346.15283,330.8362,327.64688,328.63474,326.63684,327.54425,341.89948,343.5869,342.58093,0.15365556,0.14608352,-0.032639463,-0.025714636,0.13625932,8.532812,0.29228646,0.35202417,0.09246446,0.32383558,0.85978776,1.0,0.3757974,0.009636733,1.0,0.92012084,0.6436043,0.056616515,0.37127218,1.0,0.113789074,0.20740561,0.9962717,0.24354655,0.029546617,0.6451348,0.00031503502,1.9805473e-05,1.7192644e-05,0.9921218,0.0064744055,0.00074597733,0.00030572907,-0.016474469,0.010943476,0.012540879,0.061851922,0.06325073,0.058608383,0.012735683,0.0540565,0.032421444,0.0015979311,0.04613706,-0.006903793,0.0038118148,0.023735968,0.004080121,-0.012981681,0.0337065,0.008941093,-0.05526206,-0.039800156,0.0071719647,0.02831355,0.021601634,0.04859631,0.002851353,0.015315047,0.040310893,0.023462288,0.03462724,0.03606105,0.08480601,0.057251737,0.046283107,0.012111813,0.047561545,-0.0094048865,-0.02754141,-0.031991947,-0.011458619,0.018665064,0.01556529,-0.065480635,0.004626003,-0.030373467,-0.004519181,-0.017916244,0.03153709,-0.049230248,0.06470094,-0.013663913,0.015287711,-0.040042996,0.0666054,0.012419964,0.046224996,0.015763229,-0.015650913,-0.07325408,0.03179464,-0.0028809924,-0.03580707,-0.059437275,-0.022919977,0.025374556,0.0077693854,-0.026475063,-0.058671918,-0.0073748976,0.056421097,-0.041895557,-0.015118455,-0.01033595,-0.05796223,-0.008164366,0.046331655,0.08366611,0.03835752,-0.029137922,-0.020086711,0.03285807,0.035578735,-0.035176333,0.013614702,-0.0015192938,0.0782625,0.027681528,0.0036929313,-0.015595403,0.10054135,-0.060929168,-0.0755995,0.013845961,0.020853406,0.054866325,0.04245884,0.013306801,-0.08756025,-0.020370075,0.055481575,0.038704667,0.019288072,0.089725,0.08656697,-0.015778074,0.09101207,0.043920107,-0.0842179,-0.099626884,0.06906759,-0.032333776,-0.010098594,0.08876104,-0.044136576,-0.09358857,-0.05558949,0.041495293,-0.038613446,-0.0069723646,-0.032528315,0.011450543,0.04809019,0.023181824,-0.06674482,-0.019130373,-0.021480557,-0.03243822,0.0348112,-0.08310943,0.09773221,-0.017829346,0.08284359,0.048468348,0.0027276294,0.0290145,0.060102314,0.011632918,-0.026982026,-0.1008148,0.024199096,-0.0042365934,0.0048722434,0.0864499,-0.04040647,-0.03523084,0.018121079,0.05306914,-0.053193655,0.022634692,0.0033886011,-0.013326134,0.005064548,0.0017047133,0.06331552,0.06566757,-0.038076326,0.03195145,-0.048999943,0.0106899515,0.017866557,-0.12617467,-0.050418362,0.058052786,-0.009631532,0.00012795448,0.02645571,-0.04117754,0.0074591585,0.050559368,-0.0069889217,0.0024439734,0.001988363,-0.018898856,-0.029962912,0.051569525,0.0053519863,0.06056651,-0.10390544,-0.008586667,-0.017949691,-0.012180359,0.02515761,0.004157437,0.0015484826,0.00983071,0.040038187,-0.02233528,0.039246295,-0.008055949,-0.03440307,-0.0021564579,-0.020128747,0.07841201,0.005596402,-0.057157826,0.010939164,-0.007827504,-0.011385286,-0.026888747,0.08232488,-0.040208872,0.0024427436,0.011348812,0.14148815,-0.02625484,0.027033517,-0.0023209052,0.01527474,-0.011697312,0.026363559,-0.0062077465,-0.036329407,-0.020469788,-0.010870001,0.0347202,0.0013760913,0.044760562,0.008481366,-0.029125271,-0.029768351,-0.079282984,0.022972738,0.03150368,0.043720573,0.084690206,-0.005296119,-0.056885645,-0.025185969,0.0037654531,0.06344974,-0.011020636,-0.034753397,-0.032403383,-0.031377256,0.028057525,0.0079797525,-0.047590017,-0.023367867,0.041245505,-0.0010293467,0.03879553,-0.023595622,0.02350205,0.022298783,-0.030793274,0.028135605,0.014540241,-0.043063167,-0.05994549,-0.015393493,0.017467773,0.032540184,0.023489978,0.040859394,-0.0051623643,-0.011757172,-0.06055373,0.010123902,-0.005549315,0.020812064,-0.07180071,0.024123961,-0.023309479,0.098254316,-0.010716494,-0.00036670777,-0.0956777,0.012872121,0.055756707,-0.014370248,-0.08852961,0.017256279,0.02115862,0.016682258,0.016904736,0.0079356795,0.020504186,-0.039974067,0.027630247,-0.10302861,0.04460026,0.006781399,0.019196106,-0.038910743,0.053562753,-0.0096376855,0.0062805144,0.035093267,-0.02422915,-0.030092334,-0.016760916,-0.023927176,0.011593526,-0.012128632,-0.037911292,0.018440636,0.053659018,-0.017276218,-0.07988894,0.028071795,0.002199007,0.05566276,0.031877093,-0.017943004,-0.029590223,-0.04005937,-0.047892902,0.0076719034,0.05113467,-0.031574633,-0.018796364,-0.065027684,-0.047453213,0.025294432,-0.030823957,0.0108426185,0.06826333,0.070935816,0.08386498,0.082460284,-0.05328346,-0.031425606,-0.037453767,0.061049074,-0.07401244,0.004260008,0.010612197,-0.021415485,0.03814527,0.07026425,-0.0049082446,0.037441403,0.042973157,0.02151262,-0.0016125245,-0.029215878,0.04819301,-0.006861154,0.03469235,-0.038977176,0.000118440825,0.028943023,-0.06541923,-0.035814043,0.0037717433,0.07885256,-0.027044889,-0.008189959,0.053966045,-0.042787325,-0.074711636,0.047062967,-0.044712834,-0.037927344,-0.062896706,0.10181799,0.021692965,-0.031322412,-0.044074703,-0.08002175,-0.010946418,-0.055637382,-0.022079134,-0.0034495236,0.011248665,0.071475975,0.0016958246,-0.03511956,0.047209047,0.0012538122,0.06414943,0.025804395,-0.014669827,0.01078396,-0.03986344,-0.044051714,-0.033094324,0.0026801242,0.018369086,0.020549607,-0.0324384,-0.10296722,-0.016977975,-0.045358263,-0.027866682,-0.054452155,0.011969174,-0.0018866227,0.019150715,-0.0069170143,-0.016927373,-0.041106798,0.027885774,-0.022949317,-0.0026528083,0.028312925,-0.016724017,0.012679714,0.03601688,0.0632668,-0.06499284,-0.032440215,0.0069198227,0.0577251,0.013945847,0.03925503,0.029305262,-0.004364309,0.011462728,-0.003820251,-0.020037653,0.049300272,-0.06020724,0.019289704,-0.08574553,-0.05210954,0.031652175,0.010210739,-0.09178338,0.018035267,0.03628524,0.10640851,-0.04334012,0.005544706,0.02268188,-0.05876999,0.0028819183,-0.07320293,0.02434673,0.02245895,-0.036380097,-0.017511662,-0.004926708,-0.043883733,0.063587464,0.06745111,-0.09274271,-0.013561763,-0.037861142,-0.025485018,-0.0039560045,-0.07044285,-0.050808974,-0.018857388,-0.020162962,0.028050808,0.014899055,-0.04271194,0.004874084,0.02145925,0.006671764,0.014245377,-0.05625012,0.05317801,0.029268542,0.017990593,0.056550417,-0.10348506,0.010293681,-0.014824742,0.0677875,0.0017507968,0.06665173,0.013286108,0.018289786,-0.019141184,-0.08051572,0.019336367,-0.11074136,-0.034244426,-0.059206635,-0.087763324,-0.067176566,-0.0812001,0.04516663,-0.0016717674,0.06846575,-0.012567481,-0.0412458,0.03348754,-0.030951915,0.08707724,0.026903199,-0.12602216,-0.09201268,-0.040029086,-0.07625816,-0.00866734,0.04635235,-0.062105294,-0.023305481,0.030798053,-0.03810373,0.07282535,0.034783028,0.00664993,0.0023046574,-0.0024633678,-0.012003522,0.025509495,0.006630562,0.06307238,-0.044841655,0.08773387,-0.07649113,0.021024698,-0.021915453,0.029820804,0.030200006,0.104360245,-0.0007303208,-0.014037524,0.04481796,/Users/esh/Documents/pypackages/py-feat/feat/tests/data/single_face.jpg,0,562.0,572.0,Person_0

1.5 Visualizing detection results.#

Fex objects have a method called .plot_detections() to generate a summary figure of detected faces, action units and emotions. It always returns a list of matplotlib figures:

figs = single_face_prediction.plot_detections(poses=True)
../_images/9100cbae53835792ea511c94d509fe635f3e2e6f5c74b49a1a8c7e9bb5555eec.png

By default .plot_detections() will overlay facial lines on top of the input image. However, it’s also possible to visualize a face using Py-Feat’s standardized AU landmark model, which takes the detected AUs and projects them onto a template face. You an control this by change by setting faces='aus' instead of the default faces='landmarks'. For more details about this kind of visualization see the visualizing facial expressions and the creating an AU visualization model tutorials:

figs = single_face_prediction.plot_detections(faces="aus", muscles=True)
../_images/f3dd64267a9921ecb7d193db73bc79cf3d187d205067ed2d50c6e5b9557713bd.png

Interactive Plotting#

You can also use the .iplot_detections() method to generate an interactive plotly figure that lets you interactively enable/disable various detector outputs:

single_face_prediction.iplot_detections(bounding_boxes=True, emotions=True)

1.6 Detecting multiple faces from a single image#

A Detector will automatically find multiple faces in a single image and will create 1 row per detected face in the Fex object it outputs.

Notice how image_prediction is now a Fex instance with 5 rows, one for each detected face. We can confirm this by plotting our detection results like before:

multi_face_image_path = os.path.join(test_data_dir, "multi_face.jpg")
multi_face_prediction = detector.detect(multi_face_image_path, data_type="image")

# Show results
multi_face_prediction
  0%|          | 0/1 [00:00<?, ?it/s]
100%|██████████| 1/1 [00:01<00:00,  1.44s/it]
FaceRectX FaceRectY FaceRectWidth FaceRectHeight FaceScore x_0 x_1 x_2 x_3 x_4 ... Identity_508 Identity_509 Identity_510 Identity_511 Identity_512 input frame FrameHeight FrameWidth Identity
0 663.0 263.0 150.0 180.0 0.998755 683.637024 682.256287 681.580444 682.637024 686.754944 ... -0.030578 0.057009 -0.027664 0.055146 0.074115 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 667.0 1000.0 Person_0
1 512.0 284.0 140.0 172.0 0.997860 532.246399 530.987976 530.478943 531.346313 534.563416 ... 0.020770 0.074040 -0.061894 0.024235 0.058015 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 667.0 1000.0 Person_1
2 290.0 215.0 135.0 160.0 0.991971 311.675385 313.203674 315.590179 319.633240 326.428802 ... -0.065147 -0.021230 -0.057268 -0.008089 0.035251 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 667.0 1000.0 Person_2
3 192.0 35.0 131.0 154.0 0.963654 216.397369 214.710068 213.856934 214.397079 217.525269 ... 0.040147 0.028400 -0.029841 0.040843 -0.055877 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 667.0 1000.0 Person_3
4 413.0 193.0 112.0 134.0 0.903046 435.238007 435.729736 436.857910 439.002228 442.800690 ... 0.042136 0.047004 -0.001307 0.041147 0.046738 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 667.0 1000.0 Person_4

5 rows × 691 columns

figs = multi_face_prediction.plot_detections(add_titles=False)
../_images/fa4f4b76c1ebabe8cef46fd030959294d65ae53b5706286dbe1bc21cbf1a849a.png

1.7 Working with multiple images#

Detector is also flexible enough to process multiple image files if .detect() is passed a list of images. By default images will be processed serially, but you can set batch_size > 1 to process multiple images in a batch and speed up processing. NOTE: All images in a batch must have the same dimensions for batch processing. This is because behind the scenes, Detector is assembling a tensor by stacking images together. You can ask Detector to rescale images by padding and preserving proportions using the output_size in conjunction with batch_size. For example, the following would process a list of images in batches of 5 images at a time resizing each so one axis is 512:

detector.detect(img_list, batch_size=5, output_size=512) # without output_size this would raise an error if image sizes differ!

In the example below we keep things simple, by process both our single and multi-face example serislly by setting batch_size = 1.

Notice how the returned Fex data class instance has 6 rows: 1 for the first face in the first image, and 5 for the faces in the second image:

NOTE: Currently batch processing images gives slightly different AU detection results due to the way that py-feat integrates the underlying models. You can examine the degree of tolerance by checking out the results of test_detection_and_batching_with_diff_img_sizes in our test-suite

img_list = [single_face_img_path, multi_face_image_path]

mixed_prediction = detector.detect(img_list, batch_size=1, data_type="image")
mixed_prediction
  0%|          | 0/2 [00:00<?, ?it/s]
100%|██████████| 2/2 [00:02<00:00,  1.02s/it]
FaceRectX FaceRectY FaceRectWidth FaceRectHeight FaceScore x_0 x_1 x_2 x_3 x_4 ... Identity_508 Identity_509 Identity_510 Identity_511 Identity_512 input frame FrameHeight FrameWidth Identity
0 163.0 131.0 246.0 307.0 0.999693 188.409531 190.764130 193.926575 197.980225 206.389160 ... 0.030200 0.104360 -0.000730 -0.014038 0.044818 /Users/esh/Documents/pypackages/py-feat/feat/t... 0 562.0 572.0 Person_0
1 663.0 263.0 150.0 180.0 0.998755 683.637024 682.256287 681.580444 682.637024 686.754944 ... -0.030578 0.057009 -0.027664 0.055146 0.074115 /Users/esh/Documents/pypackages/py-feat/feat/t... 1 667.0 1000.0 Person_1
2 512.0 284.0 140.0 172.0 0.997860 532.246399 530.987976 530.478943 531.346313 534.563416 ... 0.020770 0.074040 -0.061894 0.024235 0.058015 /Users/esh/Documents/pypackages/py-feat/feat/t... 1 667.0 1000.0 Person_2
3 290.0 215.0 135.0 160.0 0.991971 311.675385 313.203674 315.590179 319.633240 326.428802 ... -0.065147 -0.021230 -0.057268 -0.008089 0.035251 /Users/esh/Documents/pypackages/py-feat/feat/t... 1 667.0 1000.0 Person_3
4 192.0 35.0 131.0 154.0 0.963654 216.397369 214.710068 213.856934 214.397079 217.525269 ... 0.040147 0.028400 -0.029841 0.040843 -0.055877 /Users/esh/Documents/pypackages/py-feat/feat/t... 1 667.0 1000.0 Person_4
5 413.0 193.0 112.0 134.0 0.903046 435.238007 435.729736 436.857910 439.002228 442.800690 ... 0.042136 0.047004 -0.001307 0.041147 0.046738 /Users/esh/Documents/pypackages/py-feat/feat/t... 1 667.0 1000.0 Person_5

6 rows × 691 columns

Calling .plot_detections() will now plot detections for all images the detector was passed:

figs = mixed_prediction.plot_detections()
../_images/7ee709416c355f656571e4e1cebd0eecda8246ef158b3b86e1840226342bde18.png ../_images/7e8ada11ad3242bec4058483e62af0f5bbef8c1632fc671736c1189e4d72a2a9.png

However, it’s easy to use pandas slicing sytax to just grab predictions for the image you want. For example you can use .loc and chain it to .plot_detections():

# Just plot the detection corresponding to the first row in the Fex data
figs = mixed_prediction.loc[0].plot_detections()
../_images/7ee709416c355f656571e4e1cebd0eecda8246ef158b3b86e1840226342bde18.png

Likewise you can use .query() and chain it to .plot_detections(). Fex data classes store each file path in the 'input' column. So we can use regular pandas methods like .unique() to get all the unique images (2 in our case) and pick the second one.

# Choose plot based on image file name
img_name = mixed_prediction["input"].unique()[1]
axes = mixed_prediction.query("input == @img_name").plot_detections()
../_images/7e8ada11ad3242bec4058483e62af0f5bbef8c1632fc671736c1189e4d72a2a9.png