Skip to content

Instantly share code, notes, and snippets.

@uupaa
Last active March 10, 2017 03:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uupaa/43b7828c955f74b3d3be341e4ce72a9d to your computer and use it in GitHub Desktop.
Save uupaa/43b7828c955f74b3d3be341e4ce72a9d to your computer and use it in GitHub Desktop.
How to add original plugin/filter to frei0r.

ffmpeg に独自フィルタを追加する

ffmpeg には libavfilter ライブラリ経由で利用できる filter 機能があり、必要に応じて独自の filter を作成し追加することが可能です。 このエントリでは frei0r に独自filterを追加する方法について説明していきます。

ffmpeg の filter について

ffmpeg filters には filter の一覧と指定方法の説明があります。

filter には以下の特徴があります。

  • video と audio 用の filter があります
  • フィルタは多段掛けが可能です
  • 基本的にはinputで受けたデータを加工しoutputに流し込みます
    • input を提供するフィルタ(ソースフィルタ)もあります
    • output を持たないフィルタ(シンクフィルタ)もあります
  • ffmpeg -filters で利用可能なフィルタの一覧を見ることができます
  • ffmpeg に標準添付されている filter と、frei0r のような外部filter(ダイナミックリンク経由で利用するfilter) があります

このエントリでは frei0r version 1.5.0, OpenCV version 3.2.0, automake, autoconf, libtool, cmake を使用します。必要に応じてインストールしてください。

brew install ffmpeg --with-frei0r
brew install opencv3
brew install automake
brew install libtool
brew install cmake

frei0r について

frei0r には C で書かれたfilter と C++ で書かれたfilter があり、OpenCV や dlib とリンクする場合は C++ で記述していきます。

README の末尾に C++ のスケルトンコードがありますが、あまり参考になりません。frei0r のコードを頑張って読み解く必要があります。

frei0r から不要な要素を削除する

独自 filter を追加する前に、必要のない filter やディレクトリを削除しておきます(コンパイル時間も短縮できます)。

src/filter 以下から、CMake関連のファイルとglow, facebl0r, facedetect, nvdi を残します。また doc/ は不要なので削除します。

  • src/filter 以下からディレクトリを削除します。

    • 削除後はこのようになります
      ▾ filter/
        ▸ CMakeFiles/
        ▸ facebl0r/
        ▸ facedetect/
        ▸ glow/
        ▸ ndvi/
          cmake_install.cmake
          CMakeLists.txt*
          Makefile
    
  • doc ディレクトリを削除し設定を削ります

    • CMakeLists.txt を開き add_subdirectory (doc) の行を削除します
    • configure.ac を開き AC_CONFIG_FILES([...]) から doc/Makefile を削除します
  • src/filter/CMakeLists.txt から不要なfilter名を削除します

    • 削除後はこのようになります
    if (${OpenCV_FOUND})
        add_subdirectory (facebl0r)
        add_subdirectory (facedetect)
    endif (${OpenCV_FOUND})
    
    add_subdirectory (glow)
    add_subdirectory (ndvi)
    
  • src/Makefile.am から不要な *.la*_la_SOURCES を削除します

    • 削除後はこのようになります
    plugin_LTLIBRARIES = \
        glow.la \
        ndvi.la
    
    if HAVE_OPENCV
    plugin_LTLIBRARIES += facebl0r.la
    facebl0r_la_SOURCES = filter/facebl0r/facebl0r.cpp
    facebl0r_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@ 
    facebl0r_la_LIBADD = @OPENCV_LIBS@
    plugin_LTLIBRARIES += facedetect.la
    facedetect_la_SOURCES = filter/facedetect/facedetect.cpp
    facedetect_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@
    facedetect_la_LIBADD = @OPENCV_LIBS@
    endif
    
    #
    # FILTERS
    #
    glow_la_SOURCES = filter/glow/glow.c
    ndvi_la_SOURCES = filter/ndvi/ndvi.cpp filter/ndvi/gradientlut.hpp
    
    AM_CPPFLAGS = -I@top_srcdir@/include 
    AM_CFLAGS = -I@top_srcdir@/include 
    AM_LDFLAGS = -module -avoid-version -lm -export-dynamic
    AM_LIBTOOLFLAGS = --tag=disable-static
    
    plugindir = @libdir@/frei0r-1
    
    install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
        mkdir -p $(DESTDIR)/$(plugindir)
        list='$(plugin_LTLIBRARIES)'; \
        for file in $$list; do \
          sofile=`basename $$file .la`.so; \
          $(INSTALL_PROGRAM) .libs/$$sofile $(DESTDIR)/$(plugindir); \
        done
    
    uninstall-pluginLTLIBRARIES:
        list='$(plugin_LTLIBRARIES)'; \
        for file in $$list; do \
          sofile=`basename $$file .la`.so; \
          rm -f $(DESTDIR)/$(plugindir)/$$sofile; \
        done
    

テストビルド

不要な filter を削った状態で frei0r をビルドします。

  • autoreconf -v または autoheader, aclocal, automake, autonconf の一連のコマンドを実行し、最後に ./configure を実行します
  • libtool でエラーになる場合は Workaround( libtool not found error )を参照してください
autoreconf -v 
# または autoheader && aclocal && libtool --ltdl --copy --force && automake --add-missing --copy && autoconf

./configure

./configure が成功したら make します。

make
make install
./dylib.sh      # mac のみ

make install を行うと、/usr/local/lib/frei0r-1 以下にビルドした filter (*.so) が設置されます。

▾ /usr/
  ▾ local/
    ▾ lib/
      ▾ frei0r-1/
          facebl0r.so
          facedetect.so
          glow.so
          ndvi.so

mac では以下のsh (./dylib.sh) を実行し、*.so を *.dylib にコピーします。

for file in /usr/local/lib/frei0r-1/*.so ; do
  cp $file "${file%.*}.dylib"
done

ビルドした filter が機能するか実行してみましょう。

ffmpeg -i a.mp4 -pix_fmt yuv420p -vf frei0r=glow:20 b.mp4

glow は特別な設定が不要なfilterなため、ビルドするだけで実行が可能です。

では次に、追加の設定が必要なfilter(facebl0r, facedetect) を実行してみましょう。

ffmpeg -i a.mp4 -pix_fmt yuv420p -vf frei0r=facebl0r b.mp4

OpenCVの設定が不十分な場合はエラーが発生し変換に失敗します。対処法は後述(Workaround: OpenCV, classifier, XML)します。

ERROR in filter facebl0r, classifier cascade not found: /usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml

独自 filter を追加するための方法を知る

NVDINVDI の追加差分 を見ると、 以下の4つのファイルを作成/更新すれば良い事がわかります。

  • src/Makefile.am
  • src/filter/CMakeLists.txt
  • src/filter/{{FILTERNAME}}/CMakeLists.txt
  • src/filter/{{FILTERNAME}}/{{FILTERNAME}}.cpp

glow は C で書かれていましたが、NVDI は C++ で書かれています。ここから先は NVDI を例に独自 filter を追加する手順を説明していきます。

src/Makefile.am

src/Makefile.am の 適切な場所に nvdi.la を追加します。

plugin_LTLIBRARIES = \
     :
    multiply.la \
+   nvdi.la \
    nervous.la \
     :

nvdi_la_SOURCES を追加します。ビルド対象の ndvi.cpp と utility 的な役割を持ったコード gradientlut.hpp を追加しています

  medians_la_SOURCES = filter/medians/medians.c filter/medians/ctmf.h filter/medians/small_medians.h
+ nvdi_la_SOURCES = filter/ndvi/ndvi.cpp filter/ndvi/gradientlut.hpp
  nervous_la_SOURCES = filter/nervous/nervous.cpp

OpenCV や Cairo などの外部ライブラリに依存した機能を追加する場合は、以下のように if xxx の中に追加します。

  • ndvi は CAIRO に依存しているため if HAVE_CAIRO の内側に記述します。
  • HAVE_OPENCV や HAVE_CAIRO については後述します。
if HAVE_OPENCV
 plugin_LTLIBRARIES += facebl0r.la
 facebl0r_la_SOURCES = filter/facebl0r/facebl0r.cpp
 facebl0r_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@
 facebl0r_la_LIBADD = @OPENCV_LIBS@
endif

if HAVE_CAIRO
 ndvi_la_CPPFLAGS = @CAIRO_CFLAGS@ @CPPFLAGS@ -DHAVE_CAIRO
 ndvi_la_LIBADD = @CAIRO_LIBS@
endif

src/filter/CMakeLists.txt

nvdi ディレクトリを作成し、cmake のビルド対象にします。

    add_subdirectory (measure)
  endif ()
+ add_subdirectory (ndvi)
  add_subdirectory (nervous)

src/filter/nvdi/CMakeLists.txt

nvdi/CMakeLists.txt を追加します。 SOURCES 変数には ビルド対象の cpp や hpp を指定します。複数ある場合は列挙します。 TARGET 変数には ビルドターゲットを指定します。 nvdi は Cairo を使用するため、target_link_libraries マクロで Cairo のパスを設定しています

set (SOURCES ndvi.cpp gradientlut.hpp)
set (TARGET ndvi)

if (Cairo_FOUND)
  include_directories(${Cairo_INCLUDE_DIR})
  set(LIBS ${LIBS} ${Cairo_LIBRARY})
endif (Cairo_FOUND)

if (MSVC)
  set (SOURCES ${SOURCES} ${FREI0R_DEF})
endif (MSVC)

add_library (${TARGET}  MODULE ${SOURCES})

set_target_properties (${TARGET} PROPERTIES PREFIX "")
target_link_libraries(ndvi ${LIBS})  # Cairo のパスを設定 http://blog.wagavulin.jp/entry/2011/11/27/222642

install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})

src/filter/ndvi/

filter のコードを追加します。

まずは src/filter/ndvi/gradientlut.hpp を追加します。

  • GRADIENTLUT_PRINT を有効にすると、debug print を行うようです。
#include <vector>
//#define GRADIENTLUT_PRINT // debug print
#ifdef GRADIENTLUT_PRINT
#include <cstdio>
#endif

class GradientLut {
public:
    struct Color {
        uint8_t r;
        uint8_t g;
        uint8_t b;
    };

    void setDepth(size_t depth);
    void fillRange(double startPos, const Color& startColor,
                   double endPos, const Color& endColor);
    const Color& operator[](double pos) const;
    void print() const;

private:
    std::vector<Color> lut;
};

void GradientLut::setDepth(size_t depth) {
    lut.resize(depth);
}

void GradientLut::fillRange( double startPos, const GradientLut::Color& startColor,
                             double endPos,   const GradientLut::Color& endColor ) {
    unsigned int startIndex = (double)(lut.size() - 1) * startPos + 0.5;
    unsigned int endIndex = (double)(lut.size() - 1) * endPos + 0.5;
    unsigned int span = endIndex - startIndex;

    if(span < 1) span = 1;

    for(int i = 0; i <= span; i++) {
        Color color;
        double ratio = (double)i / (double)span;

        color.r = startColor.r + ratio * ((double)endColor.r - (double)startColor.r);
        color.g = startColor.g + ratio * ((double)endColor.g - (double)startColor.g);
        color.b = startColor.b + ratio * ((double)endColor.b - (double)startColor.b);
        lut[i + startIndex] = color;
    }
}

const GradientLut::Color& GradientLut::operator[](double pos) const {
    unsigned int size = lut.size();
    unsigned int index = (double)size * pos;
    if(index >= size) {
        index = size - 1;
    }
    return lut[index];
};

// Debug print function.
void GradientLut::print() const {
#ifdef GRADIENTLUT_PRINT
    printf("LUT:\tIndex\tRed\tGreen\tBlue\n");
    for(int i = 0; i < lut.size(); i++) {
        const Color& color = lut[i];
        printf("\t%3d\t%02x\t%02x\t%02x\n", i, color.r, color.g, color.b);
    }
#endif
}

src/filter/ndvi/ndvi.cpp を追加します。こちらが filter の本体です。

#ifdef HAVE_CAIRO
#include <cairo.h>
#endif

#include "frei0r.hpp"
#include "frei0r_math.h"
#include "gradientlut.hpp"
#include <string>
#include <stdlib.h>

// This filter calculates NDVI values from near-infrared + blue (infrablue) video.
// The NDVI values are mapped to a false color image.
static inline double N2P(double ndvi) {
    // Convert NDVi value (-1 to 1) to position (0 to 1).
    return (ndvi + 1.0) / 2.0;
}

class Ndvi : public frei0r::filter {
public:
    Ndvi(unsigned int width, unsigned int height);
    virtual void update();

private:
    void initLut();
    double paramLutLevels;
    std::string paramColorMap;
    double paramVisScale;
    double paramVisOffset;
    double paramNirScale;
    double paramNirOffset;
    unsigned int lutLevels;
    std::string colorMap;
    GradientLut gradient;
};

Ndvi::Ndvi(unsigned int width, unsigned int height)
 : paramLutLevels(256.0 / 1000.0)
 , paramColorMap("grayscale")
 , paramVisScale(0.1)
 , paramVisOffset(0.5)
 , paramNirScale(0.1)
 , paramNirOffset(0.5)
 , lutLevels(0)
 , colorMap("")
 , gradient() {
    register_param(paramColorMap,  "Color Map",  "The color map to use. One of 'earth', 'grayscale', 'heat' or 'rainbow'.");
    register_param(paramLutLevels, "Levels",     "The number of color levels to use in the false image (divided by 1000).");
    register_param(paramVisScale,  "VIS Scale",  "A scaling factor to be applied to the visible component (divided by 10).");
    register_param(paramVisOffset, "VIS Offset", "An offset to be applied to the visible component (mapped to [-100%, 100%].");
    register_param(paramNirScale,  "NIR Scale",  "A scaling factor to be applied to the near-infrared component (divided by 10).");
    register_param(paramNirOffset, "NIR Offset", "An offset to be applied to the near-infrared component (mapped to [-100%, 100%].");
}

void Ndvi::update() {
    uint8_t *inP = (uint8_t*)in;
    uint8_t *outP = (uint8_t*)out;
    double visScale  =  paramVisScale * 10.0;
    double visOffset = (paramVisOffset * 510) - 255;
    double nirScale  =  paramNirScale * 10.0;
    double nirOffset = (paramNirOffset * 510) - 255;

    initLut();

    for (int i = 0; i < size; i++) {
        double vis =  inP[2]; // blue channel
        double nir =  inP[0]; // red channel
        vis = (vis + visOffset) * visScale;
        vis = CLAMP(vis, 0.0, 255.0);
        nir = (nir + nirOffset) * nirScale;
        nir = CLAMP(nir, 0.0, 255.0);
        double ndvi = (nir -vis) / (nir + vis);
        double pos = N2P(ndvi);
        const GradientLut::Color& falseColor = gradient[pos];
        outP[0] = falseColor.r;
        outP[1] = falseColor.g;
        outP[2] = falseColor.b;
        outP[3] = 0xff;
        inP += 4;
        outP += 4;
    }
}

void Ndvi::initLut() {
    // Only update the LUT if a parameter has changed.
    unsigned int paramLutLevelsInt = paramLutLevels * 1000.0 + 0.5;

    if (lutLevels == paramLutLevelsInt &&
        colorMap == paramColorMap) {
        return;
    } else {
        lutLevels = paramLutLevelsInt;
        colorMap = paramColorMap;
    }

    gradient.setDepth(lutLevels);

    if(colorMap == "earth") {
        ...
    } else if(colorMap == "heat") {
        ...
    } else if(colorMap == "rainbow") {
        ...
    } else { // grayscale
        ...
    }
}

frei0r::construct<Ndvi> plugin("NDVI filter", // Filter short name
    "This filter creates a NDVI false image from an infrablue source.", // description
    "Brian Matherly",           // Author
    0,                          // Major version
    1,                          // Minor version
    F0R_COLOR_MODEL_RGBA8888);  // in に渡されるカラーフォーマットの指定, 32bit RGBA

facebl0r はカラーフォーマットの指定が F0R_COLOR_MODEL_PACKED32 になっています。

frei0r::construct<FaceBl0r> plugin("FaceBl0r",
     "automatic face blur",
    "ZioKernel, Biilly, Jilt, Jaromil, ddennedy",
    1,
    1,
    F0R_COLOR_MODEL_PACKED32);  // PACKED32 は RGBA と BGRA の両方を内包できる 32bit型。OpenCVと受け渡しをする場合などに具体的な型の指定を避ける場合に使用します

via https://github.com/dyne/frei0r/commit/9fff22cc0dff61945ce04ecc835b507cdf3547e6

独自 filter を追加する場合も、nvdi の例にならって追加していきます。

独自 filter を追加する

さていよいよ本題です。OpenCV と dlib を使った独自 filter を追加していきます。ここで追加する filter の名前は facedlib とします。

まずは、facedetect をコピーした facedlib を作成し、dlib の ヘッダを組み込んでみます(ヘッダは組み込みますが、dlib はまだ呼び出しません)。

  • configure.ac に以下の行を追加し DLIB_CPPFLAGS 変数を定義します

        # Checks for programs.
        AC_PROG_CXX
        AC_PROG_CC
        AC_PROG_CC_C99
        LT_INIT([disable-static])
    
    +   DLIB_CPPFLAGS="-std=c++11 -stdlib=libc++"
    +   AC_SUBST(DLIB_CPPFLAGS)
  • src/filter/facedlib/ を作成します

  • src/filter/facedlib/dlib に dlib/dlib をコピーして設置します

    ▾ facedlib/
        ▾ dlib/
          ▾ all/
              source.cpp
          ▸ any/
    
  • src/filter/CMakeLists.txt に facedlib を追加します

      if (${OpenCV_FOUND})
          add_subdirectory (facebl0r)
          add_subdirectory (facedetect)
    +     add_subdirectory (facedlib)
      endif (${OpenCV_FOUND})
    
      add_subdirectory (glow)
      add_subdirectory (ndvi)
  • src/filter/facedlib/CMakeLists.txt を作成します

    set (SOURCES facedlib.cpp)
    set (TARGET facedlib)
    
    if (MSVC)
      set (SOURCES ${SOURCES} ${FREI0R_DEF})
    endif (MSVC)
    
    include_directories(./src/filter/facedlib/dlib)  # [!]
    set(LIBS ${LIBS} ./src/filter/facedlib/dlib)     # [!]
    
    include_directories (${OpenCV_INCLUDE_DIR})
    link_directories (${OpenCV_LIBRARY_DIRS})
    LINK_LIBRARIES(${OpenCV_LIBS} ${OpenCV_LIBRARIES})
    
    add_library (${TARGET}  MODULE ${SOURCES})
    set_target_properties (${TARGET} PROPERTIES PREFIX "")
    target_link_libraries(facedlib ${LIBS})          # [!]
    
    install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
    
  • src/filter/facedlib/facedlib.cpp を作成します。

    • 内容は、facedetect/facedetect.cpp をコピーし FaceDetectFaceDlib に変換します
  • src/Makefile.am に facedlib の情報を追加します

    • dlib/all/source.cpp を組み込みます -congigure.ac で追加した DLIB_CPPFLAGS をここで使用します
        if HAVE_OPENCV
        plugin_LTLIBRARIES += facebl0r.la
        facebl0r_la_SOURCES = filter/facebl0r/facebl0r.cpp
        facebl0r_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@
        facebl0r_la_LIBADD = @OPENCV_LIBS@
        plugin_LTLIBRARIES += facedetect.la
        facedetect_la_SOURCES = filter/facedetect/facedetect.cpp
        facedetect_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@
        facedetect_la_LIBADD = @OPENCV_LIBS@
    +   plugin_LTLIBRARIES += facedlib.la
    +   facedlib_la_SOURCES = filter/facedlib/facedlib.cpp filter/facedlib/dlib/all/source.cpp
    +   facedlib_la_CFLAGS = @OPENCV_CFLAGS@ @CFLAGS@ @DLIB_CPPFLAGS@
    +   facedlib_la_LIBADD = @OPENCV_LIBS@
        endif

この段階で一度以下のコマンドを実行しビルドを行います。

autoreconf -v
./configure
make clean
make

error: "Dlib requires C++11 support. Give your compiler the -std=c++11 option to enable it." とエラーが発生するため、 src/Makefile を編集し、ビルドフラグ(-std=c++11 -stdlib=libc++)を直接指定します。なお src/Makefile は ./configure で自動生成されるファイルなため ./configure 後は再度この作業を行ってください。 (facedlib.lo と source.lo に対して DLIB_CPPFLAGS の設定を適用する方法が不明なため、このようにしています)

    facedlib.lo: filter/facedlib/facedlib.cpp
        $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
        $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
-       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT facedlib.lo -MD -MP -MF $(DEPDIR)/facedlib.Tpo -c -o facedlib.lo `test -f 'filter/facedlib/facedlib.cpp' || echo '$(srcdir)/'`filter/facedlib/facedlib.cpp
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -std=c++11 -stdlib=libc++ -MT facedlib.lo -MD -MP -MF $(DEPDIR)/facedlib.Tpo -c -o facedlib.lo `test -f 'filter/facedlib/facedlib.cpp' || echo '$(srcdir)/'`filter/facedlib/facedlib.cpp
        $(AM_V_at)$(am__mv) $(DEPDIR)/facedlib.Tpo $(DEPDIR)/facedlib.Plo
    #	$(AM_V_CXX)source='filter/facedlib/facedlib.cpp' object='facedlib.lo' libtool=yes \
    #	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
    #	$(AM_V_CXX_no)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o facedlib.lo `test -f 'filter/facedlib/facedlib.cpp' || echo '$(srcdir)/'`filter/facedlib/facedlib.cpp

    source.lo: filter/facedlib/dlib/all/source.cpp
        $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
        $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
-       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT source.lo -MD -MP -MF $(DEPDIR)/source.Tpo -c -o source.lo `test -f 'filter/facedlib/dlib/all/source.cpp' || echo '$(srcdir)/'`filter/facedlib/dlib/all/source.cpp
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -std=c++11 -stdlib=libc++ -MT source.lo -MD -MP -MF $(DEPDIR)/source.Tpo -c -o source.lo `test -f 'filter/facedlib/dlib/all/source.cpp' || echo '$(srcdir)/'`filter/facedlib/dlib/all/source.cpp
        $(AM_V_at)$(am__mv) $(DEPDIR)/source.Tpo $(DEPDIR)/source.Plo
    #	$(AM_V_CXX)source='filter/facedlib/dlib/all/source.cpp' object='source.lo' libtool=yes \
    #	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
    #	$(AM_V_CXX_no)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o source.lo `test -f 'filter/facedlib/dlib/all/source.cpp' || echo '$(srcdir)/'`filter/facedlib/dlib/all/source.cpp

src/Makefile を更新したら ./configure を行わずに、make clean, make を行ってください。

make clean
make

Workaround

  • frei0r が Cario を使った filter を初めてサポートした時の diff がこちら

  • Mac で clang を使用するようにビルドオプションを変更した時の diff がこちら

  • facedetect が c から cpp で書き直されたときの diff がこちら

  • AM_CONDITIONAL マクロについては http://nantonaku-shiawase.hatenablog.com/entry/2015/01/08/005544 を参照してください。

  • AX_CXX_COMPILE_STDCXX_11 マクロを使うと自動的に C++11のフラグをよしなにしてくれるらしい → してくれませんでした。

  • frei0r version 1.5 では opencv3 が必要です。以下のエラーがでる場合は opencv1 or 2 をアンインストールし、opencv3 をインストールし直してください(frei0r version 1.4 は opencv2 が必要です)

    • brew uninstall opencv && brew install opencv3 && brew link opencv3 --force

      Scanning dependencies of target facedetect
      [  1%] Building CXX object src/filter/facedetect/CMakeFiles/facedetect.dir/facedetect.cpp.o
      [  2%] Linking CXX shared module facedetect.so
      ld: warning: ignoring file /usr/local/Cellar/opencv/2.4.13.2/lib/libopencv_calib3d.dylib, file was built for x86_64 which is not the architecture being linked (i386): /usr/local/Cellar/opencv/2.4.13.2/lib/libopencv_calib3d.dylib
      
      Undefined symbols for architecture i386:
      
  • AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) で warn がでる場合は

    - AC_INIT(frei0r-plugins, [1.5.0], [frei0r-devel@piksel.no])
    - AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
    
    + AC_INIT([frei0r-plugins], [1.5.0])
    + AM_INIT_AUTOMAKE
    
  • dylib.sh

    • mac では *.so ではなく *.dylib が必要なため以下のスクリプトを実行する必要があります。
    • 以下のコマンドを ./dylib.sh として作成し、chmod +x dylib.sh として実行権限を付与し、make install 後に ./dylib.sh を実行すると良いでしょう。

    When using Apple/OSX, the dlopen() mechanism (in FFMpeg for instance) will look for .dylib extensions and not the .so that frei0r plugins have by default. To fix this problem one can rename the plugins simply so:

    for file in /usr/local/lib/frei0r-1/*.so ; do
      cp $file "${file%.*}.dylib"
    done
    
  • OpenCVの設定が不十分だと ERROR in filter facebl0r, classifier cascade not found エラーが発生します これに対処するには OpenCV で読み込む classifier (XML) の更新とパスを修正する必要があります

    ERROR in filter facebl0r, classifier cascade not found:
     /usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml
    
  • OpenCV の classifier (XML) を更新する

    • src/filter/facebl0r/facebl0r.cpp が参照している classifier XML は古く、またパスも修正する必要があります

      • /usr/ 以下は、El Capitan 以降でファイル設置不能です
      • brew install opencv3 でインストールされる xml ファイルのフォーマットが古い場合があります
      • xml ファイルパスを src/filter/facebl0r/facebl0r.cpp と src/filter/facedetect/facedetect.cpp に直接指定します
      - classifier = "/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml";
      + classifier = "/usr/local/Cellar/opencv3/3.2.0/share/OpenCV/haarcascades/haarcascade_frontalface_default_new.xml";
  • frei0r version 1.4.0 についてはこちらを参照してください

  • su_zu/ffmpeg filterの作り方

  • libtool not found error

    • 一部の環境では libtool ではなく glibtoolize という名前で存在する場合があります
/usr/local/lib/pkgconfig/frei0r.pc

これ以外の事でやり方がわからない場合は master ブランチのコミットログを追いかけましょう

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment