TL;DR

  • 웹캠이나 휴대전화로 브릭을 비추면 F# WebAssembly 기반 웹 앱이 브릭을 인식하고 위치를 기록해 분류 위치를 알려주는 방식임.
  • 카메라를 테이블 위에 약 45도 각도로 설치하고, 안정적인 배경을 사용하며 가능하면 흰색 배경을 선택하는 방식임.
  • 브릭 인식은 Brickognize를 사용하며, 인식된 이미지는 저장되고 인터넷으로 전송됨.
  • 위치 정보를 브라우저에서 관리하고 CSV 가져오기·내보내기로 저장하거나 공유할 수 있음.
  • 이미지 인식 파이프라인 전송과 이미지 저장 외의 기능은 Blazor 없이 브라우저에서 F#, WebAssembly, OpenCVSharp를 통해 실행됨.

레고 브릭 분류기 사용법

  • 레고 브릭 분류기를 사용하려면 웹캠 또는 휴대전화를 테이블이나 다른 평평한 표면 위에 약 45도 각도로 설치해야 하며, 배경은 안정적인 것이 좋고 가능하면 흰색을 권장함.
  • 분류기는 배경을 학습해 브릭과 구분하므로 배경이 비교적 안정적일 때 가장 잘 작동하지만, 손에 든 휴대전화로도 사용할 수 있음.
  • johansivertsen.com/brickbox에 접속한 뒤 브릭을 카메라 화면 안에 놓으면 인식 결과를 확인할 수 있음.
  • 브릭으로 인식된 이미지는 저장되고 인터넷을 통해 전송되므로 개인적인 내용이 담긴 장면은 촬영하지 않아야 함.
  • 인식 결과에 브릭 번호 11127이 표시되며, 온라인에서 해당 번호를 검색해 식별 결과가 맞는지 확인할 수 있음.
  • 브릭 식별에는 Brickognize를 사용하며, Unlocated 표시는 해당 브릭에 아직 위치가 지정되지 않았음을 뜻함.
  • 화면에 브릭 하나만 보이도록 한 뒤 Change location을 눌러 보관 위치를 설정할 수 있으며, 이후 같은 브릭을 인식하면 지정된 위치를 표시함. 예시에서는 Box1을 위치로 입력함.
  • 나머지 두 버튼으로 위치 정보를 CSV 파일로 가져오거나 내보낼 수 있으며, 브라우저를 닫기 전에 데이터를 내보내고 다음 사용 때 다시 가져와야 함.

레고 브릭을 분류하게 된 배경

  • 플라스틱 통 몇 개에 레고 브릭이 수천 개씩 쌓이자, 온라인과 레고 앱에서 조립 설명서를 찾더라도 수많은 브릭 사이에서 필요한 부품을 찾는 일이 거의 불가능하거나 매우 느려짐.
  • 브릭을 정리하면 한동안은 어디에 무엇이 있는지 알 수 있지만, 아이들은 위치를 모를 수 있고 아이들이 정리하면 반대 상황이 생김.
  • 브릭별로 정리된 위치를 저장하고 공유할 수 있는 시스템이 필요해 프로젝트를 시작함.
  • 개인적으로는 Auer의 플라스틱 상자 여러 개를 사용하며, 분류되지 않은 브릭 수천 개를 뒤지지 않아도 되어 조립이 훨씬 즐거워짐.
  • 브릭을 잘 정리해두면 레고 조립 설명서의 그림을 참고해 필요한 브릭을 찾을 수도 있음.

소프트웨어를 만든 이유와 구현 방식

  • 이 프로젝트는 .NET 코드가 WebAssembly(Wasm)에서 실행된다는 점을 직접 탐구하기 위해 시작함.
  • 이전에는 Stocastic Report Generator 포트처럼 로직을 Azure에서 호스팅했지만, 이 앱은 상당한 연산 비용이 들 수 있는 이미지 인식 파이프라인이 필요해 브라우저에서 가능한 작업을 확인하기에 적합했음.
  • 클라우드 비용이 크게 발생할 위험 없이 소프트웨어를 공유하고, 사용자가 프로그램을 내려받아 설치하지 않아도 된다는 점이 매력적이었음.
  • .NET과 Wasm을 검색하면 Blazor가 자주 등장하지만, C#과 HTML을 함께 사용하고 이들 사이의 상호작용을 처리하는 Blazor를 학습 경험으로 선호하지 않아 가능한 한 사용하지 않기로 함.
  • 실행 흐름은 브라우저가 HTML 페이지를 불러오고, 페이지가 JavaScript인 dotnet.js를 불러온 뒤, JavaScript 실행 계층이 F# 코드를 실행할 수 있는 WebAssembly CLR을 시작하는 구조임.
  • F# 코드는 CIL로 변환되고, .NET CLR 가상 머신을 거쳐 WebAssembly로 실행된 뒤 브라우저 안의 또 다른 가상 머신을 통해 클라이언트 기기의 네이티브 명령으로 변환됨.
  • WebAssembly CLR과 브라우저·JavaScript 계층 사이의 명령 전달은 소스 코드의 [JSImport] 및 [JSExport] 특성에 따라 이뤄짐.
  • 프로젝트는 WebAssembly에서 실행되는 OpenCVSharp를 통해 OpenCV를 많이 사용하며, 이 의존성을 컴파일하는 일이 가장 큰 과제였음.
  • Blazor 샘플을 찾은 뒤에야 의존성을 컴파일하는 데 성공함.
  • 현재 브라우저 밖에서 이뤄지는 작업은 이미지를 인식 파이프라인으로 전송하고 이미지를 저장하는 것뿐이며, 나머지는 브라우저에서 실행됨.
  • 이미지 저장은 Brickognize가 언젠가 사라지거나 유료화될 가능성을 우려한 조치임. 그렇게 될 경우 분류된 이미지를 보유하면 이미지 컬렉션을 검색하는 방식으로 전환할 수 있음.
  • 브릭 감지, 이미지 자르기, CSV 가져오기·내보내기, 위치 관리는 Blazor 없이 WebAssembly를 통해 F#에서 실행됨.