おじさん、OpenCVのことばっかりブログに書いていたら古いといわれました。
いつもgcc hoge.cのように1時間程度で簡単にビルドして実行して試せる記事を書いていたのに。
しかも勝手にC/C++縛りです。
くやしいので本日は最近はやっている、PyTorch。
ついにPythonの記事か!いや、そうではありません。
PythonのPytorchの記事はみんな書いてるしね。
PyTorchってPythonで書かれているように見えますが、ほとんどはC++で書かれているのでC++から使えます。C++で書かれている部分をlibtorchというようで、以下に使い方が書かれています。
https://pytorch.org/cppdocs/
また、ライブラリのバイナリーも以下の場所から入手できます。
https://pytorch.org/cppdocs/installing.html
だけど、おじさんの使っているWindsows版のlibtorchがない。
しかも<pytorch_root>/docs/libtorch.rstに書かれている、libtorchのビルド方法は全然更新されてないらしく、全然違うし。
ドキュメント整備されてないし、ソースコード汚いし、ドキュメント通りにやってもビルドどおらないし。。どうすりゃいいんだよ。
というわけで本日はPyTorchのコア部分であるlibtorchのビルドをしてみます。
まず、必要なツールですが、VisualStudio2017、Python3.7、CMake、PyYamlがいります。
PyYamlはPythonをインストールしたあとにコマンドプロンプトから以下のように入力するとインストールすることができます。
--------------------
pip3.7 install pyyaml
--------------------
cmakeはCygwinのものを使うと、Windowsビルド用のモジュールが入っていないので、本家のcmakeをダウンロードしてインストールします。
インストールがおわり、pythonとcmakeのパスを設定し、コマンドプロンプトから次のように入力するとcmakeによるビルドが開始されるようです。
--------------------
cd <pytorch_root>\tools
mkdir build
cd build
python ..\build_libtorch.py
--------------------
ビルドにはいろいろな外部ライブラリが必要です。おじさんのようにgithubからzipファイルをダウンロードしてそれを展開してビルドすると外部ライブラリうがないため、ビルド時に以下のようなエラーになります。
--------------------
CMake Error at cmake/Dependencies.cmake:1005 (add_subdirectory):
The source directory
D:/trash/pytorch-master/third_party/foxi
does not contain a CMakeLists.txt file.
Call Stack (most recent call first):
CMakeLists.txt:236 (include)
--------------------
外部ライブラリは、<pytorch_root>/third_party/<ライブラリ名>のところに足りない外部ライブラリをどんどん突っ込んでいきます。
ソースコードは、<pytorch_root>/third_party/<ライブラリ名>のところに、CmakeLists.txtがくるように配置しないとだめです。
外部ライブラリのソースコードはpytorchのgithubのthird_partyからリンクをたどって取ってきたほうがバージョンが一致するのでよいです。
protobuf、cpuinfo、googletest、benchmark、FP16、foxi、onnx、psimdなどの外部ライブラリがいるようです。
しかしここで一つ問題が、ベクトル演算ライブラリは、なんらかのBLASまたはEigenが必要です。なぜかベクトル演算ライブラリがなくてもビルドが開始されてしまいます。
なので、eigenもgithubからとってきます。
JavaのJVMとかのビルドもそうなのですが、Windows版のビルドはCドライブ以外でビルドを行うとよくファイルのコピーでビルドエラーになります。
libtorchもCドライブ以外でビルドを行うと、psimdのコピーができないようなので、
<pytorch_root>/tools/build/confu-srcs/psimdにthird_partyにある同じファイルをコピーします。
大規模なソースコードのビルドを行うときは絶対Cドライブでやったほうがいいです。Dドライブでは本当になぜかビルドが通りません。
これでやっとビルドが開始されます。
1時間くらいでビルドができ、<pytorch_root>/tools/build/bin/Releaseにtorch.dllが出来上がります。
これでC++からpytorchが使えるようになります。
PyTorchのexample/cppフォルダにはc++のサンプルがあります。
このなかに定番の文字認識「MNIST」のlibtorch版、mnist.cppがあります。
ファイル一つしかないんですね。なのでビルド簡単。
mnistのビルド方法やドキュメントもあるので、これをつかってPyTorchのlibtorch使い方を学ぶことができます。
めでたしめでたし。
2019年4月11日木曜日
2019年3月13日水曜日
Lua言語用のプラグインDLLを作ってみた。
最近ディープラーニングはTorchやPytorchでやるようです。
TorchはLuaというスクリプト言語で書かれています。
スクリプト言語ですが、中間言語にコンパイルして高速に動かすこともできます。
Luaのソースコードを見て分かったのですが、とてもコンパクト。
さらに、Lua言語は簡単にC言語の関数やDLLを呼び出せるので、簡単にいろんなライブラリと連携させることができます。
動的にDLLを呼び出せて、オブジェクトの演算子の再定義ができて、簡単にC言語連携ができるので、たくさんのソースをビルドしないといけない機械学習に適しているんだと思います。
TorchのプラグインのDLLってどうやって作るのかを調べたら、Lua用のプラグインDLLをつくればそのままTorchから使えることがわかったので、本日はLua用のプラグインを作ってみます。
luadllsample.h
--------------------------------------------------
#ifndef DF_LUADLL_SAMPLE_H_
#define DF_LUADLL_SAMPLE_H_
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "mylua_base.h"
#ifdef _WIN32
#ifdef LUADLLSAMPLE_EXPORTS
#define LUADLLSAMPLE_API __declspec(dllexport)
#else
#define LUADLLSAMPLE_API __declspec(dllimport)
#endif
#else
#define LUADLLSAMPLE_API
#endif
#ifdef __cplusplus
extern "C"
{
#endif
LUADLLSAMPLE_API int func_sample(lua_State* l);
#ifdef __cplusplus
}
#endif
#endif
--------------------------------------------------
luadllsample.cpp
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "mylua_base.h"
#include "luadllsample.h"
LUADLLSAMPLE_API int func_sample(lua_State* l)
{
printf("kita!!!!!\n");
return 123;
}
--------------------------------------------------
test.lua
--------------------------------------------------
f=package.loadlib("luadll_sample.dll","func_sample")
f()
--------------------------------------------------
こんだけでプラグインができるなんて。
とても簡単にプラグインを作れます。
でもこれだとビルド時にliblua.dllがいるので、ビルド時にliblua.dllがいらない版も作ってみました。
これで、ばんばんtorchのプラグインが作れる。
mylua_base.h
--------------------------------------------------
#ifndef MY_LUA_BASE_H_
#define MY_LUA_BASE_H_
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern lua_State *(*p_luaL_newstate) (void);
extern void(*p_luaL_openlibs)(lua_State *L);
extern int(*p_luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
extern void(*p_lua_close)(lua_State *L);
extern void(*p_lua_pushcclosure)(lua_State *L, lua_CFunction fn, int n);
extern void(*p_lua_setglobal)(lua_State *L, const char *name);
extern int(*p_lua_pcallk)(lua_State *L, int nargs, int nresults, int errfunc,
lua_KContext ctx, lua_KFunction k);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#define luaL_newstate p_luaL_newstate
#define luaL_openlibs p_luaL_openlibs
#define luaL_loadfilex p_luaL_loadfilex
#define lua_close p_lua_close
#define lua_pushcclosure p_lua_pushcclosure
#define lua_setglobal p_lua_setglobal
#define lua_pcallk p_lua_pcallk
#endif
--------------------------------------------------
mylua_base.cpp
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "mylua_base_min.h"
#include "dll_client.h"
#define LUA_SO_NAME "liblua"
// api function
lua_State *(*p_luaL_newstate) (void) = NULL;
void(*p_luaL_openlibs)(lua_State *L) = NULL;
void(*p_lua_close)(lua_State *L) = NULL;
int(*p_luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode) = NULL;
void(*p_lua_pushcclosure)(lua_State *L, lua_CFunction fn, int n) = NULL;
void(*p_lua_setglobal)(lua_State *L, const char *name) = NULL;
int(*p_lua_pcallk)(lua_State *L, int nargs, int nresults, int errfunc,
lua_KContext ctx, lua_KFunction k) = NULL;
// init
class myluabase_init {
public:
myluabase_init();
virtual ~myluabase_init();
};
static myluabase_init mi;
static void* osh = NULL;
myluabase_init::myluabase_init()
{
osh = dll_load(DLL_NAME(LUA_SO_NAME));
if (osh == NULL)printf("liblua dll_load error\n");
p_luaL_newstate = (lua_State *(*) (void))dll_access(osh, "luaL_newstate");
if (p_luaL_newstate == NULL)printf("luaL_newstate dll_access error\n");
p_luaL_openlibs = (void(*)(lua_State *))dll_access(osh, "luaL_openlibs");
if (p_luaL_openlibs == NULL)printf("luaL_openlibs dll_access error\n");
p_lua_close = (void(*)(lua_State *))dll_access(osh, "lua_close");
if (p_lua_close == NULL)printf("lua_close dll_access error\n");
p_luaL_loadfilex = (int(*) (lua_State *, const char *,const char *))dll_access(osh, "luaL_loadfilex");
if (p_luaL_loadfilex == NULL)printf("luaL_loadfilex dll_access error\n");
p_lua_pushcclosure = (void(*)(lua_State *, lua_CFunction, int))dll_access(osh, "lua_pushcclosure");
if (p_lua_pushcclosure == NULL)printf("lua_pushcclosure dll_access error\n");
p_lua_setglobal = (void(*)(lua_State *, const char *))dll_access(osh, "lua_setglobal");
if (p_lua_setglobal == NULL)printf("lua_setglobal dll_access error\n");
p_lua_pcallk = (int(*)(lua_State *, int, int, int,lua_KContext,lua_KFunction))dll_access(osh, "lua_pcallk");
if (p_lua_pcallk == NULL)printf("lua_pcallk dll_access error\n");
}
myluabase_init::~myluabase_init()
{
if (osh) {
dll_close(osh);
}
osh = NULL;
}
--------------------------------------------------
dll_client.h
--------------------------------------------------
#ifndef _DLL_CLIENT_H_
#define _DLL_CLIENT_H_
#define _DLL_CLIENT_H_VER "20130701"
#define LIB_OK 0
#define LIB_ERR_INVALID_REQUEST (-1)
#define LIB_ERR_INVALID_PARAMETER (-2)
#define LIB_ERR_NOSERVICE (-3)
#define LIB_ERR_NOREQUEST (-4)
#if defined(_WIN32) && !defined(__GNUC__)
#define LIBEXT ".dll"
#else
#define LIBEXT ".so"
#endif
#define DLL_NAME(a) a LIBEXT
#ifdef __cplusplus
extern "C"{
#endif
void *dll_load(char *dllname);
void *dll_access(void *pDllmod, char *funcname);
void dll_close(void *pDllmod);
#ifdef __cplusplus
}
#endif
#endif
--------------------------------------------------
dll_client.c
--------------------------------------------------
#include <stdio.h>
#ifdef WIN32 /* For Windows */
#include <windows.h>
#endif
#include "dll_client.h"
#ifdef ERR_PRINT
#define EPRINT(a) fprintf(stderr,a)
#define EPRINT2(a,b) fprintf(stderr,a,b)
#else
#define EPRINT(a) do; while(0)
#define EPRINT2(a,b) do; while(0)
#endif
void *dll_load(char *dllname)
{
void *pFunclib=NULL;
if(dllname==NULL) {
EPRINT("### dllname is NULL\n");
return NULL;
}
#ifdef _WIN32
pFunclib = LoadLibraryA(dllname);
#endif
#if defined(unix) || defined(__APPLE__)
pFunclib = dlopen(dllname, RTLD_LAZY);
#endif
if(!pFunclib) {
EPRINT2("### cannot dll_load >%s<\n",dllname);
}
return pFunclib;
}
void *dll_access(void *pDllmod, char *funcname)
{
void *pDll_func=NULL;
if(pDllmod==NULL) {
EPRINT("### dll_access handle is NULL\n");
return NULL;
}
if(funcname==NULL) {
EPRINT("### dll_access funcname is NULL\n");
return NULL;
}
#ifdef _WIN32
pDll_func = GetProcAddress((HMODULE)pDllmod, funcname);
#endif
#if defined(unix) || defined(__APPLE__)
pDll_func = dlsym(pDllmod, funcname);
#endif
if(!pDll_func) {
EPRINT2("### cannot dll_access >%s<\n",funcname);
}
return pDll_func;
}
void dll_close(void *pDllmod)
{
if(pDllmod==NULL)return;
#ifdef _WIN32
FreeLibrary(pDllmod);
#endif
#if defined(unix) || defined(__APPLE__)
dlclose(pDllmod);
#endif
return;
}
--------------------------------------------------
TorchはLuaというスクリプト言語で書かれています。
スクリプト言語ですが、中間言語にコンパイルして高速に動かすこともできます。
Luaのソースコードを見て分かったのですが、とてもコンパクト。
さらに、Lua言語は簡単にC言語の関数やDLLを呼び出せるので、簡単にいろんなライブラリと連携させることができます。
動的にDLLを呼び出せて、オブジェクトの演算子の再定義ができて、簡単にC言語連携ができるので、たくさんのソースをビルドしないといけない機械学習に適しているんだと思います。
TorchのプラグインのDLLってどうやって作るのかを調べたら、Lua用のプラグインDLLをつくればそのままTorchから使えることがわかったので、本日はLua用のプラグインを作ってみます。
luadllsample.h
--------------------------------------------------
#ifndef DF_LUADLL_SAMPLE_H_
#define DF_LUADLL_SAMPLE_H_
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "mylua_base.h"
#ifdef _WIN32
#ifdef LUADLLSAMPLE_EXPORTS
#define LUADLLSAMPLE_API __declspec(dllexport)
#else
#define LUADLLSAMPLE_API __declspec(dllimport)
#endif
#else
#define LUADLLSAMPLE_API
#endif
#ifdef __cplusplus
extern "C"
{
#endif
LUADLLSAMPLE_API int func_sample(lua_State* l);
#ifdef __cplusplus
}
#endif
#endif
--------------------------------------------------
luadllsample.cpp
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "mylua_base.h"
#include "luadllsample.h"
LUADLLSAMPLE_API int func_sample(lua_State* l)
{
printf("kita!!!!!\n");
return 123;
}
--------------------------------------------------
test.lua
--------------------------------------------------
f=package.loadlib("luadll_sample.dll","func_sample")
f()
--------------------------------------------------
こんだけでプラグインができるなんて。
とても簡単にプラグインを作れます。
でもこれだとビルド時にliblua.dllがいるので、ビルド時にliblua.dllがいらない版も作ってみました。
これで、ばんばんtorchのプラグインが作れる。
mylua_base.h
--------------------------------------------------
#ifndef MY_LUA_BASE_H_
#define MY_LUA_BASE_H_
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern lua_State *(*p_luaL_newstate) (void);
extern void(*p_luaL_openlibs)(lua_State *L);
extern int(*p_luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
extern void(*p_lua_close)(lua_State *L);
extern void(*p_lua_pushcclosure)(lua_State *L, lua_CFunction fn, int n);
extern void(*p_lua_setglobal)(lua_State *L, const char *name);
extern int(*p_lua_pcallk)(lua_State *L, int nargs, int nresults, int errfunc,
lua_KContext ctx, lua_KFunction k);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#define luaL_newstate p_luaL_newstate
#define luaL_openlibs p_luaL_openlibs
#define luaL_loadfilex p_luaL_loadfilex
#define lua_close p_lua_close
#define lua_pushcclosure p_lua_pushcclosure
#define lua_setglobal p_lua_setglobal
#define lua_pcallk p_lua_pcallk
#endif
--------------------------------------------------
mylua_base.cpp
--------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "mylua_base_min.h"
#include "dll_client.h"
#define LUA_SO_NAME "liblua"
// api function
lua_State *(*p_luaL_newstate) (void) = NULL;
void(*p_luaL_openlibs)(lua_State *L) = NULL;
void(*p_lua_close)(lua_State *L) = NULL;
int(*p_luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode) = NULL;
void(*p_lua_pushcclosure)(lua_State *L, lua_CFunction fn, int n) = NULL;
void(*p_lua_setglobal)(lua_State *L, const char *name) = NULL;
int(*p_lua_pcallk)(lua_State *L, int nargs, int nresults, int errfunc,
lua_KContext ctx, lua_KFunction k) = NULL;
// init
class myluabase_init {
public:
myluabase_init();
virtual ~myluabase_init();
};
static myluabase_init mi;
static void* osh = NULL;
myluabase_init::myluabase_init()
{
osh = dll_load(DLL_NAME(LUA_SO_NAME));
if (osh == NULL)printf("liblua dll_load error\n");
p_luaL_newstate = (lua_State *(*) (void))dll_access(osh, "luaL_newstate");
if (p_luaL_newstate == NULL)printf("luaL_newstate dll_access error\n");
p_luaL_openlibs = (void(*)(lua_State *))dll_access(osh, "luaL_openlibs");
if (p_luaL_openlibs == NULL)printf("luaL_openlibs dll_access error\n");
p_lua_close = (void(*)(lua_State *))dll_access(osh, "lua_close");
if (p_lua_close == NULL)printf("lua_close dll_access error\n");
p_luaL_loadfilex = (int(*) (lua_State *, const char *,const char *))dll_access(osh, "luaL_loadfilex");
if (p_luaL_loadfilex == NULL)printf("luaL_loadfilex dll_access error\n");
p_lua_pushcclosure = (void(*)(lua_State *, lua_CFunction, int))dll_access(osh, "lua_pushcclosure");
if (p_lua_pushcclosure == NULL)printf("lua_pushcclosure dll_access error\n");
p_lua_setglobal = (void(*)(lua_State *, const char *))dll_access(osh, "lua_setglobal");
if (p_lua_setglobal == NULL)printf("lua_setglobal dll_access error\n");
p_lua_pcallk = (int(*)(lua_State *, int, int, int,lua_KContext,lua_KFunction))dll_access(osh, "lua_pcallk");
if (p_lua_pcallk == NULL)printf("lua_pcallk dll_access error\n");
}
myluabase_init::~myluabase_init()
{
if (osh) {
dll_close(osh);
}
osh = NULL;
}
--------------------------------------------------
dll_client.h
--------------------------------------------------
#ifndef _DLL_CLIENT_H_
#define _DLL_CLIENT_H_
#define _DLL_CLIENT_H_VER "20130701"
#define LIB_OK 0
#define LIB_ERR_INVALID_REQUEST (-1)
#define LIB_ERR_INVALID_PARAMETER (-2)
#define LIB_ERR_NOSERVICE (-3)
#define LIB_ERR_NOREQUEST (-4)
#if defined(_WIN32) && !defined(__GNUC__)
#define LIBEXT ".dll"
#else
#define LIBEXT ".so"
#endif
#define DLL_NAME(a) a LIBEXT
#ifdef __cplusplus
extern "C"{
#endif
void *dll_load(char *dllname);
void *dll_access(void *pDllmod, char *funcname);
void dll_close(void *pDllmod);
#ifdef __cplusplus
}
#endif
#endif
--------------------------------------------------
dll_client.c
--------------------------------------------------
#include <stdio.h>
#ifdef WIN32 /* For Windows */
#include <windows.h>
#endif
#include "dll_client.h"
#ifdef ERR_PRINT
#define EPRINT(a) fprintf(stderr,a)
#define EPRINT2(a,b) fprintf(stderr,a,b)
#else
#define EPRINT(a) do; while(0)
#define EPRINT2(a,b) do; while(0)
#endif
void *dll_load(char *dllname)
{
void *pFunclib=NULL;
if(dllname==NULL) {
EPRINT("### dllname is NULL\n");
return NULL;
}
#ifdef _WIN32
pFunclib = LoadLibraryA(dllname);
#endif
#if defined(unix) || defined(__APPLE__)
pFunclib = dlopen(dllname, RTLD_LAZY);
#endif
if(!pFunclib) {
EPRINT2("### cannot dll_load >%s<\n",dllname);
}
return pFunclib;
}
void *dll_access(void *pDllmod, char *funcname)
{
void *pDll_func=NULL;
if(pDllmod==NULL) {
EPRINT("### dll_access handle is NULL\n");
return NULL;
}
if(funcname==NULL) {
EPRINT("### dll_access funcname is NULL\n");
return NULL;
}
#ifdef _WIN32
pDll_func = GetProcAddress((HMODULE)pDllmod, funcname);
#endif
#if defined(unix) || defined(__APPLE__)
pDll_func = dlsym(pDllmod, funcname);
#endif
if(!pDll_func) {
EPRINT2("### cannot dll_access >%s<\n",funcname);
}
return pDll_func;
}
void dll_close(void *pDllmod)
{
if(pDllmod==NULL)return;
#ifdef _WIN32
FreeLibrary(pDllmod);
#endif
#if defined(unix) || defined(__APPLE__)
dlclose(pDllmod);
#endif
return;
}
--------------------------------------------------
いろんなBLASを使ってみた
最近はやっているディープラーニング、大体Pythonで書かれています。
Pythonだけでは行列の計算が貧弱なので、numpyというライブラリを使って行列の計算をしいます。
さらにnumpyは行列計算をBLAS(Basic Linear Algebra Subprograms)というライブラリで行っています。
以前このブログでも触れたのですが、このBLASは1979年に作られたため、その後いろいろな人が改良していろいろなBLASがあります。
しかもオリジナルはFORTRANという言語で書かれていて、最新のディープラーニングは半世紀も前のプログラムに支えられています。
組み込みで使いたいときはどうすればよいのかと思い、これらの半世紀前のプログラムをいろいろビルドしてみました。
1. reference BLASのビルド
オリジナルのBLASです。LAPACKというBLASの拡張もあります。
Fortanで書かれています。以前この日記にも書きました。
・まずf2cというFORTRANからC言語に変換するプログラムをまずビルドします。
を
・次にlibf2cというライブラリをビルドして、FORTRANの複素数型や高度な数学関数をビルドします。
・fc2でBLASとXBLASとLAPACKのFORTRANソースコードをC言語に変換してビルドします。
・CBLASとCLAPACKのラッパー関数もビルドします。
とってもめんどくさいんですが、半世紀前のソースコードがWindows10とVisualStudio2019でビルドできます。
2. OpenBLASのビルド
現在一番使われているBLASです。
マルチスレッド化してあるので、CPUのコア数が増えれば増えるほど高速に演算できます。
大部分がC言語で書かれていますが、高速化のため一部がアセンブラとフォートランで書かれています。このため、その特定の部分をVisualCなどでコンパイルできません。
このため、Windowsではなかなか手軽に遊べず。
しかしMinGWなどでコンパイルすればWindows版も作れます。
高速動作に命を懸けているので、コンパイラーに依存しています。
アセンブラ部分をなくてもビルドを通るようにしてくれればよいのに。
LAPACKというライブラリ部分はGFORTRANを使うので、GFORTRANがない場合はLAPACKがコンパイルされません。
ファイル数が1000個以上あるのでコンパイルに非常に時間がかかります。
3 GSL BLASのビルド
GNU Science Libraryの中に入っているBLASです。
LAPACKは入っていませんがC言語で書かれていて一番簡単にビルドできます。
テストコードも簡単にビルドできるので、Windows10のVisualStudio2019でもビルドできてテストにパスしました。
4 Eigen BLAS
Googleが機械学習用に作っている行列演算ライブラリEigenの中に入っています。
BLASはほぼ全関数、LAPACKは一部の関数が入っています。
一番ファイル数が少なくビルドも高速。
一番まともですごいのになんで全関数ないんだ。
ということで、BLASを組み込みや勉強で使うときはEigenかGSL BLASがよさそうです。
Torchなどの機械学習の学習で使うときはフルのLAPACKが必要でEigenが使えません。
なのでOpenBLASかGPU対応のcuDNNじゃないとだめですね。
Pythonだけでは行列の計算が貧弱なので、numpyというライブラリを使って行列の計算をしいます。
さらにnumpyは行列計算をBLAS(Basic Linear Algebra Subprograms)というライブラリで行っています。
以前このブログでも触れたのですが、このBLASは1979年に作られたため、その後いろいろな人が改良していろいろなBLASがあります。
しかもオリジナルはFORTRANという言語で書かれていて、最新のディープラーニングは半世紀も前のプログラムに支えられています。
組み込みで使いたいときはどうすればよいのかと思い、これらの半世紀前のプログラムをいろいろビルドしてみました。
1. reference BLASのビルド
オリジナルのBLASです。LAPACKというBLASの拡張もあります。
Fortanで書かれています。以前この日記にも書きました。
・まずf2cというFORTRANからC言語に変換するプログラムをまずビルドします。
を
・次にlibf2cというライブラリをビルドして、FORTRANの複素数型や高度な数学関数をビルドします。
・fc2でBLASとXBLASとLAPACKのFORTRANソースコードをC言語に変換してビルドします。
・CBLASとCLAPACKのラッパー関数もビルドします。
とってもめんどくさいんですが、半世紀前のソースコードがWindows10とVisualStudio2019でビルドできます。
2. OpenBLASのビルド
現在一番使われているBLASです。
マルチスレッド化してあるので、CPUのコア数が増えれば増えるほど高速に演算できます。
大部分がC言語で書かれていますが、高速化のため一部がアセンブラとフォートランで書かれています。このため、その特定の部分をVisualCなどでコンパイルできません。
このため、Windowsではなかなか手軽に遊べず。
しかしMinGWなどでコンパイルすればWindows版も作れます。
高速動作に命を懸けているので、コンパイラーに依存しています。
アセンブラ部分をなくてもビルドを通るようにしてくれればよいのに。
LAPACKというライブラリ部分はGFORTRANを使うので、GFORTRANがない場合はLAPACKがコンパイルされません。
ファイル数が1000個以上あるのでコンパイルに非常に時間がかかります。
3 GSL BLASのビルド
GNU Science Libraryの中に入っているBLASです。
LAPACKは入っていませんがC言語で書かれていて一番簡単にビルドできます。
テストコードも簡単にビルドできるので、Windows10のVisualStudio2019でもビルドできてテストにパスしました。
4 Eigen BLAS
Googleが機械学習用に作っている行列演算ライブラリEigenの中に入っています。
BLASはほぼ全関数、LAPACKは一部の関数が入っています。
一番ファイル数が少なくビルドも高速。
一番まともですごいのになんで全関数ないんだ。
ということで、BLASを組み込みや勉強で使うときはEigenかGSL BLASがよさそうです。
Torchなどの機械学習の学習で使うときはフルのLAPACKが必要でEigenが使えません。
なのでOpenBLASかGPU対応のcuDNNじゃないとだめですね。
2019年2月28日木曜日
天下一品のマークを誤認識させてみた。
おじさん、この前ネットで、ホンダの車は天下一品のマークを進入禁止マークと誤認識する記事を読みました。
https://togetter.com/li/1266643
https://ikikuru.com/entertainment/22551/
これ本当に起きるのでしょうか?
もし、本当におきるのであれば、おじさん、この誤認識プログラムも作れる!
やっぱ、技術の平和利用って大切だしなぁ。
という世界平和を願う気持ちを抱きながら、天下一品マークを誤認識するかどうかをたしかめる標識認識プログラムを作ってみました。
まず、前回と同じようにその辺のネットに落ちているOpenCVの標識認識の学習済みデータを持ってきます。
だけど、日本の進入禁止の学習済みデータなんて公開されていない・・・・。
だれか作って公開してくれないかなぁ。
日本の自動車メーカーとかも学習データを無料で公開してくれるくらいの気持ちがないと自動運転作れないと思うんだよなぁ。
こまったなぁ。
でもアメリカの速度制限の標識が似てるからそれで試してみよう!
ということで、ここのサイトから速度制限の標識学習データを取ってきます。
https://github.com/cfizette/road-sign-cascades
このデータ、メロン大学の学生が作ってる?んだ。
このメロン大学の貴重な研究成果を利用して、本当にくだならい天下一品のマークを誤認識させてみます。
プログラムは以前書いた、信号認識と全く同じ。
ただ学習済みデータと入力画像を変えるだけです。
よし、これで準備万端。実験してみました。
この画像を標識認識させてみます。
やっぱり天下一品のマークは道路標識とにているのか。
-------------------------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
int main()
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
//load image
p = stbi_load("stop3.jpg", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat gray;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, gray, CV_BGR2GRAY);
//cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("stopsign_classifier.xml");
//cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("Stopsign_HAAR_19Stages.xml");
cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("Speedlimit_24_15Stages.xml");
vector<cv::Rect> shingou;
SS_cascade.detectMultiScale(gray, shingou, 1.01, 1);
//SS_cascade.detectMultiScale(gray, shingou, 1.3, 1);
for (auto it = shingou.begin(); it != shingou.end(); it++) {
printf("kita!!\n");
cv::rectangle(color, it->tl(), it->br(), cv::Scalar(0, 255, 0), 1, 8, 0);
}
changeb_g(color.data, x, y, 4);
stbi_write_png("result.png", x, y, 4, color.data, 4 * x);
return 0;
}
-------------------------------
ということで、標識認識プログラムは天下一品のマークを道路標識として誤認識します。
https://togetter.com/li/1266643
https://ikikuru.com/entertainment/22551/
これ本当に起きるのでしょうか?
もし、本当におきるのであれば、おじさん、この誤認識プログラムも作れる!
やっぱ、技術の平和利用って大切だしなぁ。
という世界平和を願う気持ちを抱きながら、天下一品マークを誤認識するかどうかをたしかめる標識認識プログラムを作ってみました。
まず、前回と同じようにその辺のネットに落ちているOpenCVの標識認識の学習済みデータを持ってきます。
だけど、日本の進入禁止の学習済みデータなんて公開されていない・・・・。
だれか作って公開してくれないかなぁ。
日本の自動車メーカーとかも学習データを無料で公開してくれるくらいの気持ちがないと自動運転作れないと思うんだよなぁ。
こまったなぁ。
でもアメリカの速度制限の標識が似てるからそれで試してみよう!
ということで、ここのサイトから速度制限の標識学習データを取ってきます。
https://github.com/cfizette/road-sign-cascades
このデータ、メロン大学の学生が作ってる?んだ。
このメロン大学の貴重な研究成果を利用して、本当にくだならい天下一品のマークを誤認識させてみます。
プログラムは以前書いた、信号認識と全く同じ。
ただ学習済みデータと入力画像を変えるだけです。
よし、これで準備万端。実験してみました。
この画像を標識認識させてみます。
やっぱり天下一品のマークは道路標識とにているのか。
-------------------------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
int main()
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
//load image
p = stbi_load("stop3.jpg", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat gray;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, gray, CV_BGR2GRAY);
//cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("stopsign_classifier.xml");
//cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("Stopsign_HAAR_19Stages.xml");
cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("Speedlimit_24_15Stages.xml");
vector<cv::Rect> shingou;
SS_cascade.detectMultiScale(gray, shingou, 1.01, 1);
//SS_cascade.detectMultiScale(gray, shingou, 1.3, 1);
for (auto it = shingou.begin(); it != shingou.end(); it++) {
printf("kita!!\n");
cv::rectangle(color, it->tl(), it->br(), cv::Scalar(0, 255, 0), 1, 8, 0);
}
changeb_g(color.data, x, y, 4);
stbi_write_png("result.png", x, y, 4, color.data, 4 * x);
return 0;
}
-------------------------------
ということで、標識認識プログラムは天下一品のマークを道路標識として誤認識します。
信号機が何色かを判別してみた。
おじさん、老後の趣味の一つで勝手に自動運転の仕組みを勉強しています。
自動運転って仕組みを一つ一つ理解していけばいつかできそうですね。
前回は信号機自体がどこにあるのかを認識しました。
信号機までの距離は認識した信号機の大きさでたぶんわかるので省略。
今回はその認識した信号の色を調べます。
信号の色ってどうやってプログラムで識別するんだろう。
いろいろ調べてみると、どうやら色空間をHSVに変換して、HSV空間の特定の領域に入っているかどうかを調べればよいみたいです。
映画やテレビでよく使われているクロマキーとかと同じ手法ですね。
特定の色のところだけを抜き出して、その割合でその色があるかどうか判別します。
https://algorithm.joho.info/programming/python/opencv-color-tracking-py/
こんなかんじです。
1.前回認識した信号機の部分
3.黄色の部分をマスク
4.緑の部分をマスク
HSV空間の特定の領域にある部分だけをマスクすると、このように信号機が緑色であることがわかります。作るのもとっても簡単。
--------------------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
static double calc_mask(unsigned char* buf, int x, int y, int s)
{
int i, c;
int ct = 0;
double d;
c = x*y;
for (i = 0; i < c; i++) {
if (*buf >= 128)ct++;
buf += s;
}
d = (double)ct / (double)c*100.0;
//printf("ct=%d c=%d %f\n",ct,c,d);
return d;
}
int get_traffic_light_color(const char* fn)
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
double dr, dg, dy;
//load image
p = stbi_load(fn, &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 0;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat hsv;
cv::Mat mask_r1, mask_r2, mask_r, color_r;
cv::Mat mask_g, color_g;
cv::Mat mask_y, color_y;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, hsv, CV_BGR2HSV);
//r
cv::inRange(hsv, cv::Scalar(0, 128, 0), cv::Scalar(10, 255, 255), mask_r1);
cv::inRange(hsv, cv::Scalar(150, 128, 0), cv::Scalar(179, 255, 255), mask_r2);
cv::bitwise_or(mask_r1, mask_r2, mask_r);
cv::cvtColor(mask_r, color_r, CV_GRAY2RGBA);
stbi_write_png("result_r.png", x, y, 4, color_r.data, 4 * x);
dr=calc_mask(color_r.data, x, y, 4);
//printf("red=%f\n", dr);
//y
cv::inRange(hsv, cv::Scalar(10, 64, 0), cv::Scalar(40, 255, 255), mask_y);
cv::cvtColor(mask_y, color_y, CV_GRAY2RGBA);
stbi_write_png("result_y.png", x, y, 4, color_y.data, 4 * x);
dy = calc_mask(color_y.data, x, y, 4);
//printf("yellow=%f\n", dy);
//g
cv::inRange(hsv, cv::Scalar(40, 128, 0), cv::Scalar(100, 255, 255), mask_g);
cv::cvtColor(mask_g, color_g, CV_GRAY2RGBA);
stbi_write_png("result_g.png", x, y, 4, color_g.data, 4 * x);
dg = calc_mask(color_g.data, x, y, 4);
//printf("green=%f\n", dg);
if (dr >= dy && dr >= dg)return 1; //red
if (dy >= dr && dy >= dg)return 2; //yellow
if (dg >= dy && dg >= dr)return 3; //green
return 0;
}
int main()
{
unsigned char*p;
int i;
int color;
char* fn_list[] = {
"red1.jpg",
"yellow1.jpg",
"green1.jpg",
"green2.jpg",
NULL
};
char* color_list[] =
{
"black",
"red",
"yellow",
"green",
};
for (i = 0; i < 10000; i++) {
if (fn_list[i] == NULL)break;
color = get_traffic_light_color(fn_list[i]);
printf("color=%s file=%s \n",color_list[color],fn_list[i]);
}
return 0;
}
--------------------------
自動運転って仕組みを一つ一つ理解していけばいつかできそうですね。
前回は信号機自体がどこにあるのかを認識しました。
信号機までの距離は認識した信号機の大きさでたぶんわかるので省略。
今回はその認識した信号の色を調べます。
信号の色ってどうやってプログラムで識別するんだろう。
いろいろ調べてみると、どうやら色空間をHSVに変換して、HSV空間の特定の領域に入っているかどうかを調べればよいみたいです。
映画やテレビでよく使われているクロマキーとかと同じ手法ですね。
特定の色のところだけを抜き出して、その割合でその色があるかどうか判別します。
https://algorithm.joho.info/programming/python/opencv-color-tracking-py/
信号機の色判別なんてどこにもソースコードがないので今回上のサイトをもとに自分でごりごり書きます。
1.前回認識した信号機の部分
2.赤色の部分をマスク
3.黄色の部分をマスク
4.緑の部分をマスク
HSV空間の特定の領域にある部分だけをマスクすると、このように信号機が緑色であることがわかります。作るのもとっても簡単。
--------------------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
static double calc_mask(unsigned char* buf, int x, int y, int s)
{
int i, c;
int ct = 0;
double d;
c = x*y;
for (i = 0; i < c; i++) {
if (*buf >= 128)ct++;
buf += s;
}
d = (double)ct / (double)c*100.0;
//printf("ct=%d c=%d %f\n",ct,c,d);
return d;
}
int get_traffic_light_color(const char* fn)
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
double dr, dg, dy;
//load image
p = stbi_load(fn, &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 0;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat hsv;
cv::Mat mask_r1, mask_r2, mask_r, color_r;
cv::Mat mask_g, color_g;
cv::Mat mask_y, color_y;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, hsv, CV_BGR2HSV);
//r
cv::inRange(hsv, cv::Scalar(0, 128, 0), cv::Scalar(10, 255, 255), mask_r1);
cv::inRange(hsv, cv::Scalar(150, 128, 0), cv::Scalar(179, 255, 255), mask_r2);
cv::bitwise_or(mask_r1, mask_r2, mask_r);
cv::cvtColor(mask_r, color_r, CV_GRAY2RGBA);
stbi_write_png("result_r.png", x, y, 4, color_r.data, 4 * x);
dr=calc_mask(color_r.data, x, y, 4);
//printf("red=%f\n", dr);
//y
cv::inRange(hsv, cv::Scalar(10, 64, 0), cv::Scalar(40, 255, 255), mask_y);
cv::cvtColor(mask_y, color_y, CV_GRAY2RGBA);
stbi_write_png("result_y.png", x, y, 4, color_y.data, 4 * x);
dy = calc_mask(color_y.data, x, y, 4);
//printf("yellow=%f\n", dy);
//g
cv::inRange(hsv, cv::Scalar(40, 128, 0), cv::Scalar(100, 255, 255), mask_g);
cv::cvtColor(mask_g, color_g, CV_GRAY2RGBA);
stbi_write_png("result_g.png", x, y, 4, color_g.data, 4 * x);
dg = calc_mask(color_g.data, x, y, 4);
//printf("green=%f\n", dg);
if (dr >= dy && dr >= dg)return 1; //red
if (dy >= dr && dy >= dg)return 2; //yellow
if (dg >= dy && dg >= dr)return 3; //green
return 0;
}
int main()
{
unsigned char*p;
int i;
int color;
char* fn_list[] = {
"red1.jpg",
"yellow1.jpg",
"green1.jpg",
"green2.jpg",
NULL
};
char* color_list[] =
{
"black",
"red",
"yellow",
"green",
};
for (i = 0; i < 10000; i++) {
if (fn_list[i] == NULL)break;
color = get_traffic_light_color(fn_list[i]);
printf("color=%s file=%s \n",color_list[color],fn_list[i]);
}
return 0;
}
--------------------------
信号機の色判別できた!
2019年2月27日水曜日
信号機認識をやってみた。
おじさん、前回は歩行者認識をやったので、今回は調子に乗って信号機認識をやってみたいと思います。
信号機認識ってどうやってやるんだろうね。
信号機認識,OpenCVとかで検索しても全くソースコードが出てきません。
なんてこった。これじゃあコピペで作れないじゃん。
日本人で作ってるひとあまりいないのね。
検索で出てこないってことは難しいんだ・・・。
でもわかったことは、歩行者認識のようにOpenCVにデフォルトで入っているDetectorを使う場合はなにもいらないのですが、信号機認識のようにOpenCVにデフォルトで入っていDetectorを使う場合は、学習済みデータを作るかどこからか取ってこないといけないようです。
なので英語でtraffic,light,detection,opencvと検索してネットで落ちているそれっぽいOpenCVの学習済みデータを取ってきます。
https://github.com/D-KG5/opencv
https://github.com/swaroopbelur/Traffic-Signal-Detection
きっとこのへんのデータを使えば信号機認識できるはず。
というわけでこの学習データで信号機認識をさせてみました。
おー本当に認識できんじゃん。
だけどここまでたどり着くのにかなり時間がかかてしまいました。
これほんとうに学習させるのが難しくて、日本の信号機とか他の地域の信号機はまず認識することはありません。
このようにきちんと認識できる写真を探し出すのにかなり苦労します。
この結果のあとに色識別を行うと信号機の色がわかるっぽいです。
色識別はまた別の会に書きたいと思います。
--------------------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
int main()
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
//load image
p = stbi_load("shingo1.jpg", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat gray;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, gray, CV_BGR2GRAY);
//cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("traffic_light.xml");
cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("TrafficLight_HAAR_16Stages.xml");
vector<cv::Rect> shingou;
SS_cascade.detectMultiScale(gray,shingou, 1.1, 1);
for (auto it = shingou.begin(); it != shingou.end(); it++){
printf("kita!!\n");
cv::rectangle(color,it->tl(),it->br(),cv::Scalar(0,255,0),1,8,0);
}
changeb_g(color.data, x, y, 4);
stbi_write_png("result.png", x, y, 4, color.data, 4 * x);
return 0;
}
--------------------------
信号機認識ってどうやってやるんだろうね。
信号機認識,OpenCVとかで検索しても全くソースコードが出てきません。
なんてこった。これじゃあコピペで作れないじゃん。
日本人で作ってるひとあまりいないのね。
検索で出てこないってことは難しいんだ・・・。
でもわかったことは、歩行者認識のようにOpenCVにデフォルトで入っているDetectorを使う場合はなにもいらないのですが、信号機認識のようにOpenCVにデフォルトで入っていDetectorを使う場合は、学習済みデータを作るかどこからか取ってこないといけないようです。
なので英語でtraffic,light,detection,opencvと検索してネットで落ちているそれっぽいOpenCVの学習済みデータを取ってきます。
https://github.com/D-KG5/opencv
https://github.com/swaroopbelur/Traffic-Signal-Detection
きっとこのへんのデータを使えば信号機認識できるはず。
というわけでこの学習データで信号機認識をさせてみました。
おー本当に認識できんじゃん。
だけどここまでたどり着くのにかなり時間がかかてしまいました。
これほんとうに学習させるのが難しくて、日本の信号機とか他の地域の信号機はまず認識することはありません。
このようにきちんと認識できる写真を探し出すのにかなり苦労します。
この結果のあとに色識別を行うと信号機の色がわかるっぽいです。
色識別はまた別の会に書きたいと思います。
--------------------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
int main()
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
//load image
p = stbi_load("shingo1.jpg", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat gray;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, gray, CV_BGR2GRAY);
//cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("traffic_light.xml");
cv::CascadeClassifier SS_cascade = cv::CascadeClassifier("TrafficLight_HAAR_16Stages.xml");
vector<cv::Rect> shingou;
SS_cascade.detectMultiScale(gray,shingou, 1.1, 1);
for (auto it = shingou.begin(); it != shingou.end(); it++){
printf("kita!!\n");
cv::rectangle(color,it->tl(),it->br(),cv::Scalar(0,255,0),1,8,0);
}
changeb_g(color.data, x, y, 4);
stbi_write_png("result.png", x, y, 4, color.data, 4 * x);
return 0;
}
--------------------------
2019年2月25日月曜日
歩行者認識をやってみた。
ずっと忙しくして、ブログを更新するのを忘れてました。
最近ちょっと暇になったので久しぶりにブログを更新。
おじさん、この前、防犯カメラを作っている会社に会社見学行ってきました。
最近の防犯カメラってすごいね。カメラの画像から人がどこにいるかわかるらしい。
車の自動運転のデモでもよくみかけますね。
昔このブログで歩行者認識やりますといって書いてなかった気もします。
あれどうやってんだろね。
調べてみるとなんかHOGとかで特徴検出してSVMで学習させてるらしい。
これならおじさんのラズパイでも作れる!
というわけで、作ってみました。
いつものようにラズパイとかでも動くように、C++言語で実装。
以前ブログで書いた、OpenCVのライブラリから必要な部分だけを抜き出して最小のOpenCVで実装しています。
ねっとに落っこちている適当な画像で試してみました。
歩行者以外も検出しまくり!!
どうもパラメーター調整をしないと誤検出してしまうようです。
みんないい結果だけ乗せるんだから。
-------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
int main()
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
//load image
//p = stbi_load("dave.jpg", &x, &y, &n, 4);
p = stbi_load("test.jpg", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat gray;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, gray, CV_BGR2GRAY);
cv::HOGDescriptor hog = cv::HOGDescriptor(cv::Size(48, 96), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9);
hog.setSVMDetector(hog.getDaimlerPeopleDetector());
vector<cv::Rect> people;
hog.detectMultiScale(gray, people);
for (auto it = people.begin(); it != people.end(); it++){
cv::rectangle(color,it->tl(),it->br(),cv::Scalar(0,255,0),1,8,0);
}
//for (i = 0; i < n; i++){
// cv::line(color, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(0, 0, 255), 2);
//}
changeb_g(color.data, x, y, 4);
stbi_write_png("result.png", x, y, 4, color.data, 4 * x);
return 0;
}
-------------
というわけで簡単な歩行者検出でした。
最近ちょっと暇になったので久しぶりにブログを更新。
おじさん、この前、防犯カメラを作っている会社に会社見学行ってきました。
最近の防犯カメラってすごいね。カメラの画像から人がどこにいるかわかるらしい。
車の自動運転のデモでもよくみかけますね。
昔このブログで歩行者認識やりますといって書いてなかった気もします。
あれどうやってんだろね。
調べてみるとなんかHOGとかで特徴検出してSVMで学習させてるらしい。
これならおじさんのラズパイでも作れる!
というわけで、作ってみました。
いつものようにラズパイとかでも動くように、C++言語で実装。
以前ブログで書いた、OpenCVのライブラリから必要な部分だけを抜き出して最小のOpenCVで実装しています。
ねっとに落っこちている適当な画像で試してみました。
歩行者以外も検出しまくり!!
どうもパラメーター調整をしないと誤検出してしまうようです。
みんないい結果だけ乗せるんだから。
-------------
#include <stdio.h>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "core.hpp"
#include "imgproc.hpp"
#include "objdetect.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
#define X_DIV 10
#define Y_DIV 10
using namespace std;
void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}
int main()
{
unsigned char*p;
int x = -1, y = -1;
int n, m;
int i;
//load image
//p = stbi_load("dave.jpg", &x, &y, &n, 4);
p = stbi_load("test.jpg", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
// R<-->B
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
cv::Mat gray;
//copy data
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
cv::cvtColor(color, gray, CV_BGR2GRAY);
cv::HOGDescriptor hog = cv::HOGDescriptor(cv::Size(48, 96), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9);
hog.setSVMDetector(hog.getDaimlerPeopleDetector());
vector<cv::Rect> people;
hog.detectMultiScale(gray, people);
for (auto it = people.begin(); it != people.end(); it++){
cv::rectangle(color,it->tl(),it->br(),cv::Scalar(0,255,0),1,8,0);
}
//for (i = 0; i < n; i++){
// cv::line(color, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(0, 0, 255), 2);
//}
changeb_g(color.data, x, y, 4);
stbi_write_png("result.png", x, y, 4, color.data, 4 * x);
return 0;
}
-------------
登録:
投稿 (Atom)












