視覚信号処理III深さ学習練習


深く勉強する.


ニューラルネットワークと深い学習


深さ学習(deep learning)は2000年代から使用されている深層ニューラルネットワーク(deep neural network)のもう一つの名前である.
ニューラルネットワークは人工ニューラルネットワークとも呼ばれる
これはヒト脳神経細胞(neuron)の反応をモデリングすることによって生じる古典的な機械学習アルゴリズムである.
深さ学習はニューラルネットワークを多層に積層する機械学習アルゴリズムである.
コンピュータ視覚の分野で、深さ学習技術が広く注目されているのは、オブジェクト識別、顔認識、オブジェクト検出、分割などの多くの分野での応用が、従来のコンピュータ視覚に基づく技術よりも高い性能を持っているからである.

OpenCV DNモジュール


OpenCV dnnモジュールは、作成されたネットワーク上で双方向に動作するように設計されています.
深さ学習は、伝統的な有名なカフェ(Caffe)やテンセントフロー(TensorFlow)など、他の深さ学習フレームワークで行われる.
学習モデルを読み込み、実行するときにdnnモジュールを使用します.
多くの深い学習フレームワークはPython言語を使用していますが、OpenCV dnnモジュールはC/C++環境で実行できるため、プログラムの移植性が高いという利点があります.
OpenCV 3.1は他のモジュール形式のdnnモジュールをサポートし、OpenCV 3.3バージョンから基本モジュールに含まれる
OpenCV dnnモジュールは広く使用されている深度学習ネットワーク構成をサポートする
最近新しく開発された深い学習ネットワークを引き続きサポート
OpenCVで、AlexNet、GoogLeNet、VGG、ResNet、SquezeNet、DeseNet、SheffleeNet、MobileNet、Darknetなどのビデオ認識に関連するネットワークが実行されていることを確認しました.
対象検出には、VG SSD、MobileNet-SD、Faster RCN、R-FCN、OpenCV顔検出、Mask-CN、EAST、YOLOv 2、Tiny YOLO、YOLOv 3等を使用することができる.
また、OpenPoseは人の姿勢を認識し、白黒ビデオは自動的に着色し、OpenFaceなどのモデルもOpenCV dnnモジュールで使用することができる.
frameworkパラメータは、モデルファイルを作成するための深さ学習フレームワークの名前を指定します.
modelまたはconfigファイル拡張子でフレームワークを区別できる場合はframeworkパラメータを省略できます
表16-1は、modelおよびconfigパラメータに指定できるファイル拡張子およびフレームワークのフレームワーク名を示す

MNIST手書きデジタル認識


手書きデジタル認識


深さ学習の分野では,主にMNISTデータセットを用いて手書きデジタル識別訓練を行った.
MNISTは、ニューヨーク大学の楊楽坤(ヤン・レゴン)教授が郵便番号などの手書き数字を識別するために使用したデータのセットで、6万個の訓練ビデオと1万個のテストビデオから構成されている.
各デジタルビデオは28×28個のサイズで構成され、画素値は0〜1の実数値で正規化される.
ラーニングTensor Flowのmnist_cnn.pbファイルを読み込みネットワークを作成
ユーザがマウスで描画した手書きデジタルビデオをネットワーク入力に転送することで結果を予測する
プログラムが初めて実行されると、画面に黒で初期化されたimgビデオが表示されます.
上でマウスの左ボタンを押して数字を描き、スペースボタンを押して認識結果をコンソールウィンドウに出力します.
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::dnn;

void on_mouse(int event, int x, int y, int flags, void* userdata); 

int main()
{
	Net net = readNet("mnist_cnn.pb");

	if (net.empty())
	{
		cerr << "Network load failed!" << endl;
		return -1;
	}

	Mat img = Mat::zeros(400, 400, CV_8UC1);

	imshow("img", img);
	setMouseCallback("img", on_mouse, (void*)&img);

	while (true)
	{
		int c = waitKey(0);

		if (c == 27)
		{
			break;
		}
		else if (c == ' ')
		{
			Mat blob = blobFromImage(img, 1 / 255.f, Size(28, 28));
			net.setInput(blob);
			Mat prob = net.forward();

			double maxVal;
			Point maxLoc;
			minMaxLoc(prob, NULL, &maxVal, NULL, &maxLoc);
			int digit = maxLoc.x;

			cout << digit << " (" << maxVal * 100 << "%)" << endl;

			img.setTo(0);
			imshow("img", img);
		}
	}
	return 0;
}

Point ptPrev(-1, -1);

void on_mouse(int event, int x, int y, int flags, void* userdata) //마우스 이벤트 조작
{
	Mat img = *(Mat*)userdata;

	if (event == EVENT_LBUTTONDOWN)
	{
		ptPrev = Point(x, y);
	}
	else if (event == EVENT_LBUTTONUP)
	{
		ptPrev = Point(-1, -1);
	}
	else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
	{
		line(img, ptPrev, Point(x, y), Scalar::all(255), 40, LINE_AA, 0);
		ptPrev = Point(x, y);

		imshow("img", img);
	}
}
コードを作成するときは、マウスの左ボタンを押して数字を描き、スペースボタンを押して認識結果をコンソールウィンドウに出力します.以下のようにします.

精度が低い>過去のデータを使用しているため

Googleの動画認識


Googleの動画認識


深い学習がコンピュータの視覚分野で大きな発展を遂げたのは,ImageNet Large Scaleの可視化識別競争大会の影響も受けている.
ILSVVRCは、2010年から毎年行われているアルゴリズムコンテストで、ビデオ認識やオブジェクト検出などの性能を比較することを目的としています.
ILSVRCは大規模なビデオデータベースImageNetを使用
特に、ビデオ認識の分野では、100万以上のビデオ(1000カテゴリに分類)を使用してパフォーマンスを比較しています.
本大会では2012年のAlexNet深さ学習アルゴリズム
アルゴリズムよりも優れたパフォーマンス
コンピュータビジュアル分野で深い学習ブームを巻き起こした[Krizhevsky 12]
GoogleがGoogleのネットワーク構造を発表
2014年ILSVRCビデオ認識分野トップ[Szegedy 15]
グーグルネットは22階建て
これは、同時にパブリッシュされる深度学習ネットワーク構造で最も使用されるレイヤです.
層は深く設計されているが,完全な接続層がない構造が既存の他のネットワークのパラメータよりも少ないことを特徴とする.
Googleネットワークは、さまざまなサイズのカーネルを同時に使用してビデオから大きな特徴と小さな特徴を抽出するように特別に設計されています.

OpenCVでGoogle Net識別機能を使用するには、他の深い学習フレームワークを使用して事前にトレーニングしたモデルファイルとプロファイルが必要です.
官カレーフレームワークを使用して学習したGoogleネットワークモデルファイルは、次のリンクから入手できます.
http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel
カフェでトレーニングされたネットワーク構造を使用したプロファイルは、「モデルのメインハブ」ページから入手できます.
https://github.com/BVLC/caffe/blob/master/models/bvlc_googlenet/deploy.prototxt
Google Net識別機能を正しく実装するには、モデルファイルとプロファイルのほかに、識別されたビデオクラス名を持つテキストファイル(classification_classes_ILSVRC2012.txt)>ラベル名が必要です.
このファイルには、1行あたり1000個のビデオクラス名が含まれています.
Google Netサンプルプログラムを作成するために必要な3つのファイルを整理します.
学習モデルファイル:bvlc googlenet.caffemodel
プロファイル:deploy.prototxt
クラス名ファイル:classification class ILSVR C 2012.txt
ビデオに含まれるプライマリオブジェクトの特定
オブジェクト名と判定確率を文字列としてビデオに出力
#include "opencv2/opencv.hpp"
#include <iostream>
#include <fstream>

using namespace std;
using namespace cv;
using namespace cv::dnn;

int main(int argc, char* argv[])
{
	//load an image

	Mat img;

	if (argc < 2)
		img = imread("cats.jpg", IMREAD_COLOR);
	else
		img = imread(argv[1], IMREAD_COLOR);

	if (img.empty())
	{
		cerr << "image load failed!" << endl;
		return -1;
	}

	//load network

	Net net = readNet("bvlc_googlenet.caffemodel", "deploy.prototxt");

	if (net.empty())
	{
		cerr << "network load failed!" << endl;
		return -1;
	}

	//load class names
	ifstream fp("classification_classes_ILSVRC2012.txt");

	if (!fp.is_open())
	{
		cerr << "class file load failed!" << endl;
		return -1;
	}

	vector<String> classNames;
	string name;
	while (!fp.eof())
	{
		getline(fp, name);
		if (name.length())
			classNames.push_back(name);
	}

	fp.close();

	//inference

	Mat inputBlob = blobFromImage(img, 1, Size(224, 224), Scalar(104, 117, 123));
	net.setInput(inputBlob, "data");
	Mat prob = net.forward();

	//check results & display

	double maxVal;
	Point maxLoc;
	minMaxLoc(prob, NULL, &maxVal, NULL, &maxLoc);

	String str = format("%s (%4.2lf%%)", classNames[maxLoc.x].c_str(), maxVal * 100);
	putText(img, str, Point(10, 30), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 0, 255));
	imshow("img", img);

	waitKey();
	return 0;
}
上記のコードを実行すると、以下の結果が得られます.
一致する語は、グーグルで登録されている1000語の中で最も似たような語をもたらします.

ヤマネコ匹
ガタイロ山

SSD顔認識


SSD顔認識


download_weights.pyファイルはネット上から予め訓練された学習モデルファイルを取得し、顔検出に使用する.
download_weights.pyファイルはres 10 300 x 300 ssd iter 140000 fp 16です.caffemodelファイルと
opencv_face_detector_uint8.2つのpbファイルを取得
res10_300x300_ssd_iter_140000_fp16.CaffemodelファイルはCaffeフレームワークで訓練されたファイルです
opencv_face_detector_uint8.pbファイルはTensorflowトレーニングのファイルです
両方の学習モードのパフォーマンスは同等で、いずれのモードも使用する必要はありません.
ダウンロードした学習モデルファイルは2016年にリリースされたSSDアルゴリズムを用いて学習された[Liu 16]
SSDはオブジェクト検出深度学習アルゴリズムであり、入力ビデオから特定のオブジェクトのクラス、位置、サイズ情報をリアルタイムで抽出することができる.
SSDアルゴリズムは本来複数のクラスオブジェクトを検出することができるが,OpenCVが提供する顔検出は訓練された学習モデルを用いて顔オブジェクトの位置と大きさを決定する.
基本的なSSDネットワークを下図に示します.
この構成に300を入力×300サイズの2 D BGRカラービデオを使用
このビデオは、Scalar(104、117、123)の値を使用して標準化されて使用されます.
12ソリッドステートハードディスクネットワークの出力には、抽出対象のID、信頼性、矩形位置などの情報が含まれる.

深度学習の顔検出サンプルプログラムを使用して、コンピュータに接続された各フレームカメラで顔を検出します.
#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;
using namespace cv::dnn;

const String model = "res10_300x300_ssd_iter_140000_fp16.caffemodel";
const String config = "deploy.prototxt"; //두개의 파일을 폴더 안에 넣음
//const String model = "opencv_face_detector_uint8.pb";
//const String config = "opencv_face_detector.pbtxt";

int main(void)
{
	VideoCapture cap(0);

	if (!cap.isOpened())
	{
		cerr << "camera open failed!" << endl;
		return -1;
	}

	Net net = readNet(model, config);

	if (net.empty())
	{
		cerr << "net open failed" << endl;
		return -1;
	}

	Mat frame;
	while (true)
	{
		cap >> frame;
		if (frame.empty())
			break;

		Mat blob = blobFromImage(frame, 1, Size(300, 300), Scalar(104, 177, 123));
		net.setInput(blob);
		Mat res = net.forward();

		Mat detect(res.size[2], res.size[3], CV_32FC1, res.ptr<float>());

		for (int i = 0; i < detect.rows; i++)
		{
			float confidence = detect.at<float>(i, 2);
			if (confidence < 0.5)
				break;

			int x1 = cvRound(detect.at<float>(i, 3) * frame.cols);
			int y1 = cvRound(detect.at<float>(i, 4) * frame.rows);
			int x2 = cvRound(detect.at<float>(i, 5) * frame.cols);
			int y2 = cvRound(detect.at<float>(i, 6) * frame.rows);

			rectangle(frame, Rect(Point(x1, y1), Point(x2, y2)), Scalar(0, 255, 0));

			String label = format("Face : %4.3f", confidence);
			putText(frame, label, Point(x1, y1 - 1), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(0, 255, 0));
		}

		imshow("frame", frame);
		if (waitKey(1) == 27)
			break;
	}

	return 0;
}
顔領域を正確に検出し、緑の長方形を描画し、緑の長方形に顔検出の信頼性を同時に出力できます.
カスケード分類器に基づく顔検出方法は,正面の顔でなければ失敗することが多い.
SSD深さ学習による顔検出により,一部の顔が遮られたり,横顔が入力されたりしても,顔領域が安定して検出されることが保証される.
カスケード分類器に基づく方法と比較して,SSD深さ学習に基づく顔検出速度はより高速であった.