NOMO.asia

웹브라우저 client 단에서 NSFW(Not Safe For Work) 또는 누드 이미지를 감지할 수 있는 두가지 자바스크립트 라이브러리에 대해 정리해보았다. 이러한 것을 조사한 개인적인 이유는 채팅에 올라오는 이미지의 NSFW 여부를 판별하여 자동으로 노출/숨김 처리를 할 수 있는 브라우저 확장기능의 개발을 위해서이다.

nude.js

이미지(또는 비디오)에 사람의 피부색에 해당하는 픽셀 영역을 분석하여 누드 이미지인지를 판별한다.

위 라이브러리는 2005년에 발표된 논문을 기반으로 만들어졌는데, 논문에서 주장하는 탐지율은 92%, 오탐지율은 9% 이다. 하지만 해당 논문에 나와있는 모든 알고리즘이 위 라이브러리에 적용되어 있지는 않아서 라이브러리 자체의 탐지율은 60% 수준이라고 한다.

장단점

장점

  1. 빠르다.
  2. 간단하다.

단점

  1. 부정확하다. 주로 판단하는 것은 픽셀의 색깔이기 때문에, 단순히 신체의 일부분이 클로즈업 된 사진이나 피부색과 비슷한 모래 사진 등도 누드 이미지로 판별하는 경우가 있다.

알고리즘

라이브러리는 이미지 또는 비디오를 html5 canvas 로 변환하여 canvas 의 getImageData 함수를 이용해 픽셀 데이터를 가져온 후, 이를 분석하여 피부톤 이미지인지를 판별한다. 직접 사용해보니 이미지 크기가 수천px * 수천px 정도로 많이 큰 경우 계산에 꽤 오랜 시간이 걸리므로 적절히 리사이즈 해주는 것이 중요했다.

라이브러리에 적용된 누드(피부톤) 이미지 분류 알고리즘은 아래와 같다.

  1. 이미지를 분석하여 피부색에 해당하는 픽셀을 찾고, 찾은 픽셀들이 연결된 각각의 영역을 구분한다.
  2. 찾은 피부톤 영역 중 픽셀이 연결된 가장 큰 3개의 영역을 찾는다.
  3. 아래의 알고리즘을 따라 누드 이미지인지 판단한다.
    1. 피부색에 해당하는 픽셀이 차지하는 비율이 이미지 전체 픽셀의 15% 미만인 경우 이미지는 누드가 아니다.
    2. 가장 큰 피부 영역의 픽셀 수가 전체 피부 픽셀의 35% 미만이고, 두번 째 영역이 30% 미만이고, 세번 째 영역이 30% 미만인 경우 이미지는 누드가 아니다.
    3. 가장 큰 피부 영역의 픽셀 수가 전체 피부색에 해당하는 픽셀의 45% 미만인 경우, 이미지는 누드가 아니다.
    4. 만약 총 피부 영역의 개수가 60개 이상인 경우, 이미지는 누드가 아니다.
    5. 위 4가지 경우에 해당되지 않는 경우, 이미지는 누드이다.

라이브러리에서 생략된 부분은 아래와 같다.

  1. 가장 큰 3개의 피부 영역에서 각각 가장 왼쪽, 가장 오른쪽, 가장 위쪽, 가장 아래쪽 픽셀을 찾아 총 12개의 꼭지점로 구성된 다각형을 구성한다. 이 영역을 경계 폴리곤(bounding polygon) 이라고 부른다. (논문에 경계 폴리곤의 정의가 정확하게 기재되어 있지 않아서 임의로 추정한 것이다.)
  2. 만약 총 피부 픽셀이 전체 픽셀의 30% 미만이고, 경계 폴리곤 내에 있는 피부 픽셀이 경계 폴리곤 내 전체 픽셀의 55% 미만인 경우 이미지는 누드가 아니다.
  3. 만약 총 피부 영역의 개수가 60개 이상이고, 경계 폴리곤 내 average intensity 가 0.25 미만인 경우 이미지는 누드가 아니다. (average intensity 의 정의가 무엇인지에 대해서도 논문에 명확히 기재되어 있지 않다. 단순히 폴리곤 내의 스킨 픽셀 수/폴리곤 내의 전체 픽셀 수 는 아닌 것 같고 평균 색상을 나타내는 것 같은데 정확히는 모르겠다.)

nsfw.js

TensorFlow.js 를 이용하여 NSFW 이미지를 감지한다. (알고리즘 분석은 별도로 하지 않았다.)

머신러닝을 기반으로 하는만큼 학습된 model 데이터를 필요로한다. NSFW 이미지 판별을 위한 모델 데이터는 넘쳐나기 때문에, 그냥 제공되는 것을 아무거나 가져다가 쓰면 된다.

장단점

장점

  1. 타 방법에 비해 상대적으로 정확하다 (약 90%).

단점

  1. 초기 모델 로딩에 시간이 걸린다 (2.5MB 모델의 경우 약 5초)
  2. 모델 크기가 부담될 수 있다 (작은 모델의 경우 약 2.5MB, 큰 모델의 경우 약 17MB)

그 외

여러 기관/업체에서 제공하는 api 를 이용할 수 있다. 온전히 client 에서만 돌아가는 것은 아니지만, 단순 호출만 하면 된다는 점에서는 편리한 방법이다.

대부분의 api 는 월 300 ~ 10,000회 까지의 호출은 무료이나 정해진 횟수를 초과하면 비용을 지불해야한다. Google Vision API 로도 이미지의 nsfw 여부를 판별할 수 있는데, 월 1,000회까지 무료이고 이후 1,000개당 $1.5 의 비용을 지불해야한다. 그 외의 곳들은 좀 더 저렴하다.

다만 client 에서 호출하는 경우 여러 client 에서 같은 이미지에 대해 반복적으로 api 호출을 하는 것은 매우 큰 낭비이기 때문에 호출 여부와 결과값 저장을 위한 별도의 캐시 서버가 필요할 것이다. 그런데 이렇게 하자니 그냥 가져다 쓰기만 하면 되는 NSFW Detiection 툴이 이미 많기 때문에, 아예 서버에 nsfw 이미지 판별을 위한 시스템을 구축하는 것이 비용적인 측면에서는 조금 더 저렴할 것이다.