先日、諦めたライブラリをどうにかしてみよう。
改めて、ソースコードの構成を確認する。
$ cd Vitis-AI/tools/Vitis-AI-Library/facedetect
$ tree
.
├── CMakeLists.txt
├── include
│ └── vitis
│ └── ai
│ └── facedetect.hpp
├── src
│ ├── detect_imp.cpp
│ ├── detect_imp.hpp
│ └── facedetect.cpp
└── test
├── test_accuracy_facedetect.cpp
├── test_facedetect.cpp
└── test_facedetect_batch.cpp
test
はライブラリのテスト用だと思うのでsrc
だけビルドできればいいだろう。
ファイルは3つなので全部、覗いてみよう。
まずはfacedetect.cpp
を見る。
/*
* Copyright 2019 Xilinx Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vitis/ai/facedetect.hpp>
#include "./detect_imp.hpp"
namespace vitis {
namespace ai {
FaceDetect::FaceDetect() {}
FaceDetect::~FaceDetect() {}
std::unique_ptr<FaceDetect> FaceDetect::create(const std::string &model_name,
bool need_preprocess) {
return std::unique_ptr<FaceDetect>(
new DetectImp(model_name, need_preprocess));
}
std::unique_ptr<FaceDetect> FaceDetect::create(const std::string &model_name,
xir::Attrs *attrs,
bool need_preprocess) {
return std::unique_ptr<FaceDetect>(
new DetectImp(model_name, attrs, need_preprocess));
}
} // namespace ai
} // namespace vitis
これが本体だよね。
先日はvitis::ai::main_for_jpeg_demo
がハードウェアだよねと位置付けたが実行するアプリのtest_jpeg_facedetect.cpp
はvitis::ai::FaceDetect::create(model)
でこのソースコードを呼び出すということですね。
ここから、create
されてDetecgImp
関数を呼び出すわけですね。
あれ?
main_for_jpeg_demo
のソースコードがない。
ここではなくて別のところにあるんだな。
main_for_jpeg_demo
はVitis-AI/tools/Vitis-AI-Library/benchmark/include/vitis/ai/demo.hpp
に次のようにいた。
// Entrance of jpeg demo
template <typename FactoryMethod, typename ProcessResult>
int main_for_jpeg_demo(int argc, char *argv[],
const FactoryMethod &factory_method,
const ProcessResult &process_result, int start_pos = 1) {
if (argc <= 1) {
usage_jpeg(argv[0]);
exit(1);
}
auto model = factory_method();
for (int i = start_pos; i < argc; ++i) {
auto image_file_name = std::string{argv[i]};
auto image = cv::imread(image_file_name);
if (image.empty()) {
LOG(FATAL) << "cannot load " << image_file_name << std::endl;
abort();
}
auto result = model->run(image);
image = process_result(image, result, true);
auto out_file =
image_file_name.substr(0, image_file_name.size() - 4) + "_result.jpg";
cv::imwrite(out_file, image);
LOG_IF(INFO, ENV_PARAM(DEBUG_DEMO)) << "result image write to " << out_file;
}
LOG_IF(INFO, ENV_PARAM(DEBUG_DEMO)) << "BYEBYE";
return 0;
}
} // namespace ai
} // namespace vitis
ここでOpenCVを利用してJPEGをimread
で読み込み、model->run(image)
で実行して、process_result
でなにかして、imwrite
で結果を書き戻しているんだな。
process_result
はfacedetectのディレクトリにdemo/Vitis-AI-Library/samples/facedetect/
にprocess_result.hpp
がいたな。
こんなかんじだな。
/*
* Copyright 2019 Xilinx Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
cv::Mat process_result(cv::Mat &m1, const vitis::ai::FaceDetectResult &result,
bool is_jpeg) {
cv::Mat image;
cv::resize(m1, image, cv::Size{result.width, result.height});
for (const auto &r : result.rects) {
LOG_IF(INFO, is_jpeg) << " " << r.score << " " //
<< r.x << " " //
<< r.y << " " //
<< r.width << " " //
<< r.height;
cv::rectangle(image,
cv::Rect{cv::Point(r.x * image.cols, r.y * image.rows),
cv::Size{(int)(r.width * image.cols),
(int)(r.height * image.rows)}},
0xff);
}
return image;
}
結果を四角で書き込むのか。
次は実行本体のDetectImpを見てみよう。
ソースコードはdetect_imp.cpp
を見る。
/*
* Copyright 2019 Xilinx Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "detect_imp.hpp"
#include <vitis/ai/profiling.hpp>
using std::vector;
namespace vitis {
namespace ai {
DetectImp::DetectImp(const std::string &model_name, bool need_preprocess)
: vitis::ai::TConfigurableDpuTask<FaceDetect>(model_name, need_preprocess),
det_threshold_(configurable_dpu_task_->getConfig()
.dense_box_param()
.det_threshold()) { //
}
DetectImp::DetectImp(const std::string &model_name,
xir::Attrs *attrs,
bool need_preprocess)
: vitis::ai::TConfigurableDpuTask<FaceDetect>(model_name, attrs,
need_preprocess),
det_threshold_(configurable_dpu_task_->getConfig()
.dense_box_param()
.det_threshold()) { //
}
DetectImp::~DetectImp() {}
FaceDetectResult DetectImp::run(const cv::Mat &input_image) {
__TIC__(FACE_DETECT_E2E)
// Set input image into DPU Task
cv::Mat image;
auto size = cv::Size(getInputWidth(), getInputHeight());
if (size != input_image.size()) {
cv::resize(input_image, image, size, 0);
} else {
image = input_image;
}
__TIC__(FACE_DETECT_SET_IMG)
configurable_dpu_task_->setInputImageBGR(image);
__TOC__(FACE_DETECT_SET_IMG)
__TIC__(FACE_DETECT_DPU)
configurable_dpu_task_->run(0);
__TOC__(FACE_DETECT_DPU)
__TIC__(FACE_DETECT_POST_ARM)
auto ret = vitis::ai::face_detect_post_process(
configurable_dpu_task_->getInputTensor(),
configurable_dpu_task_->getOutputTensor(),
configurable_dpu_task_->getConfig(), det_threshold_);
__TOC__(FACE_DETECT_POST_ARM)
__TOC__(FACE_DETECT_E2E)
return ret[0];
}
std::vector<FaceDetectResult> DetectImp::run(
const std::vector<cv::Mat> &input_images) {
__TIC__(FACE_DETECT_E2E)
// Set input image into DPU Task
std::vector<cv::Mat> images;
auto size = cv::Size(getInputWidth(), getInputHeight());
for (auto i = 0u; i < input_images.size(); i++) {
if (size != input_images[i].size()) {
cv::Mat img;
cv::resize(input_images[i], img, size, 0);
images.push_back(img);
} else {
images.push_back(input_images[i]);
}
}
__TIC__(FACE_DETECT_SET_IMG)
configurable_dpu_task_->setInputImageBGR(images);
__TOC__(FACE_DETECT_SET_IMG)
__TIC__(FACE_DETECT_DPU)
configurable_dpu_task_->run(0);
__TOC__(FACE_DETECT_DPU)
__TIC__(FACE_DETECT_POST_ARM)
auto ret = vitis::ai::face_detect_post_process(
configurable_dpu_task_->getInputTensor(),
configurable_dpu_task_->getOutputTensor(),
configurable_dpu_task_->getConfig(), det_threshold_);
__TOC__(FACE_DETECT_POST_ARM)
__TOC__(FACE_DETECT_E2E)
return ret;
}
float DetectImp::getThreshold() const {
std::lock_guard<std::mutex> lock(mtx_threshold_);
return det_threshold_;
}
void DetectImp::setThreshold(float threshold) {
std::lock_guard<std::mutex> lock(mtx_threshold_);
det_threshold_ = threshold;
}
} // namespace ai
} // namespace vitis
ソースコードの長さからするとこいつが本命のようだな。
最後にヘッダファイルのdetect_imp.hpp
も確認しておくか。
/*
* Copyright 2019 Xilinx Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <mutex>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <vector>
#include <vitis/ai/configurable_dpu_task.hpp>
#include <vitis/ai/facedetect.hpp>
using std::tuple;
using std::vector;
namespace vitis {
namespace ai {
class DetectImp : public vitis::ai::TConfigurableDpuTask<FaceDetect> {
public:
DetectImp(const std::string &model_name, bool need_preprocess);
DetectImp(const std::string &model_name, xir::Attrs *attrs, bool need_preprocess);
/// Destructor
virtual ~DetectImp();
/// Set an image and get positions and scores of faces in the image
virtual FaceDetectResult run(const cv::Mat &img) override;
/// Set an image list and get positions and scores of faces in the image
virtual std::vector<FaceDetectResult> run(
const std::vector<cv::Mat> &img) override;
/// Get detect threshold
virtual float getThreshold() const override;
/// Set detect threshold
virtual void setThreshold(float threshold) override;
private:
float det_threshold_;
mutable std::mutex mtx_threshold_;
};
} // namespace ai
} // namespace vitis
detectImp
のTConfigurableDpuTask
はdetect_imp.hpp
にいたのか。
そして、det_threshold_
はfloat
なのね。
そういえば、ライブラリを確認したいんじゃなくって、ライブラリをビルドする方法を確認するんだった。
明日にしよう。