理想の顔に近づくメイク術:dlib & OpenCVで顔の特徴差を分析してみた

beauty

こんばんは、Yuinaです!

今日はSQLをお休みして、Pythonでプログラムを作成します。

ところで、みなさんは「このモデルさんみたいな顔になりたいな」「自分に似合うメイクってどうやって見つけるんだろう?」そんなふうに思ったこと、ありませんか?

メイクって、感覚や流行だけじゃなくて、「自分と理想の顔の“差”」を知ることでグッと精度が上がるんです。

今回は、自分の顔と理想の顔(女優さん・モデルさん・アニメキャラなどでもOK)を画像で比較して、
目や鼻、口、輪郭などの細かなパーツごとの特徴差を数値化しました。

理想の顔に“寄せていく”楽しさを、ぜひ体験してみてください!

よろしくお願いいたします🙏


環境:Google Colab

必要なライブラリ:

  • cv2: OpenCV ライブラリです。画像データの読み込み、処理、表示などに使われます。
  • dlib: 顔検出や顔のパーツ(ランドマーク)の検出に使われるライブラリです。
  • numpy: 数値計算を効率的に行うためのライブラリです。ここでは、ランドマークの座標を数値配列として扱ったり、距離計算などを行ったりするのに使われます。
!pip install opencv-python dlib numpy

必要なファイル:

shape_predictor_68_face_landmarks.dat

これはdlibの顔ランドマーク検出に必要な学習モデルファイルです。

!wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
!bzip2 -d shape_predictor_68_face_landmarks.dat.bz2

画像ファイルの準備します。

self_image_path: あなたの顔写真のファイルパス
ideal_image_path: 理想の顔の写真のファイルパス

self_image_path = "/content/S__40124419.jpg"
ideal_image_path = "/content/S__40124437.jpg"

アップロードが完了したら、ファイル名を確認して次へ進みます。

import cv2
import dlib
import numpy as np

# 顔検出器と68点のランドマークモデル
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

ライブラリの準備と読み込みをしていきます。

get_frontal_face_detector()は顔を検出する関数です。

shape_predictor(...)は、顔の68点ランドマークモデルを読み込んでいます。

def get_landmarks(image_path):
    img = cv2.imread(image_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    faces = detector(gray)

    if len(faces) == 0:
        raise ValueError("顔が見つかりませんでした")

    shape = predictor(gray, faces[0])
    landmarks = np.array([[p.x, p.y] for p in shape.parts()])
    return landmarks


ここでは、ランドマークの取得と特徴量を抽出しています。

まず画像を読み込み、グレースケールに変換します。

続いて、顔を検出し、最初に見つかった顔に対してランドマーク(目、鼻、口、輪郭など68点)を取得します。そして、取得した点をNumPy配列として返却します。

def extract_detailed_features(landmarks):
    features = {}
    features["eye_width_L"] = np.linalg.norm(landmarks[36] - landmarks[39])
    features["eye_width_R"] = np.linalg.norm(landmarks[42] - landmarks[45])
    ...
    return features

ここでは特徴の抽出と差分の計算をしています。

顔の各パーツ(目の横幅・間隔・鼻の長さ・唇の厚み・顔全体の比率など)を定義し、

np.linalg.normで2点間の距離を測定し、特徴として記録します。

ちなみに、landmarks[36]landmarks[39] は、dlibの68点顔ランドマークモデルにおける 特定の顔パーツの座標 を意味します。


このモデルでは、以下は主な番号の意味です:

範囲部位説明
0–16顎ラインあごの左端から右端まで
17–21左眉毛左目の上の眉毛
22–26右眉毛右目の上の眉毛
27–30鼻筋眉間から鼻の先へ
30–35鼻の下部鼻のふくらみ部分
36–41左目6点で囲まれる輪郭
42–47右目同様に6点で囲まれる輪郭
48–59外唇唇の輪郭部分
60–67内唇唇の内側の輪郭

landmarks_self = get_landmarks(self_image_path)
landmarks_ideal = get_landmarks(ideal_image_path)

features_self = extract_detailed_features(landmarks_self)
features_ideal = extract_detailed_features(landmarks_ideal)

for key in features_self:
    diff = features_self[key] - features_ideal[key]
    print(f"{key}: {diff:+.2f}")

自分と理想の顔のランドマークを比較し、各特徴量の差分を出力します。

出力結果を見てみる

以下は私の顔と理想の顔のランドマークを比較した結果です。

それぞれの項目は、私の顔の特徴が理想の顔と比べてどれだけ大きいか(プラスの値)

または小さいか(マイナスの値)の差分を示しています。

🔍 顔の特徴差分:
eye_width_L: +96.17
eye_width_R: +91.66
eye_distance: +155.96
nose_length: +192.96
nose_width: +97.02
nose_bridge_width: +47.98
mouth_width: +169.07
upper_lip_thickness: +28.00
lower_lip_thickness: +37.97
forehead_height: +96.50
brow_length_L: +183.88
brow_length_R: +154.48
brow_gap: +108.98
jaw_width: +410.44
chin_sharpness: +45.51
face_height: +390.80
face_width: +497.58
face_ratio: +0.04

表にまとめてみました。

特徴名説明(何を測っているか)差分がプラスの場合の意味
eye_width_L左目の目尻〜目頭の距離左目が横に広い
eye_width_R右目の目尻〜目頭の距離右目が横に広い
eye_distance左目の目頭〜右目の目頭の距離目の間隔が広い(離れ目寄り)
nose_length鼻の付け根(眉間)〜鼻先の距離鼻が長い
nose_width小鼻の端〜小鼻の端の距離鼻が横に広い(小鼻が張っている)
nose_bridge_width鼻筋の幅(鼻の上部の幅)鼻筋が太い
mouth_width口角〜口角の距離口が大きく見える
upper_lip_thickness上唇の厚さ上唇が厚い
lower_lip_thickness下唇の厚さ下唇が厚い
forehead_height眉間〜額の上部の距離額が広い(生え際が上にある印象)
brow_length_L左眉の長さ左眉が長い
brow_length_R右眉の長さ右眉が長い
brow_gap左右眉の内側間の距離(眉間の広さ)眉間が広い
jaw_width顎(エラ)の横幅顎が広い、エラが張っている印象
chin_sharpness顎の尖り具合顎が丸い、または前に出ている
face_height眉間〜顎先までの顔の高さ顔が長い(面長)
face_width顔の横幅(こめかみ〜こめかみ)顔の横幅が広い(横長)
face_ratio顔の縦横比(face_height ÷ face_width)面長寄り

まとめ

「黄金比」だけに頼らず、自分と理想の“差分”に注目したメイク分析は、結構実用的だと思いました。

“なりたい自分”に近づくためのアプローチとして、ぜひ取り入れてみてください😊

ありがとうございました!

コメント

タイトルとURLをコピーしました