これ、いろんなONNXファイルを読みこめるので、いろんなディープラーニングを動かすことができます。
ディープラーニングの部分は以下のほぼ3行だし。
net=readNetFromONNX()
net.setInput()
net.forward();
今日は以下のサイトを参考に、ResNetという写真に写っているものが何かを認識するプログラムを作ってみたいと思います。
https://rest-term.com/archives/3503/
ResNetはこんなにつながってるらしいです。
これつなげるだけで間違うな。
でもいつものようにつなげて学習済みのデータを取ってくれば誰でもできます。
まず、先日作ったいつもの最小のNewralNetwork Runtimeを取ってきます。
https://drive.google.com/file/d/1P4VC3_gZXwANeL0yup-5Ni56IFyvs_VM/view?usp=sharingminoipencv
次に、ResNet-50の学習済みデータを取ってきます。
https://github.com/onnx/models/tree/master/models/image_classification/resnet
ディープラーニングの学習済みデータってどれも何百Mバイトもデータがあります。
ほんとうにすぐにハードディスクなくなってしまうじゃないか。
OpenCVのDNNライブラリはドキュメントがまだきちんと整備されていないのでいろいろはまるところがあります。
ソースコードやONNXの仕様書を読んでいろいろパラメーターを調べていくと、どうやらこのコードが正しそう。
---------------------------------
#include<stdio.h>
#include<iostream>
#include<string>
#include<vector>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "opencv2_core.hpp"
#include "opencv2_imgproc.hpp"
#include "opencv2_imgproc_imgproc_c.h"
#include "opencv2_dnn.hpp"
#include "stb_image.h"
#include "stb_image_write.h"
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, n=-1;
//
p = stbi_load("beer.jpg", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);
//
cv::Mat img;
cv::cvtColor(color, img, CV_BGRA2BGR);
cv::resize(img, img, cv::Size(224, 224));
cv::Mat inpBlob = cv::dnn::blobFromImage(img, 1.0 / 255.0, cv::Size(224, 224), cv::Scalar(104, 117, 123));
cv::dnn::Net net = cv::dnn::readNetFromONNX("resnet50v1.onnx");
net.setInput(inpBlob);
cv::Mat output = net.forward();
cv::Mat sorted(output.rows, output.cols, CV_32F);
cv::sortIdx(output, sorted, CV_SORT_EVERY_ROW | CV_SORT_DESCENDING);
cv::Mat topk = sorted(cv::Rect(0, 0, 5, 1));
int no;
//std::cout << "output = " << std::endl << " " << output << std::endl << std::endl;
//std::cout << "topk = " << std::endl << " " << topk << std::endl << std::endl;
static char name[1000][256];
char buf[256];
int i;
FILE* fp;
char* s;
fp = fopen("synset.txt", "rt");
if (fp) {
for (i = 0; i < 1000; i++) {
buf[0] = 0;
fgets(buf, 256, fp);
s = strstr(buf, "\r");
if (s)*s = ' ';
s = strstr(buf, "\n");
if (s)*s = ' ';
strcpy(name[i], buf);
}
}
for (i = 0; i < 5; i++) {
no = topk.at<int>(i);
printf("%d %d %s %f\n",i+1, no, name[no], output.at<float>(no));
}
return 0;
}
---------------------------------
それではビールのグラスの絵を認識させてみます。
結果
---------------------------------
1 441 n02823750 beer glass 18.468941
2 572 n03443371 goblet 13.881867
3 440 n02823428 beer bottle 10.277216
4 969 n07932039 eggnog 10.136989
5 898 n04557648 water bottle 9.364053
---------------------------------
昨日は朝から晩まで飯も食わず一日中デバッグしてもできなかったんですが、おーなんかできた気がする。
ONNXでディープラーニングって数行コード書くだけでいろいろなとができて楽しいね。
OpenCVのNewralNetwork Runtimeはまだネットで検索してもあまり出てきませんが、とっても軽量で使い方も簡単。
C++コンパイラ以外何にもインストールなしで手軽にディープラーニングができて面白いですね。
0 件のコメント:
コメントを投稿