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;
}


-------------------------------
ということで、標識認識プログラムは天下一品のマークを道路標識として誤認識します。


信号機が何色かを判別してみた。

おじさん、老後の趣味の一つで勝手に自動運転の仕組みを勉強しています。
自動運転って仕組みを一つ一つ理解していけばいつかできそうですね。

前回は信号機自体がどこにあるのかを認識しました。
信号機までの距離は認識した信号機の大きさでたぶんわかるので省略。
今回はその認識した信号の色を調べます。

信号の色ってどうやってプログラムで識別するんだろう。
いろいろ調べてみると、どうやら色空間を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;
}

--------------------------



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;
}



-------------

というわけで簡単な歩行者検出でした。