2020年6月15日月曜日

深度推定をする

カメラの画像から物体までの距離を推定する、単眼深度推定(mono depth estimation)をしてみました。
この分野は盛んに研究されているらしく、vid2depth、monodepth、fcrndepthなど、いろいろなアルゴリズムがあります。
最新の研究だと、Tensorflowにデフォルトにないオペレーターとかを使うから、動かすのがとってもめんどくさい。
さらに、精度の良いアルゴリズムは、学習済みデータでも100Mくらい、元データは何百GバイトもあってとてもおじさんのPCでは実験できません。
この人たちどういうPCで研究しているんだろね。
そもそもおじさんのPCはGPUないし。

一年位前から手軽にさくっとできる単眼深度推定ないかなぁと論文を探していたところ、以下の論文を見つけました。
"Unsupervised CNN for single view depth estimation: Geometry to the rescue"
https://arxiv.org/pdf/1603.04992.pdf

学習はステレオカメラだけど、推定は一枚の画像でできるようです。

https://github.com/Ravi-Garg/Unsupervised_Depth_Estimation
学習済みデータも数十メガバイトしかないし。
なんかResNet50ベースって書いてあるから、これならば、いつもの最小のOpenCVでもさくっと実行できるかも。

ということで、github上の学習済みデータとテストコードを見ながら頑張って数時間かけて上記の論文のプログラムをC++で作ってみました。

以前作った最小限のOpenCVもとってきます。
http://yomeiotani.blogspot.com/2019/07/pose-estimation.html




なんとなくそれっぽい結果が。
-------------------------------
#include<stdio.h>
#include<string>
#include<vector>
#include<iostream>

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



#if 1

int main()
{
unsigned char* p;
int x=-1, y=-1, n=-1;

// Specify the paths for the 2 files
std::string protoFile = "deploy_resnet50by2_pool.prototxt";
std::string weightsFile = "train_iter_40000.caffemodel";


// Read the network into Memory
cv::dnn::Net net = cv::dnn::readNetFromCaffe(protoFile, weightsFile);

//
p = stbi_load("1.png", &x, &y, &n, 4);
//p = stbi_load("mask5.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(608,160));

cv::Mat inpBlob = cv::dnn::blobFromImage(img, 1.0);

// Set the prepared object as the input blob of the network
net.setInput(inpBlob);


cv::Mat output = net.forward();
std::vector<cv::Mat> outImg;
cv::dnn::imagesFromBlob(output, outImg);
cv::Mat out = outImg[0];
unsigned char* pp = new unsigned char[608 * 160 * 4];
p = pp;
float* ff = (float*)out.data;

for (int i = 0; i < 160 * 608; i++) {
//if(i%608==0)printf("i=%d ff=%f\n",i,*ff);
float a = *ff++*5;
if (a > 255)a = 255;
if (a <0)a = 0;
*p++ = a;
*p++ = a;
*p++ = a;
*p++ = 255;
}

stbi_write_png("result.png", 608, 160, 4, pp, 4 * 608);

delete[] pp;
return 0;
}

#endif
-------------------------------

おじさん、次はLSTMをやりたいんだよなぁ。
機械翻訳のseq2seqとか、数式の写真をとると答えを計算してくれるim2latexとかをやってみたい。
opencvだとオペレーターが足りないんだよなぁ。


0 件のコメント:

コメントを投稿