مرورگرهای وب روز به روز قدرت بیشتری می گیرند. وب سایت ها و برنامه های وب نیز در حال افزایش پیچیدگی هستند. عملیاتی که چند دهه پیش به یک ابر رایانه احتیاج داشت ، هم اکنون با یک تلفن هوشمند اجرا می شود. یکی از آن موارد تشخیص چهره است.

توانایی تشخیص و تجزیه و تحلیل چهره بسیار مفید است ، زیرا به ما امکان می دهد ویژگی های هوشمندانه ای اضافه کنیم. به صورت خودکار تار شدن چهره ها (مانند Google Maps) ، تغییر مکان و مقیاس بندی یک فید وب وب برای تمرکز بر روی افراد (مانند Microsoft Teams) ، تأیید اعتبار گذرنامه ، افزودن فیلترهای احمقانه (مانند اینستاگرام و Snapchat) و موارد دیگر فکر کنید. اما قبل از اینکه همه این کارها را انجام دهیم ، ابتدا باید چهره را پیدا کنیم!

Face-api.js کتابخانه ای است که توسعه دهندگان را قادر می سازد از تشخیص چهره در برنامه های خود بدون نیاز به سابقه یادگیری ماشین استفاده کنند.

کد این آموزش در دسترس است GitHub.

تشخیص چهره با یادگیری ماشینی

تشخیص اشیا، ، مانند صورت کاملاً پیچیده است. به این فکر کنید: شاید بتوانیم برنامه ای بنویسیم که پیکسل ها را اسکن کند تا چشم ها ، بینی و دهان را پیدا کند. می توان این کار را انجام داد ، اما کاملاً قابل اعتماد بودن ، با توجه به فاکتورهای زیادی که در نظر گرفته می شود ، عملاً غیرممکن است. به شرایط نوری ، موهای صورت ، تنوع گسترده ای از اشکال و رنگ ها ، آرایش ، زاویه ، ماسک های صورت و موارد دیگر فکر کنید.

با این وجود شبکه های عصبی در این نوع مشکلات سرآمد هستند و می توانند به گونه ای تعمیم داده شوند که بیشتر (اگر نگوییم همه) شرایط را در نظر بگیرند. ما می توانیم با استفاده از TensorFlow.js ، کتابخانه معروف یادگیری ماشین JavaScript ، شبکه های عصبی را در مرورگر ایجاد ، آموزش و استفاده کنیم. با این حال ، حتی اگر ما از یک مدل خارج از قفسه و آموزش دیده استفاده کنیم ، باز هم باید کمی در مورد تأمین اطلاعات به TensorFlow و تفسیر خروجی رنج ببریم. اگر به جزئیات فنی یادگیری ماشین علاقه مند هستید ، “مقدمه یادگیری ماشین با پایتون” را ببینید.

face-api.js را وارد کنید. همه اینها را در یک API بصری قرار می دهد. ما می توانیم عبور کنیم img، canvas، یا video عنصر DOM و کتابخانه یک یا مجموعه ای از نتایج را برمی گردانند. Face-api.js می تواند چهره ها را تشخیص دهد ، اما موارد مختلفی را نیز در آنها تخمین می زند ، همانطور که در زیر ذکر شده است.

  • شناسایی چهره: مرزهای یک یا چند چهره را بدست آورید. این برای تعیین اینکه کجا و چه اندازه چهره ها در یک عکس بزرگ هستند مفید است.
  • تشخیص نقطه علامت چهره: حالت و فرم ابروها ، چشم ها ، بینی ، دهان و لب ها و چانه را بدست آورید. این می تواند برای تعیین جهت رو به رو یا برای ایجاد گرافیک در مناطق خاص مانند سبیل بین بینی و لب ها استفاده شود.
  • تشخیص چهره: مشخص کنید چه کسی در تصویر است.
  • تشخیص بیان چهره: بیان را از صورت بگیرید. توجه داشته باشید که مسافت پیموده شده ممکن است در فرهنگ های مختلف متفاوت باشد.
  • تشخیص سن و جنسیت: سن و جنسیت را از یک چهره بگیرید. توجه داشته باشید که برای طبقه بندی “جنسیت” ، این یک چهره را زنانه یا مردانه طبقه بندی می کند ، که لزوما جنسیت آنها را نشان نمی دهد.

قبل از استفاده از هر یک از این موارد فراتر از آزمایش ، لطفا توجه داشته باشید که هوش مصنوعی در تقویت تعصبات بسیار عالی است. طبقه بندی جنسیتی برای افراد مستند خوب کار می کند ، اما نمی تواند جنسیت دوستان غیربایناری من را تشخیص دهد. این سفید پوستان را بیشتر اوقات شناسایی می کند اما اغلب افراد رنگی را تشخیص نمی دهد.

در مورد استفاده از این فناوری بسیار متفکر باشید و کاملاً با یک گروه آزمایش متنوع آزمایش کنید.

نصب و راه اندازی

ما می توانیم face-api.js را از طریق npm نصب کنیم:

npm install face-api.js

با این حال ، برای پرش از تنظیم ابزارهای ساخت ، بسته UMD را از طریق unpkg.org اضافه می کنم:


import 'https://unpkg.com/face-api.js@0.22.2/dist/face-api.min.js';

پس از آن ، باید صحیح را بارگیری کنیم مدل (های) آموزش دیده از مخزن کتابخانه. آنچه را می خواهیم از چهره بدانیم مشخص کنید و از آن استفاده کنید بخش مدلهای موجود برای تعیین مدل های مورد نیاز برخی از ویژگی ها با چندین مدل کار می کنند. در این صورت ، ما باید بین پهنای باند / عملکرد و دقت یکی را انتخاب کنیم. اندازه پرونده مدلهای مختلف موجود را مقایسه کنید و هر کدام را که برای پروژه شما بهتر است انتخاب کنید.

مطمئن نیستید برای استفاده خود به کدام مدل نیاز دارید؟ بعداً می توانید به این مرحله بازگردید. هنگامی که ما از API بدون بارگذاری مدل های مورد نیاز استفاده می کنیم ، خطایی نشان داده می شود که کتابخانه منتظر کدام مدل است.

پیام خطای کنسول

اکنون آماده استفاده هستیم face-api.js API.

مثال ها

بیایید چند چیز بسازیم!

برای مثال های زیر ، یک تصویر تصادفی از آن بارگیری می کنم منبع Unsplash با این عملکرد:

function loadRandomImage() {
  const image = new Image();

  image.crossOrigin = true;

  return new Promise((resolve, reject) => {
    image.addEventListener('error', (error) => reject(error));
    image.addEventListener('load', () => resolve(image));
    image.src = 'https://source.unsplash.com/512x512/?face,friends';
  });
}

برش یک عکس

می توانید کد مربوط به این نسخه ی نمایشی را در آن همراه بیابید repo GitHub.

ابتدا باید مدل را انتخاب و بارگذاری کنیم. برای برش یک تصویر ، فقط باید جعبه مرز یک چهره را بدانیم ، بنابراین تشخیص چهره کافی است. برای این کار می توانیم از دو مدل استفاده کنیم: مدل SSD Mobilenet v1 (کمی کمتر از 6 مگابایت) و مدل ردیاب چهره کوچک (زیر 200 کیلوبایت). بگذارید بگوییم دقت و صحت خارجی است زیرا کاربران همچنین می توانند دستی برش بزنند. بعلاوه ، فرض کنید بازدیدکنندگان از این ویژگی در اتصال به اینترنت کند استفاده می کنند. از آنجا که تمرکز ما روی پهنای باند و عملکرد است ، مدل کوچکتر Tiny Face Detector را انتخاب خواهیم کرد.

پس از بارگیری مدل ، می توانیم آن را بارگیری کنیم:

await faceapi.nets.tinyFaceDetector.loadFromUri('/models');

اکنون می توانیم یک تصویر را بارگیری کرده و به face-api.js منتقل کنیم. faceapi.detectAllFaces به طور پیش فرض از مدل SSD Mobilenet v1 استفاده می کند ، بنابراین ما باید صریحاً تصویب کنیم new faceapi.TinyFaceDetectorOptions() تا آن را مجبور به استفاده از مدل Tiny Face Detector کند.

const image = await loadRandomImage();
const faces = await faceapi.detectAllFaces(image, new faceapi.TinyFaceDetectorOptions());

متغیر faces اکنون شامل یک آرایه از نتایج است. هر نتیجه دارای یک است box و score ویژگی. نمره نشان می دهد که شبکه عصبی تا چه اندازه مطمئن است که نتیجه در واقع چهره است. box ویژگی شامل یک شی با مختصات صورت است. ما می توانیم اولین نتیجه را انتخاب کنیم (یا می توانیم استفاده کنیم faceapi.detectSingleFace()) ، اما اگر کاربر عکس گروهی ارسال کند ، می خواهیم همه آنها را در تصویر بریده شده مشاهده کنیم. برای انجام این کار ، می توانیم یک کادر مرزی سفارشی محاسبه کنیم:

const box = {
  
  bottom: -Infinity,
  left: Infinity,
  right: -Infinity,
  top: Infinity,

  
  get height() {
    return this.bottom - this.top;
  },

  get width() {
    return this.right - this.left;
  },
};


for (const face of faces) {
  box.bottom = Math.max(box.bottom, face.box.bottom);
  box.left = Math.min(box.left, face.box.left);
  box.right = Math.max(box.right, face.box.right);
  box.top = Math.min(box.top, face.box.top);
}

سرانجام ، ما می توانیم یک بوم ایجاد کنیم و نتیجه را نشان دهیم:

const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');

canvas.height = box.height;
canvas.width = box.width;

context.drawImage(
  image,
  box.left,
  box.top,
  box.width,
  box.height,
  0,
  0,
  canvas.width,
  canvas.height
);

قرار دادن شکلک ها

می توانید کد مربوط به این نسخه ی نمایشی را در آن همراه بیابید repo GitHub.

چرا کمی سرگرم نمی شود؟ ما می توانیم یک فیلتر درست کنیم که یک شکلک دهانی (👄) بر روی همه چشم ها قرار دهد. برای یافتن نشانه های چشم ، به مدل دیگری نیاز داریم. این بار ، ما به دقت اهمیت می دهیم ، بنابراین از مدل های SSD Mobilenet v1 و 68 Point Face Landmark Detection استفاده می کنیم.

باز هم ، ابتدا باید مدل ها و تصویر را بارگیری کنیم:

await faceapi.nets.faceLandmark68Net.loadFromUri('/models');
await faceapi.nets.ssdMobilenetv1.loadFromUri('/models');

const image = await loadRandomImage();

برای بدست آوردن نشانه ها ، باید موارد را ضمیمه کنیم withFaceLandmarks() فراخوانی عملکرد به detectAllFaces() برای دریافت اطلاعات مهم:

const faces = await faceapi
  .detectAllFaces(image)
  .withlandmarks();

مثل دفعه آخر، faces شامل لیستی از نتایج است. علاوه بر مکان صورت ، هر نتیجه حاوی یک لیست خام از نقاط برای نشانه ها است. برای به دست آوردن نشانه های مناسب در هر ویژگی ، باید لیست نقاط را برش دهیم. از آنجا که تعداد امتیازات ثابت است ، من انتخاب کردم که کدها را به سختی کد کنم:

for (const face of faces) {
  const features = {
    jaw: face.landmarks.positions.slice(0, 17),
    eyebrowLeft: face.landmarks.positions.slice(17, 22),
    eyebrowRight: face.landmarks.positions.slice(22, 27),
    noseBridge: face.landmarks.positions.slice(27, 31),
    nose: face.landmarks.positions.slice(31, 36),
    eyeLeft: face.landmarks.positions.slice(36, 42),
    eyeRight: face.landmarks.positions.slice(42, 48),
    lipOuter: face.landmarks.positions.slice(48, 60),
    lipInner: face.landmarks.positions.slice(60),
  };

  
}

حالا سرانجام می توانیم کمی لذت ببریم. گزینه های زیادی وجود دارد ، اما اجازه دهید چشم ها را با شکلک دهان بپوشانیم ().

ابتدا باید تعیین کنیم که شکلک را کجا قرار دهیم و چه اندازه باید ترسیم شود. برای انجام این کار ، بیایید یک تابع کمکی بنویسیم که یک جعبه از مجموعه ای دلخواه از نقاط ایجاد می کند. در این جعبه تمام اطلاعات مورد نیاز ما نگهداری می شود:

function getBoxFromPoints(points) {
  const box = {
    bottom: -Infinity,
    left: Infinity,
    right: -Infinity,
    top: Infinity,

    get center() {
      return {
        x: this.left + this.width / 2,
        y: this.top + this.height / 2,
      };
    },

    get height() {
      return this.bottom - this.top;
    },

    get width() {
      return this.right - this.left;
    },
  };

  for (const point of points) {
    box.left = Math.min(box.left, point.x);
    box.right = Math.max(box.right, point.x);

    box.bottom = Math.max(box.bottom, point.y);
    box.top = Math.min(box.top, point.y);
  }

  return box;
}

اکنون می توانیم emoji ها را روی تصویر ترسیم کنیم. از آنجا که ما باید این کار را برای هر دو چشم انجام دهیم ، می توانیم قرار دهیم feature.eyeLeft و feature.eyeRight در یک آرایه قرار دهید و روی آنها تکرار کنید تا کد یکسانی برای هر چشم اجرا شود. تنها چیزی که می ماند کشیدن شکلک ها روی بوم است!

for (const eye of [features.eyeLeft, features.eyeRight]) {
  const eyeBox = getBoxFromPoints(eye);
  const fontSize = 6 * eyeBox.height;

  context.font = `${fontSize}px/${fontSize}px serif`;
  context.textAlign = 'center';
  context.textBaseline = 'bottom';

  context.fillStyle = '#000';
  context.fillText('👄', eyeBox.center.x, eyeBox.center.y + 0.6 * fontSize);
}

توجه داشته باشید که من از چند عدد جادویی برای تغییر اندازه قلم و موقعیت دقیق متن استفاده کردم. از آنجا که شکلک ها یونیکد هستند و تایپوگرافی در وب عجیب است (حداقل برای من) ، من فقط اعداد را تغییر می دهم تا درست ظاهر شوند. یک گزینه قوی تر می تواند استفاده از یک تصویر به عنوان یک پوشش باشد.

شش نفر با ایموجی دهان به عنوان چشم

نتیجه گیری

Face-api.js یک کتابخانه عالی است که تشخیص و تشخیص چهره را واقعاً قابل دسترسی می کند. آشنایی با یادگیری ماشین و شبکه های عصبی لازم نیست. من عاشق ابزاری هستم که قادر باشد و این یکی از آنهاست.

از نظر من ، شناسایی چهره در وب باعث آسیب به عملکرد می شود. ما باید بین پهنای باند و عملکرد یا دقت یکی را انتخاب کنیم. مدل های کوچکتر قطعاً دقت کمتری دارند و در برخی از عواملی که قبلاً ذکر کردم ، مانند روشنایی ضعیف یا پوشیده شدن صورت با ماسک ، چهره را از دست می دهند.

Microsoft Azure ، Google Cloud و احتمالاً مشاغل دیگر امکان شناسایی چهره در فضای ابری را دارند. از آنجا که از بارگیری مدل های بزرگ خودداری می کنیم ، تشخیص مبتنی بر ابر از بارگذاری زیاد صفحه جلوگیری می کند ، به دلیل اینکه مرتباً بهبود می یابد ، دقیق تر می شود و حتی به دلیل سخت افزار بهینه شده ممکن است سریعتر باشد. اگر به دقت بالایی نیاز دارید ، ممکن است بخواهید طرحی را انتخاب کنید که راحت باشید.

من قطعاً توصیه می کنم برای پروژه های سرگرمی ، آزمایشات و شاید برای یک MVP با face-api.js بازی کنید.