ncnnでメイクアップTransferを動かしてみる

## 概要

メイクアップTransferは、素のお顔と、別の人の化粧をしているお顔とを入力すると、素のお顔に化粧をした画像を作成してくれる学習モデルです。
ncnnで、メイクアップTransferをしてみます。

![Screenshot from 2023-11-20 12-04-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73020/209c5c15-033b-8e08-66d8-390c5631e8a1.png)

## 環境構築
まず、M5UnitV2のクロスコンパイル環境を構築する手順で、ncnnやOpenCVをUbuntuにインストールします。

[M5UnitV2のクロスコンパイル環境を構築する手順](https://qiita.com/nnn112358/pbulic/9e15450265b689300216)

```
Ubuntu 22.04.3 LTS(x64)
OpenCV ver 0.4.4
ncnn ver 231027
```

## Stable-Diffusionのダウンロード

GitHubからFeiGeChuanShu氏のncnn_MakeupTransferのコードをダウンロードします。

```
$ git clone https://github.com/FeiGeChuanShu/ncnn_MakeupTransfer
$ cd ncnn_MakeupTransfer/linux
```

## CMakeLists.txt ファイルの作成

cmakeでコンパイルするために、CMakeLists.txtを編集します。

```
gedit CMakeLists.txt
```

```CMakeLists.txt

SET(CMAKE_BUILD_TYPE "Release")

SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

SET(TARGET_COMPILER "x64")
if(TARGET_COMPILER STREQUAL "x64")
    message(STATUS "TARGET_COMPILE STREQUAL X64")
    SET(NCNN_INSTALL_DIR /opt/external/ncnn/install/x64/)
    SET(ZBAR_INSTALL_DIR /opt/external/zbar-0.10/build/x64/)
    SET(OpenCV_DIR /opt/external/opencv/build/x64)
else()
    message(STATUS "TARGET_COMPILE STREQUAL arm")
    SET(CMAKE_CXX_COMPILER arm-none-linux-gnueabihf-g++)
    SET(CMAKE_C_COMPILER arm-none-linux-gnueabihf-gcc)
    SET(NCNN_INSTALL_DIR /opt/external/ncnn/install/arm/)
    SET(ZBAR_INSTALL_DIR /opt/external/zbar-0.10/build/arm)
    SET(OpenCV_DIR /opt/external/opencv/build/arm)
endif()

PROJECT(ncnn_ssat)
cmake_minimum_required(VERSION 3.5)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)

find_package(OpenCV REQUIRED)
if (OpenCV_FOUND)
     message(OPENCV_VERSION)
    message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}")
    message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
else ()
    message(FATAL_ERROR "opencv Not Found!")
endif (OpenCV_FOUND)

find_package(OpenMP REQUIRED)
if (OPENMP_FOUND)
    message("OPENMP FOUND")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
else ()
    message(FATAL_ERROR "OpenMP Not Found!")
endif ()

link_directories(${OpenCV_LIBRARY_DIRS})

include_directories(${OpenCV_INCLUDE_DIRS} )
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${NCNN_INSTALL_DIR}/include/ncnn)

add_executable(ncnn_ssat ssat.cpp)
target_link_libraries(ncnn_ssat ${OpenCV_LIBRARIES})
target_link_libraries(ncnn_ssat ${NCNN_INSTALL_DIR}/lib/libncnn.a -fopenmp)



```


## ビルド
Ubuntu用のバイナリをcmakeでコンパイルして、生成されたバイナリを実行します。

バイナリの引数は以下のように指定します。

```
./bin/ncnn_ssat [target_imagepath] [reference_imagepath]
```
target_imagepath・・・素のお顔を指定します
reference_imagepath・・・別の人の化粧をしているお顔を指定します

実行すると、Segmentation faultが発生してしまいました。


```shell
$ cmake .
$ make
$ ./bin/ncnn_ssat ../test_images/non-makeup/xfsy_0405.png ../test_images/makeup/vFG112.png 
param is too old, please regenerate!
layer load_param 88 ReduceMean_181 failed
param is too old, please regenerate!
layer load_param 90 ReduceMean_183 failed
param is too old, please regenerate!
layer load_param 97 ReduceSum_194 failed
param is too old, please regenerate!
layer load_param 101 ReduceSum_198 failed
Segmentation fault (コアダンプ)
```

ncnnのwikiを参照すると、「makeup.param」のファイルでエラーが起きていて、学習モデルをncnnのモデルへ変換する際に使った、caffe2ncnnのバージョンが古く、古いフォーマットであるときに発生するエラーとなっていました。

https://github.com/Tencent/ncnn/wiki/FAQ-ncnn-throw-error

オリジナルのモデルがない場合、paramファイルのレイヤー固有のパラメータを手動で修正することができます。
makeup.paramのファイルの中で、Reductionの行で、先頭の配列カウントを除く、値をマイナス1し、5=1を追加します。

```makeup.param
- 91行目:Reduction ReduceMean_181 1 1 277_splitncnn_1 321 0=3 1=0 -23303=2,2,3 4=1
+ 91行目:Reduction ReduceMean_181 1 1 277_splitncnn_1 321 0=3 1=0 -23303=2,1,2 5=1

- 93行目:Reduction ReduceMean_183 1 1 305_splitncnn_1 323 0=3 1=0 -23303=2,2,3 4=1
+ 93:行目Reduction ReduceMean_183 1 1 305_splitncnn_1 323 0=3 1=0 -23303=2,1,2 5=1

- 100行目:Reduction ReduceSum_194 1 1 337 338 1=0 -23303=1,1 4=1
+ 100行目:Reduction ReduceSum_194 1 1 337 338 1=0 -23303=1,0 5=1

- 104行目:Reduction ReduceSum_198 1 1 337 338 1=0 -23303=1,1 4=1
+ 104行目:Reduction ReduceSum_198 1 1 337 338 1=0 -23303=1,0 5=1
```

再度、生成されたバイナリを実行します。
メイクアップTransferを動かしてみることができました。

```
$ ./bin/ncnn_ssat ../test_images/non-makeup/xfsy_0405.png ../test_images/makeup/vFG112.png 
```

![Screenshot from 2023-11-22 14-33-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73020/9b232140-f11e-973c-8894-cdde8740f202.png)




## 参考資料
この記事を作成するにあたり、以下のウェブサイトを参考にしました。
[FeiGeChuanShu/ncnn_MakeupTransfer](https://github.com/FeiGeChuanShu/ncnn_MakeupTransfer)
[SSAT: A Symmetric Semantic-Aware Transformer Network for Makeup Transfer and Removal](https://github.com/Snowfallingplum/SSAT)