타이포그래피와 상호 작용하기 위해 얼굴 모션을 사용하는 방법

게시 됨: 2022-03-10
빠른 요약 ↬ 이 기사에서는 머신 러닝, 가변 글꼴 및 CSS 그리드를 결합하여 근접성, 기울기 및 사용자 얼굴 수에 반응하는 레이아웃을 만드는 방법을 다룹니다.

웹 디자이너는 항상 페이지 콘텐츠의 표현을 개선할 수 있는 새로운 방법을 찾고 있습니다. 때로는 이것이 독창적인 솔루션으로 이어지거나 종종 설계 분야에서 멀리 떨어져 있는 기술과 상호 작용할 수 있습니다. 이 기사에서는 텍스트의 가독성을 향상시키기 위해 기계 학습을 사용하여 사용자 얼굴의 근접성과 같은 것을 감지하는 인공 지능과 타이포그래피를 연결합니다.

우리는 화면과 사용자의 얼굴 사이의 거리 또는 페이지를 읽는 사람들의 양과 같은 일부 정보를 카메라에서 추출하기 위해 Tensorflow로 얼굴 인식을 사용하는 방법을 실험할 것입니다. 그런 다음 타이포그래피를 조정하고 페이지 레이아웃을 조정하기 위해 해당 데이터를 CSS에 전달합니다.

텐서플로우란?

Tensorflow는 기계 학습을 위한 Google의 오픈 소스 플랫폼입니다. 머신 러닝은 이미지, 오디오 트랙, 시계열, 자연 텍스트 및 데이터 일반에서 복잡한 관계와 반복 패턴을 인식하는 방법을 배우는 알고리즘을 연구하는 컴퓨터 과학의 한 분야입니다. 이러한 알고리즘은 입력 데이터를 기반으로 의사 결정을 내리는 데 사용할 수 있는 일종의 스키마인 수학적 모델(훈련된 모델이라고도 함)을 생성합니다. 이 주제에 접근하고 싶다면 Charlie Gerard가 Smashing Mag에서 프론트엔드 개발자를 위한 ML에 대해 썼습니다.

Tensorflow는 AI 개발자, 데이터 과학자, 수학자를 위한 많은 도구를 제공하지만 데이터 분석이 일상적이지 않더라도 당황하지 마십시오! 좋은 소식은 사전 제작된 모델을 사용하는 한 전문가가 아니어도 사용할 수 있다는 것입니다.

Tensorflow 모델은 JavaScript SDK와 함께 웹에서 사용할 수 있습니다.

설정

얼굴 인식 알고리즘을 사용하려면 몇 가지 단계를 따라야 합니다.

  • Tensorflow SDK를 로드합니다.
  • 수학적 모델이 포함된 Facemesh 라이브러리를 로드합니다.
  • 사용자의 카메라에 액세스하여 HTML 비디오 요소로 스트리밍합니다. Facemesh는 비디오 태그의 프레임을 분석하여 얼굴의 존재를 감지합니다.

이 프로젝트에서는 CDN을 통해 Tensorflow를 사용할 것이지만 번들러 방식을 선호하는 경우 NPM에서도 사용할 수 있습니다.

 <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-webgl"></script>

Tensorflow는 자체적으로 트릭을 수행하지 않으므로 ML 프레임워크 위에 구축되고 얼굴 인식을 위해 이미 훈련된 모델을 제공하는 라이브러리인 Facemesh를 추가해야 합니다.

 <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/facemesh"></script>

다음 단계는 훈련된 모델을 로드하고 비디오 스트림에서 얼굴 데이터를 평가할 함수를 정의하기 위해 Facemesh 라이브러리를 설정하는 것입니다.

 // create and place the video const video = document.createElement('video'); document.body.appendChild(video); // setup facemesh const model = await facemesh.load({ backend: 'wasm', maxFaces: 1, }); async function detectFaces() { const faces = await model.estimateFaces(video); console.log(faces); // recursively detect faces requestAnimationFrame(detectFaces); }

이제 비디오 태그를 사용하여 카메라 스트림에 액세스할 수 있는 권한을 사용자에게 요청할 준비가 되었습니다.

 // enable autoplay video.setAttribute('autoplay', ''); video.setAttribute('muted', ''); video.setAttribute('playsinline', ''); // start face detection when ready video.addEventListener('canplaythrough', detectFaces); // stream the camera video.srcObject = await navigator.mediaDevices.getUserMedia({ audio: false, video: { facingMode: 'user', }, }); // let's go! video.play();

navigator.mediaDevices.getUserMedia 메서드는 권한을 요청하고 카메라를 비디오 요소로 스트리밍하기 시작합니다. 수락되면 카메라는 비디오 태그로 스트리밍하기 시작하고 브라우저 콘솔은 Facemesh에서 감지한 얼굴 정보를 기록합니다.

카메라 권한에는 보안 https 연결 또는 localhost가 필요합니다. 단순히 index.html 파일을 열 수는 없습니다. Node에 대한 로컬 서버 체크아웃 http-server를 설정하는 방법을 잘 모르거나 Python의 경우 이 가이드를 따르거나 PHP의 경우 이 가이드를 따르세요.

점프 후 더! 아래에서 계속 읽기 ↓

사례 1. 스마트폰 카메라를 사용하여 타이포그래피 조정

우리는 스마트폰으로 어디서나 웹을 탐색합니다. 얼마 전까지만 해도 붐비는 기차나 버스를 탈 때 자리가 없어서 스마트폰을 눈 가까이에 두던 때가 있었습니다. 우리는 하루 중 많은 순간과 장소에서 같은 사이트를 보고 있어도 스마트폰의 위치와 기울기를 자주 변경합니다. 눈과 스마트폰 사이의 거리는 우리의 읽기 능력에 영향을 미칩니다. 그 거리를 평가하면 더 가깝거나 더 먼 읽기를 위해 글리프를 최적화하기 위해 마이크로 타이포그래피를 조정할 수 있습니다.

얼굴 감지는 물론 눈 위치 감지도 의미합니다. Facemesh에서 제공하는 데이터를 사용하여 카메라에 캡처된 전체 사진과 관련하여 얼굴 크기를 계산할 수 있습니다. 얼굴이 클수록 화면에 더 가깝다고 가정할 수 있습니다. 우리는 0(한 팔 떨어져 - 얼굴이 카메라의 약 절반을 차지함)에서 1(화면에 붙임)까지 스케일을 설정하고 세그먼트 분할로 현재 값을 감지할 수 있습니다.

 async function detectFaces() { const faces = await model.estimateFaces(video); if (faces.length === 0) { // is somebody out there? return requestAnimationFrame(detectFaces); } const [face] = faces; // extract face surface corners let { bottomRight, topLeft} = face.boundingBox; // calculate face surface size let width = bottomRight[0] - topLeft[0]; let height = bottomRight[1] - topLeft[1]; let videoWidth = video.videoWidth; let videoHeight = video.videoHeight; let adjustWidth = videoWidth / 2; let adjustHeight = videoHeight / 2; // detect the ratio between face and full camera picture let widthRatio = Math.max(Math.min((width - adjustWidth) / (videoWidth - adjustWidth), 1), 0); let heightRatio = Math.max(Math.min((height - adjustHeight) / (videoHeight - adjustHeight), 1), 0); let ratio = Math.max(widthRatio, heightRatio); // recursively detect faces requestAnimationFrame(detectFaces); }
사용자의 얼굴을 세그먼트로 표현한 것은 스마트폰 프레임 내부에 배치되어 화면에서 얼굴이 차지하는 면적을 나타냅니다.
눈, 코, 입의 위치와 기울기와 같이 Facemesh에서 감지한 특성의 두 가지 예. 포인트 사이의 면적을 사용하여 스마트폰 카메라와의 근접도를 계산할 수 있습니다. (큰 미리보기)

ratio 을 계산했으므로 이제 스타일시트에 값을 전달하여 마법을 일으킬 시간입니다.

 document.documentElement.style.setProperty('--user-distance', ratio);

이 값과 약간의 계산을 통해 글꼴 두께, 크기 및 스타일에도 약간의 변경을 쉽게 적용할 수 있지만 훨씬 더 나은 작업을 수행할 수 있습니다. 글리프의 모양과 공간을 매개변수화한 글꼴인 가변 글꼴을 사용하여 광학적 크기 변화를 업데이트하여 모든 글리프의 인식을 조정할 수 있습니다.

모든 가변 글꼴은 광학적 크기 값에 대해 자체 스케일을 사용하기 때문에 비율 값을 해당 스케일과 연관시켜야 합니다. 또한 약간의 향상을 제공하기 위해 사용 가능한 광학 크기의 하위 집합 사이를 이동할 수 있습니다.

 .main-text { --min-opsz: 10; --max-opsz: 15; --opsz: calc(var(--min-opsz) + (var(--user-distance) * (var(--max-opsz) - var(--min-opsz)))); ... font-family: 'Amstelvar', serif; font-variation-settings: 'opsz' var(--opsz); }

여기에서 라이브로 볼 수 있습니다. 이 예는 기술이 작동하는 방식을 보여주는 예시일 뿐입니다. 실제로 더 나은 독자 경험을 제공하려면 인쇄상의 변화가 사용자의 눈에 거의 감지되지 않아야 합니다. 여기서는 글리프 모양을 활용했지만 색상을 사용하여 대비를 높이거나 낮추는 것도 시도해 볼 수 있는 또 다른 좋은 솔루션입니다. 또 다른 실험은 읽기의 원근을 계산하기 위해 얼굴의 각도를 감지하고, 어센더, 디센더 및 문자 높이를 수정하는 것이었습니다.

Edoardo Cavazza의 펜 [Facemesh 및 상승/하강](https://codepen.io/smashingmag/pen/oNxrYop)을 참조하십시오.

Edoardo Cavazza의 Pen Facemesh 및 어센더/디센더를 참조하십시오.

사례 #2: 보는 사람의 수가 변경될 때 레이아웃 조정

이 두 번째 경우에는 화면을 보는 사람의 수에 따라 레이아웃을 변경합니다. 우리는 고등학교 교실의 맥락에서 대화형 화이트보드에 표시되는 에세이를 상상할 수 있습니다. 이 시나리오는 시청하는 학생 수가 10명보다 적거나 많을 경우 페이지 레이아웃을 조정하기를 원하기 때문에 사용되지 않는 프로젝션 미디어 쿼리에서 감지한 것과 조용히 다릅니다. 칠판에 안전하게 접근할 수 있지만 전체 교실이 있는 경우 공간이 충분하지 않을 수 있으며 더 적은(그리고 더 큰) 항목을 표시하도록 레이아웃을 변경해야 합니다.

화이트보드를 보고 있는 얼굴의 수를 올바르게 감지하려면 이전 스크립트를 약간만 변경하면 됩니다. 먼저 Facemesh에 여러 얼굴을 감지하도록 지시해야 합니다.

 const model = await facemesh.load({ backend: 'wasm', maxFaces: 30, });

그런 다음 해당 번호를 스타일시트에 전달해야 합니다.

 async function detectFaces() { const faces = await model.estimateFaces(video); document.documentElement.style.setProperty('--watching', faces.length); // recursively detect faces requestAnimationFrame(detectFace); }

다시 말하지만, 이 값을 사용하여 단순히 글꼴 크기를 늘릴 수 있지만 우리의 목표는 완전히 다른 레이아웃을 제공하는 것입니다. CSS 그리드 레이아웃은 이 임무를 수행하는 데 도움이 될 수 있습니다. 이 투사 문서는 관련 이미지가 포함된 긴 형식입니다.

 <section> <article> <h1>...</h1> <h2>...</h2> <p>...</p> </article> <aside> <img src="..." alt="..." /> </aside> </section>

기본 레이아웃은 다음과 같습니다.

 section { display: grid; grid-template-columns: repeat(12, 1fr); grid-column-gap: 1em; width: 120ch; max-width: 100%; padding: 1em; } section article { grid-column: 1 / -5; } section aside { grid-column: 7 / -1; }
왼쪽: 10명 이상 시청 시 사용 가능한 모든 열을 사용하여 본문의 우선 순위를 지정하고 텍스트 뒤에 이미지를 이동합니다. 오른쪽: 활성 Firefox 그리드 검사기 가이드가 있는 12개 열을 사용하는 페이지 레이아웃. 12개 열은 모두 본문에 사용되고 4개 열은 그 다음 이미지에 사용됩니다.
왼쪽 : 페이지의 기본 레이아웃은 긴 형식의 텍스트에 대해 12개 열 중 8개 열을 사용하고 이미지에 나머지 4개 열을 사용합니다. 오른쪽 : 10명 이상 시청 시, 사용 가능한 모든 열을 사용하여 본문의 우선 순위를 지정하고 텍스트 뒤에 이미지를 이동합니다. (큰 미리보기)

많은 사람들이 시청할 때 긴 형식의 읽기 컨텍스트에 권한을 부여하여 기본 열에 더 많은 공간을 제공하고 글꼴 크기를 늘리고 방해 요소를 제거해야 합니다. 그렇게 하기 위해 스팬 열의 수를 늘리고 본문 아래로 옆으로 이동합니다.

 :root { --watching: 10; } section { /** The maximum number of people watching for the default layout */ --switch: 10; /** The default number of columns for the text */ --text: 8; /** The default number of columns for the aside */ --aside: 4; grid-template-columns: repeat(calc(var(--text) + var(--aside)), 1fr); } section article { /** * Kinda magic calculation. * When the number of people watching is lower than --switch, it returns -2 * When the number of people watching is greater than --switch, it returns -1 * We are going to use this number for negative span calculation */ --layout: calc(min(2, (max(var(--switch), var(--watching)) - var(--switch) + 1)) - 3); /** * Calculate the position of the end column. * When --layout is -1, the calculation just returns -1 * When --layout is -2, the calculation is lower than -1 */ --layout-span: calc((var(--aside) * var(--layout)) + var(--aside) - 1); /** * Calculate the maximum index of the last column (the one "before" the aside) */ --max-span: calc(-1 * var(--aside) - 1); /** * get the max between --layout-span and the latest column index. * -1 means full width * --max-span means default layout */ --span: max(var(--max-span), var(--span)); grid-column-start: 1; grid-column-end: var(--span); }
  • 여기에서 라이브로 볼 수 있습니다 →

반대로, 소규모 그룹의 학생이 칠판 근처에서 텍스트를 경험할 때 미디어 파일 및 대화형 작업 트리거와 같은 더 자세한 정보를 제공할 수 있습니다.

얼굴 인식 너머

우리가 직면한 () 사례는 레이아웃 또는 인쇄 범위에 얼굴 인식 기술을 사용하는 방법의 두 가지 예일 뿐입니다. Tensorflow는 카메라 스트림을 페이지의 변수로 변환할 수 있는 다른 모델과 라이브러리를 제공합니다. 또한 스마트폰에는 GPS, 가속도계, 주변광 등 Sensor API를 사용하여 악용할 수 있는 다른 센서가 많이 있다는 사실을 잊어서는 안 됩니다.

기분은 정보를 읽고, 연구하고, 검색하는 방식에 영향을 미치므로 머신 러닝을 통해 사용자의 표정을 분석하여 사용자의 정신에 따라 최소 레이아웃에서 세부 레이아웃으로 전환할 수도 있습니다.

수년 동안 우리는 반응형 웹 디자인을 위해 CSS 미디어 쿼리를 사용하는 데 익숙했습니다. 그러나 뷰포트의 크기는 사용자 경험의 변수 중 하나일 뿐입니다. 최근에, 사용자 선호도를 존중하도록 설계된 새로운 종류의 미디어 쿼리가 prefers-color-schemeprefers-reduced-motion 과 같은 브라우저에 등장했습니다. 이를 통해 디자이너와 개발자는 웹 디자인 관행에서 한 단계 더 나아가 웹 페이지가 사용자의 장치가 아닌 전체 환경에 적응할 수 있습니다. 빅 데이터 시대에 우리는 반응형 및 적응형 디자인을 넘어선 기회가 있습니다. 우리 웹 페이지는 마침내 "화면을 떠나" 사용자의 글로벌 경험의 일부가 될 수 있습니다. 인터랙션 디자인은 이러한 모든 가능성을 포함할 것이므로 기술과 웹 디자인 간의 가능한 조합을 계속 실험하는 것이 향후 몇 년 동안 매우 중요할 것입니다.