mirror of
https://github.com/lltcggie/waifu2x-caffe.git
synced 2025-06-26 13:42:48 +00:00
832 lines
22 KiB
C++
832 lines
22 KiB
C++
#include "waifu2x.h"
|
||
#include <caffe/caffe.hpp>
|
||
#include <cudnn.h>
|
||
#include <mutex>
|
||
#include <opencv2/opencv.hpp>
|
||
#include <boost/filesystem.hpp>
|
||
#include <boost/algorithm/string.hpp>
|
||
#include <chrono>
|
||
#include <cuda_runtime.h>
|
||
|
||
|
||
#ifdef _DEBUG
|
||
#pragma comment(lib, "caffe-d.lib")
|
||
#pragma comment(lib, "proto-d.lib")
|
||
#pragma comment(lib, "libboost_system-vc120-mt-gd-1_59.lib")
|
||
#pragma comment(lib, "libboost_thread-vc120-mt-gd-1_59.lib")
|
||
#pragma comment(lib, "libboost_filesystem-vc120-mt-gd-1_59.lib")
|
||
#pragma comment(lib, "glogd.lib")
|
||
#pragma comment(lib, "gflagsd.lib")
|
||
#pragma comment(lib, "libprotobufd.lib")
|
||
#pragma comment(lib, "libhdf5_hl_D.lib")
|
||
#pragma comment(lib, "libhdf5_D.lib")
|
||
#pragma comment(lib, "zlibstaticd.lib")
|
||
#pragma comment(lib, "libopenblas.dll.a")
|
||
#pragma comment(lib, "cudart.lib")
|
||
#pragma comment(lib, "curand.lib")
|
||
#pragma comment(lib, "cublas.lib")
|
||
#pragma comment(lib, "cudnn.lib")
|
||
|
||
#pragma comment(lib, "opencv_calib3d249d.lib")
|
||
#pragma comment(lib, "opencv_contrib249d.lib")
|
||
#pragma comment(lib, "opencv_core249d.lib")
|
||
#pragma comment(lib, "opencv_highgui249d.lib")
|
||
#pragma comment(lib, "opencv_imgproc249d.lib")
|
||
#else
|
||
#pragma comment(lib, "caffe.lib")
|
||
#pragma comment(lib, "proto.lib")
|
||
#pragma comment(lib, "libboost_system-vc120-mt-1_59.lib")
|
||
#pragma comment(lib, "libboost_thread-vc120-mt-1_59.lib")
|
||
#pragma comment(lib, "libboost_filesystem-vc120-mt-1_59.lib")
|
||
#pragma comment(lib, "glog.lib")
|
||
#pragma comment(lib, "gflags.lib")
|
||
#pragma comment(lib, "libprotobuf.lib")
|
||
#pragma comment(lib, "libhdf5_hl.lib")
|
||
#pragma comment(lib, "libhdf5.lib")
|
||
#pragma comment(lib, "zlibstatic.lib")
|
||
#pragma comment(lib, "libopenblas.dll.a")
|
||
#pragma comment(lib, "cudart.lib")
|
||
#pragma comment(lib, "curand.lib")
|
||
#pragma comment(lib, "cublas.lib")
|
||
#pragma comment(lib, "cudnn.lib")
|
||
|
||
#pragma comment(lib, "opencv_calib3d249.lib")
|
||
#pragma comment(lib, "opencv_contrib249.lib")
|
||
#pragma comment(lib, "opencv_core249.lib")
|
||
#pragma comment(lib, "opencv_highgui249.lib")
|
||
#pragma comment(lib, "opencv_imgproc249.lib")
|
||
#endif
|
||
|
||
// “ü—͉摜‚̃IƒtƒZƒbƒg
|
||
const int offset = 0;
|
||
// srcnn.prototxt‚Å’è‹`‚³‚ꂽƒŒƒCƒ„<C692>[‚Ì<E2809A>”
|
||
const int layer_num = 7;
|
||
|
||
const int ConvertMode = CV_RGB2YUV;
|
||
const int ConvertInverseMode = CV_YUV2RGB;
|
||
|
||
// <20>Å’áŒÀ•K—v‚ÈCUDAƒhƒ‰ƒCƒo<C692>[‚̃o<C692>[ƒWƒ‡ƒ“
|
||
const int MinCudaDriverVersion = 6050;
|
||
|
||
static std::once_flag waifu2x_once_flag;
|
||
static std::once_flag waifu2x_cudnn_once_flag;
|
||
static std::once_flag waifu2x_cuda_once_flag;
|
||
|
||
#ifndef CUDA_CHECK_WAIFU2X
|
||
#define CUDA_CHECK_WAIFU2X(condition) \
|
||
do { \
|
||
cudaError_t error = condition; \
|
||
if(error != cudaSuccess) throw error; \
|
||
} while (0)
|
||
#endif
|
||
|
||
#define CUDA_HOST_SAFE_FREE(ptr) \
|
||
do { \
|
||
if (ptr) { \
|
||
cudaFreeHost(ptr); \
|
||
ptr = nullptr; \
|
||
} \
|
||
} while (0)
|
||
|
||
#define SAFE_DELETE_WAIFU2X(ptr) \
|
||
do { \
|
||
if (ptr) { \
|
||
delete [] ptr; \
|
||
ptr = nullptr; \
|
||
} \
|
||
} while (0)
|
||
|
||
namespace
|
||
{
|
||
class IgnoreErrorCV
|
||
{
|
||
private:
|
||
static int handleError(int status, const char* func_name,
|
||
const char* err_msg, const char* file_name,
|
||
int line, void* userdata)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
public:
|
||
IgnoreErrorCV()
|
||
{
|
||
cv::redirectError(handleError);
|
||
}
|
||
};
|
||
|
||
IgnoreErrorCV g_IgnoreErrorCV;
|
||
}
|
||
|
||
Waifu2x::Waifu2x() : is_inited(false), isCuda(false), input_block(nullptr), dummy_data(nullptr), output_block(nullptr)
|
||
{
|
||
}
|
||
|
||
Waifu2x::~Waifu2x()
|
||
{
|
||
destroy();
|
||
}
|
||
|
||
// ‰æ‘œ‚ð“Ç‚Ý<E2809A>ž‚ñ‚Å’l‚ð0.0f<EFBFBD>`1.0f‚͈̔͂ɕϊ·
|
||
Waifu2x::eWaifu2xError Waifu2x::LoadMat(cv::Mat &float_image, const uint32_t* source, int width, int height)
|
||
{
|
||
float_image = cv::Mat(cv::Size(width, height), CV_MAKETYPE(CV_8U, 4));
|
||
|
||
const auto LinePixel = float_image.step1() / float_image.channels();
|
||
const auto Channel = float_image.channels();
|
||
const auto Width = float_image.size().width;
|
||
const auto Height = float_image.size().height;
|
||
|
||
const uint8_t *sptr = (const uint8_t *)source;
|
||
auto ptr = float_image.data;
|
||
for (int i = 0; i < height; i++)
|
||
{
|
||
for (int j = 0; j < width; j++)
|
||
{
|
||
for (int ch = 0; ch < Channel; ch++)
|
||
ptr[(i * LinePixel + j) * 4 + ch] = sptr[(i * width + j) * 4 + ch];
|
||
}
|
||
}
|
||
|
||
// RGB‚¾‚©‚çBGR‚ɕϊ·
|
||
/*
|
||
for (int i = 0; i < height; i++)
|
||
{
|
||
for (int j = 0; j < width; j++)
|
||
std::swap(ptr[(i * LinePixel + j) * 4 + 0], ptr[(i * LinePixel + j) * 4 + 2]);
|
||
}
|
||
*/
|
||
|
||
cv::Mat convert;
|
||
float_image.convertTo(convert, CV_32F, 1.0 / 255.0);
|
||
float_image.release();
|
||
|
||
{
|
||
// ƒAƒ‹ƒtƒ@ƒ`ƒƒƒ“ƒlƒ‹•t‚«‚¾‚Á‚½‚烿<C692>æŽZ<C5BD>ς݂ɂ·‚é
|
||
|
||
std::vector<cv::Mat> planes;
|
||
cv::split(convert, planes);
|
||
|
||
cv::Mat w = planes[3];
|
||
|
||
planes[0] = planes[0].mul(w);
|
||
planes[1] = planes[1].mul(w);
|
||
planes[2] = planes[2].mul(w);
|
||
|
||
cv::merge(planes, convert);
|
||
}
|
||
|
||
float_image = convert;
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
// “ü—͉摜‚Ì(Photoshop‚Å‚¢‚¤)ƒLƒƒƒ“ƒoƒXƒTƒCƒY‚ðoutput_size‚Ì”{<7B>”‚É•Ï<E280A2>X
|
||
// ‰æ‘œ‚Í<E2809A>¶<EFBFBD>ã”z’u<E28099>A—]”’‚Ícv::BORDER_REPLICATE‚Å–„‚ß‚é
|
||
Waifu2x::eWaifu2xError Waifu2x::PaddingImage(const cv::Mat &input, cv::Mat &output)
|
||
{
|
||
const auto h_blocks = (int)floor(input.size().width / output_size) + (input.size().width % output_size == 0 ? 0 : 1);
|
||
const auto w_blocks = (int)floor(input.size().height / output_size) + (input.size().height % output_size == 0 ? 0 : 1);
|
||
const auto height = offset + h_blocks * output_size + offset;
|
||
const auto width = offset + w_blocks * output_size + offset;
|
||
const auto pad_h1 = offset;
|
||
const auto pad_w1 = offset;
|
||
const auto pad_h2 = (height - offset) - input.size().width;
|
||
const auto pad_w2 = (width - offset) - input.size().height;
|
||
|
||
cv::copyMakeBorder(input, output, pad_w1, pad_w2, pad_h1, pad_h2, cv::BORDER_REPLICATE);
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
// ‰æ‘œ‚ðcv::INTER_NEAREST‚Å“ñ”{‚ÉŠg‘債‚Ä<E2809A>APaddingImage()‚ŃpƒfƒBƒ“ƒO‚·‚é
|
||
Waifu2x::eWaifu2xError Waifu2x::Zoom2xAndPaddingImage(const cv::Mat &input, cv::Mat &output, cv::Size_<int> &zoom_size)
|
||
{
|
||
zoom_size = input.size();
|
||
zoom_size.width *= 2;
|
||
zoom_size.height *= 2;
|
||
|
||
cv::Mat zoom_image;
|
||
cv::resize(input, zoom_image, zoom_size, 0.0, 0.0, cv::INTER_NEAREST);
|
||
|
||
return PaddingImage(zoom_image, output);
|
||
}
|
||
|
||
// “ü—͉摜‚ðzoom_size‚̑傫‚³‚Écv::INTER_CUBIC‚ÅŠg‘債<E2809A>A<EFBFBD>F<EFBFBD>î•ñ‚݂̂ðŽc‚·
|
||
Waifu2x::eWaifu2xError Waifu2x::CreateZoomColorImage(const cv::Mat &float_image, const cv::Size_<int> &zoom_size, std::vector<cv::Mat> &cubic_planes)
|
||
{
|
||
cv::Mat zoom_cubic_image;
|
||
cv::resize(float_image, zoom_cubic_image, zoom_size, 0.0, 0.0, cv::INTER_CUBIC);
|
||
|
||
cv::Mat converted_cubic_image;
|
||
cv::cvtColor(zoom_cubic_image, converted_cubic_image, ConvertMode);
|
||
zoom_cubic_image.release();
|
||
|
||
cv::split(converted_cubic_image, cubic_planes);
|
||
converted_cubic_image.release();
|
||
|
||
// ‚±‚ÌY<C38C>¬•ª‚ÍŽg‚í‚È‚¢‚̂ʼnð•ú
|
||
cubic_planes[0].release();
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
// ƒ‚ƒfƒ‹ƒtƒ@ƒCƒ‹‚©‚çƒlƒbƒgƒ<67><C692>[ƒN‚ð<E2809A>\’z
|
||
// process‚Åcudnn‚ªŽw’肳‚ê‚È‚©‚Á‚½<E2809A>ê<EFBFBD>‡‚ÍcuDNN‚ªŒÄ‚Ñ<E2809A>o‚³‚ê‚È‚¢‚悤‚É•Ï<E280A2>X‚·‚é
|
||
Waifu2x::eWaifu2xError Waifu2x::ConstractNet(boost::shared_ptr<caffe::Net<float>> &net, const std::string &model_path, const std::string ¶m_path, const std::string &process)
|
||
{
|
||
const std::string caffemodel_path = param_path + ".caffemodel";
|
||
const std::string modelbin_path = model_path + ".protobin";
|
||
|
||
FILE *fp = fopen(caffemodel_path.c_str(), "rb");
|
||
const bool isModelExist = fp != nullptr;
|
||
if (fp) fclose(fp);
|
||
|
||
fp = fopen(modelbin_path.c_str(), "rb");
|
||
const bool isModelBinExist = fp != nullptr;
|
||
if (fp) fclose(fp);
|
||
|
||
caffe::NetParameter param;
|
||
if (isModelExist && isModelBinExist && caffe::ReadProtoFromBinaryFile(modelbin_path, ¶m))
|
||
{
|
||
const auto ret = SetParameter(param);
|
||
if (ret != eWaifu2xError_OK)
|
||
return ret;
|
||
|
||
net = boost::shared_ptr<caffe::Net<float>>(new caffe::Net<float>(param));
|
||
net->CopyTrainedLayersFrom(caffemodel_path);
|
||
|
||
input_plane = param.input_dim(1);
|
||
}
|
||
else
|
||
return eWaifu2xError_FailedConstructModel;
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
Waifu2x::eWaifu2xError Waifu2x::SetParameter(caffe::NetParameter ¶m) const
|
||
{
|
||
param.mutable_state()->set_phase(caffe::TEST);
|
||
|
||
{
|
||
auto mid = param.mutable_input_dim();
|
||
|
||
if (mid->size() != 4)
|
||
return eWaifu2xError_FailedParseModelFile;
|
||
|
||
*mid->Mutable(0) = batch_size;
|
||
*mid->Mutable(2) = input_block_size;
|
||
*mid->Mutable(3) = input_block_size;
|
||
}
|
||
|
||
for (int i = 0; i < param.layer_size(); i++)
|
||
{
|
||
caffe::LayerParameter *layer_param = param.mutable_layer(i);
|
||
const std::string& type = layer_param->type();
|
||
if (type == "Convolution")
|
||
{
|
||
if (process == "cudnn")
|
||
layer_param->mutable_convolution_param()->set_engine(caffe::ConvolutionParameter_Engine_CUDNN);
|
||
else
|
||
layer_param->mutable_convolution_param()->set_engine(caffe::ConvolutionParameter_Engine_CAFFE);
|
||
}
|
||
else if (type == "ReLU")
|
||
{
|
||
if (process == "cudnn")
|
||
layer_param->mutable_relu_param()->set_engine(caffe::ReLUParameter_Engine_CUDNN);
|
||
else
|
||
layer_param->mutable_relu_param()->set_engine(caffe::ReLUParameter_Engine_CAFFE);
|
||
}
|
||
}
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
// ƒlƒbƒgƒ<67><C692>[ƒN‚ðŽg‚Á‚ĉ摜‚ð<E2809A>Ä<EFBFBD>\’z‚·‚é
|
||
Waifu2x::eWaifu2xError Waifu2x::ReconstructImage(boost::shared_ptr<caffe::Net<float>> net, cv::Mat &im)
|
||
{
|
||
const auto Height = im.size().height;
|
||
const auto Width = im.size().width;
|
||
const auto Line = im.step1();
|
||
|
||
assert(Width % output_size == 0);
|
||
assert(Height % output_size == 0);
|
||
|
||
assert(im.channels() == 1 || im.channels() == 3);
|
||
|
||
cv::Mat outim(im.rows, im.cols, im.type());
|
||
|
||
// float *imptr = (float *)im.data;
|
||
float *imptr = (float *)outim.data;
|
||
|
||
try
|
||
{
|
||
auto input_blobs = net->input_blobs();
|
||
auto input_blob = net->input_blobs()[0];
|
||
|
||
input_blob->Reshape(batch_size, input_plane, input_block_size, input_block_size);
|
||
|
||
assert(im.channels() == input_plane);
|
||
assert(input_blob->shape(1) == input_plane);
|
||
|
||
const int WidthNum = Width / output_size;
|
||
const int HeightNum = Height / output_size;
|
||
|
||
const int BlockNum = WidthNum * HeightNum;
|
||
|
||
const int input_block_plane_size = input_block_size * input_block_size * input_plane;
|
||
const int output_block_plane_size = output_block_size * output_block_size * input_plane;
|
||
|
||
const int output_padding = inner_padding + outer_padding - layer_num;
|
||
|
||
// ‰æ‘œ‚Í(<28>Á”ïƒ<C3AF>ƒ‚ƒŠ‚Ì“s<E2809C>‡<EFBFBD>ã)output_size*output_size‚É•ª‚¯‚Ä<E2809A>Ä<EFBFBD>\’z‚·‚é
|
||
for (int num = 0; num < BlockNum; num += batch_size)
|
||
{
|
||
const int processNum = (BlockNum - num) >= batch_size ? batch_size : BlockNum - num;
|
||
|
||
if (processNum < batch_size)
|
||
input_blob->Reshape(processNum, input_plane, input_block_size, input_block_size);
|
||
|
||
for (int n = 0; n < processNum; n++)
|
||
{
|
||
const int wn = (num + n) % WidthNum;
|
||
const int hn = (num + n) / WidthNum;
|
||
|
||
const int w = wn * output_size;
|
||
const int h = hn * output_size;
|
||
|
||
if (w + crop_size <= Width && h + crop_size <= Height)
|
||
{
|
||
int x, y;
|
||
x = w - inner_padding;
|
||
y = h - inner_padding;
|
||
|
||
int width, height;
|
||
|
||
width = crop_size + inner_padding * 2;
|
||
height = crop_size + inner_padding * 2;
|
||
|
||
int top, bottom, left, right;
|
||
|
||
top = outer_padding;
|
||
bottom = outer_padding;
|
||
left = outer_padding;
|
||
right = outer_padding;
|
||
|
||
if (x < 0)
|
||
{
|
||
left += -x;
|
||
width -= -x;
|
||
x = 0;
|
||
}
|
||
|
||
if (x + width > Width)
|
||
{
|
||
right += (x + width) - Width;
|
||
width = Width - x;
|
||
}
|
||
|
||
if (y < 0)
|
||
{
|
||
top += -y;
|
||
height -= -y;
|
||
y = 0;
|
||
}
|
||
|
||
if (y + height > Height)
|
||
{
|
||
bottom += (y + height) - Height;
|
||
height = Height - y;
|
||
}
|
||
|
||
cv::Mat someimg = im(cv::Rect(x, y, width, height));
|
||
|
||
cv::Mat someborderimg;
|
||
// ‰æ‘œ‚𒆉›‚ɃpƒfƒBƒ“ƒO<C692>B—]”’‚Ícv::BORDER_REPLICATE‚Å–„‚ß‚é
|
||
// ŽÀ‚Íim‚ʼnæ‘f‚ª‘¶<E28098>Ý‚·‚é•”•ª‚Í—]”’‚Æ”Fޝ‚³‚ê‚È‚¢‚ª<E2809A>Ainner_padding‚ªlayer_num‚Åouter_padding‚ª1ˆÈ<CB86>ã‚Ȃ炻‚±‚Ì•”•ª‚̉æ‘f‚ÍŒ‹‰Ê‰æ‘œ‚Æ‚µ‚ÄŽæ‚è<E2809A>o‚·•”•ª‚ɂ͉e‹¿‚µ‚È‚¢
|
||
cv::copyMakeBorder(someimg, someborderimg, top, bottom, left, right, cv::BORDER_REPLICATE);
|
||
someimg.release();
|
||
|
||
// ‰æ‘œ‚ð’¼—ñ‚ɕϊ·
|
||
{
|
||
float *fptr = input_block + (input_block_plane_size * n);
|
||
const float *uptr = (const float *)someborderimg.data;
|
||
|
||
const auto Line = someborderimg.step1();
|
||
|
||
if (someborderimg.channels() == 1)
|
||
{
|
||
if (input_block_size == Line)
|
||
memcpy(fptr, uptr, input_block_size * input_block_size * sizeof(float));
|
||
else
|
||
{
|
||
for (int i = 0; i < input_block_size; i++)
|
||
memcpy(fptr + i * input_block_size, uptr + i * Line, input_block_size * sizeof(float));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
const auto LinePixel = someborderimg.step1() / someborderimg.channels();
|
||
const auto Channel = someborderimg.channels();
|
||
const auto Width = someborderimg.size().width;
|
||
const auto Height = someborderimg.size().height;
|
||
|
||
for (int i = 0; i < Height; i++)
|
||
{
|
||
for (int j = 0; j < LinePixel; j++)
|
||
{
|
||
for (int ch = 0; ch < Channel; ch++)
|
||
fptr[(ch * Height + i) * Width + j] = uptr[(i * LinePixel + j) * Channel + ch];
|
||
}
|
||
}
|
||
|
||
/*
|
||
{
|
||
cv::Mat im(someborderimg.size(), CV_32F, fptr, Width * sizeof(float));
|
||
|
||
cv::Mat write_iamge;
|
||
im.convertTo(write_iamge, CV_8U, 255.0);
|
||
im.release();
|
||
|
||
if (!cv::imwrite("test_in.png", write_iamge))
|
||
return eWaifu2xError_FailedOpenOutputFile;
|
||
}
|
||
*/
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
assert(input_blob->count() == input_block_plane_size * processNum);
|
||
|
||
// ƒlƒbƒgƒ<67><C692>[ƒN‚ɉ摜‚ð“ü—Í
|
||
input_blob->set_cpu_data(input_block);
|
||
|
||
// ŒvŽZ
|
||
auto out = net->ForwardPrefilled(nullptr);
|
||
|
||
auto b = out[0];
|
||
|
||
assert(b->count() == output_block_plane_size * processNum);
|
||
|
||
const float *ptr = nullptr;
|
||
|
||
if (caffe::Caffe::mode() == caffe::Caffe::CPU)
|
||
ptr = b->cpu_data();
|
||
else
|
||
ptr = b->gpu_data();
|
||
|
||
caffe::caffe_copy(output_block_plane_size * processNum, ptr, output_block);
|
||
|
||
for (int n = 0; n < processNum; n++)
|
||
{
|
||
const int wn = (num + n) % WidthNum;
|
||
const int hn = (num + n) / WidthNum;
|
||
|
||
const int w = wn * output_size;
|
||
const int h = hn * output_size;
|
||
|
||
const float *fptr = output_block + (output_block_plane_size * n);
|
||
|
||
// Œ‹‰Ê‚ð<E2809A>o—͉摜‚ɃRƒs<C692>[
|
||
if (outim.channels() == 1)
|
||
{
|
||
for (int i = 0; i < crop_size; i++)
|
||
memcpy(imptr + (h + i) * Line + w, fptr + (i + output_padding) * output_block_size + output_padding, crop_size * sizeof(float));
|
||
}
|
||
else
|
||
{
|
||
const auto LinePixel = outim.step1() / outim.channels();
|
||
const auto Channel = outim.channels();
|
||
|
||
for (int i = 0; i < crop_size; i++)
|
||
{
|
||
for (int j = 0; j < crop_size; j++)
|
||
{
|
||
for (int ch = 0; ch < Channel; ch++)
|
||
imptr[((h + i) * LinePixel + (w + j)) * Channel + ch] = fptr[(ch * output_block_size + i + output_padding) * output_block_size + j + output_padding];
|
||
}
|
||
}
|
||
|
||
/*
|
||
{
|
||
cv::Mat im(someborderimg.size(), CV_32F, fptr, Width * sizeof(float));
|
||
|
||
cv::Mat write_iamge;
|
||
im.convertTo(write_iamge, CV_8U, 255.0);
|
||
im.release();
|
||
|
||
if (!cv::imwrite("test_in.png", write_iamge))
|
||
return eWaifu2xError_FailedOpenOutputFile;
|
||
}
|
||
*/
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (...)
|
||
{
|
||
return eWaifu2xError_FailedProcessCaffe;
|
||
}
|
||
|
||
im = outim;
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
Waifu2x::eWaifu2xError Waifu2x::init(int argc, char** argv, const std::string &Mode, const int NoiseLevel, const std::string &ModelDir, const std::string &Process,
|
||
const int CropSize, const int BatchSize)
|
||
{
|
||
Waifu2x::eWaifu2xError ret;
|
||
|
||
if (is_inited)
|
||
return eWaifu2xError_OK;
|
||
|
||
try
|
||
{
|
||
mode = Mode;
|
||
noise_level = NoiseLevel;
|
||
model_dir = ModelDir;
|
||
process = Process;
|
||
|
||
crop_size = CropSize;
|
||
batch_size = BatchSize;
|
||
|
||
inner_padding = layer_num;
|
||
outer_padding = 1;
|
||
|
||
output_size = crop_size - offset * 2;
|
||
input_block_size = crop_size + (inner_padding + outer_padding) * 2;
|
||
original_width_height = 128 + layer_num * 2;
|
||
|
||
output_block_size = crop_size + (inner_padding + outer_padding - layer_num) * 2;
|
||
|
||
std::call_once(waifu2x_once_flag, [argc, argv]()
|
||
{
|
||
assert(argc >= 1);
|
||
|
||
int tmpargc = 1;
|
||
char* tmpargvv[] = { argv[0] };
|
||
char** tmpargv = tmpargvv;
|
||
// glog“™‚Ì<E2809A>‰Šú‰»
|
||
caffe::GlobalInit(&tmpargc, &tmpargv);
|
||
});
|
||
|
||
const auto cuDNNCheckStartTime = std::chrono::system_clock::now();
|
||
|
||
if (process == "gpu")
|
||
process = "cudnn";
|
||
|
||
const auto cuDNNCheckEndTime = std::chrono::system_clock::now();
|
||
|
||
boost::filesystem::path mode_dir_path(model_dir);
|
||
if (!mode_dir_path.is_absolute()) // model_dir‚ª‘Š‘ÎƒpƒX‚È‚ç<E2809A>â‘΃pƒX‚É’¼‚·
|
||
{
|
||
// ‚Ü‚¸‚̓JƒŒƒ“ƒgƒfƒBƒŒƒNƒgƒŠ‰º‚É‚ ‚é‚©’T‚·
|
||
mode_dir_path = boost::filesystem::absolute(model_dir);
|
||
if (!boost::filesystem::exists(mode_dir_path) && argc >= 1) // –³‚©‚Á‚½‚çargv[0]‚©‚çŽÀ<C5BD>sƒtƒ@ƒCƒ‹‚Ì‚ ‚éƒtƒHƒ‹ƒ_‚ð<E2809A>„’肵<E2809A>A‚»‚̃tƒHƒ‹ƒ_‰º‚É‚ ‚é‚©’T‚·
|
||
{
|
||
boost::filesystem::path a0(argv[0]);
|
||
if (a0.is_absolute())
|
||
mode_dir_path = a0.branch_path() / model_dir;
|
||
}
|
||
}
|
||
|
||
if (!boost::filesystem::exists(mode_dir_path))
|
||
return eWaifu2xError_FailedOpenModelFile;
|
||
|
||
if (process == "cpu")
|
||
{
|
||
caffe::Caffe::set_mode(caffe::Caffe::CPU);
|
||
isCuda = false;
|
||
}
|
||
else
|
||
{
|
||
caffe::Caffe::set_mode(caffe::Caffe::GPU);
|
||
isCuda = true;
|
||
}
|
||
|
||
if (mode == "noise" || mode == "noise_scale" || mode == "auto_scale")
|
||
{
|
||
const std::string model_path = (mode_dir_path / "srcnn.prototxt").string();
|
||
const std::string param_path = (mode_dir_path / ("noise" + std::to_string(noise_level) + "_model.json")).string();
|
||
|
||
ret = ConstractNet(net_noise, model_path, param_path, process);
|
||
if (ret != eWaifu2xError_OK)
|
||
return ret;
|
||
}
|
||
|
||
if (mode == "scale" || mode == "noise_scale" || mode == "auto_scale")
|
||
{
|
||
const std::string model_path = (mode_dir_path / "srcnn.prototxt").string();
|
||
const std::string param_path = (mode_dir_path / "scale2.0x_model.json").string();
|
||
|
||
ret = ConstractNet(net_scale, model_path, param_path, process);
|
||
if (ret != eWaifu2xError_OK)
|
||
return ret;
|
||
}
|
||
|
||
const int input_block_plane_size = input_block_size * input_block_size * input_plane;
|
||
const int output_block_plane_size = output_block_size * output_block_size * input_plane;
|
||
|
||
if (isCuda)
|
||
{
|
||
CUDA_CHECK_WAIFU2X(cudaHostAlloc(&input_block, sizeof(float) * input_block_plane_size * batch_size, cudaHostAllocWriteCombined));
|
||
CUDA_CHECK_WAIFU2X(cudaHostAlloc(&dummy_data, sizeof(float) * input_block_plane_size * batch_size, cudaHostAllocWriteCombined));
|
||
CUDA_CHECK_WAIFU2X(cudaHostAlloc(&output_block, sizeof(float) * output_block_plane_size * batch_size, cudaHostAllocDefault));
|
||
}
|
||
else
|
||
{
|
||
input_block = new float[input_block_plane_size * batch_size];
|
||
dummy_data = new float[input_block_plane_size * batch_size];
|
||
output_block = new float[output_block_plane_size * batch_size];
|
||
}
|
||
|
||
for (size_t i = 0; i < input_block_plane_size * batch_size; i++)
|
||
dummy_data[i] = 0.0f;
|
||
|
||
is_inited = true;
|
||
}
|
||
catch (...)
|
||
{
|
||
return eWaifu2xError_InvalidParameter;
|
||
}
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
void Waifu2x::destroy()
|
||
{
|
||
net_noise.reset();
|
||
net_scale.reset();
|
||
|
||
if (isCuda)
|
||
{
|
||
CUDA_HOST_SAFE_FREE(input_block);
|
||
CUDA_HOST_SAFE_FREE(dummy_data);
|
||
CUDA_HOST_SAFE_FREE(output_block);
|
||
}
|
||
else
|
||
{
|
||
SAFE_DELETE_WAIFU2X(input_block);
|
||
SAFE_DELETE_WAIFU2X(dummy_data);
|
||
SAFE_DELETE_WAIFU2X(output_block);
|
||
}
|
||
|
||
is_inited = false;
|
||
}
|
||
|
||
Waifu2x::eWaifu2xError Waifu2x::waifu2x(int factor, const uint32_t* source, uint32_t* dest, int width, int height)
|
||
{
|
||
Waifu2x::eWaifu2xError ret;
|
||
|
||
if (!is_inited)
|
||
return eWaifu2xError_NotInitialized;
|
||
|
||
cv::Mat float_image;
|
||
ret = LoadMat(float_image, source, width, height);
|
||
if (ret != eWaifu2xError_OK)
|
||
return ret;
|
||
|
||
cv::Mat im;
|
||
if (input_plane == 1)
|
||
return eWaifu2xError_NotInitialized;
|
||
else
|
||
{
|
||
std::vector<cv::Mat> planes;
|
||
cv::split(float_image, planes);
|
||
|
||
if (float_image.channels() == 4)
|
||
planes.resize(3);
|
||
|
||
// BGR‚©‚çRGB‚É‚·‚é
|
||
//std::swap(planes[0], planes[2]);
|
||
|
||
cv::merge(planes, im);
|
||
}
|
||
cv::Size_<int> image_size = im.size();
|
||
|
||
const bool isReconstructNoise = mode == "noise" || mode == "noise_scale" || mode == "auto_scale";
|
||
const bool isReconstructScale = mode == "scale" || mode == "noise_scale";
|
||
|
||
if (isReconstructNoise)
|
||
{
|
||
PaddingImage(im, im);
|
||
|
||
ret = ReconstructImage(net_noise, im);
|
||
if (ret != eWaifu2xError_OK)
|
||
return ret;
|
||
|
||
// ƒpƒfƒBƒ“ƒO‚ðŽæ‚è•¥‚¤
|
||
im = im(cv::Rect(offset, offset, image_size.width, image_size.height));
|
||
}
|
||
|
||
const int scale2 = ceil(log2((double)factor));
|
||
const double shrinkRatio = (double)factor / std::pow(2.0, (double)scale2);
|
||
|
||
if (isReconstructScale)
|
||
{
|
||
bool isError = false;
|
||
for (int i = 0; i < scale2; i++)
|
||
{
|
||
Zoom2xAndPaddingImage(im, im, image_size);
|
||
|
||
ret = ReconstructImage(net_scale, im);
|
||
if (ret != eWaifu2xError_OK)
|
||
return ret;
|
||
|
||
// ƒpƒfƒBƒ“ƒO‚ðŽæ‚è•¥‚¤
|
||
im = im(cv::Rect(offset, offset, image_size.width, image_size.height));
|
||
}
|
||
}
|
||
|
||
cv::Mat process_image;
|
||
if (input_plane == 1)
|
||
{
|
||
// <20>Ä<EFBFBD>\’z‚µ‚½‹P“x‰æ‘œ‚ÆCreateZoomColorImage()‚Å<E2809A>ì<EFBFBD>¬‚µ‚½<E2809A>F<EFBFBD>î•ñ‚ðƒ}<7D>[ƒW‚µ‚Ä’Ê<E28099>í‚̉摜‚ɕϊ·‚µ<E2809A>A<EFBFBD>‘‚«<E2809A>ž‚Þ
|
||
|
||
std::vector<cv::Mat> color_planes;
|
||
CreateZoomColorImage(float_image, image_size, color_planes);
|
||
|
||
float_image.release();
|
||
|
||
color_planes[0] = im;
|
||
im.release();
|
||
|
||
cv::Mat converted_image;
|
||
cv::merge(color_planes, converted_image);
|
||
color_planes.clear();
|
||
|
||
cv::cvtColor(converted_image, process_image, ConvertInverseMode);
|
||
converted_image.release();
|
||
}
|
||
else
|
||
{
|
||
std::vector<cv::Mat> planes;
|
||
cv::split(im, planes);
|
||
|
||
// RGB‚©‚çBGR‚É’¼‚·
|
||
//std::swap(planes[0], planes[2]);
|
||
|
||
cv::merge(planes, process_image);
|
||
}
|
||
|
||
cv::Mat alpha;
|
||
if (float_image.channels() == 4)
|
||
{
|
||
std::vector<cv::Mat> planes;
|
||
cv::split(float_image, planes);
|
||
alpha = planes[3];
|
||
|
||
cv::resize(alpha, alpha, image_size, 0.0, 0.0, cv::INTER_CUBIC);
|
||
}
|
||
|
||
// ƒAƒ‹ƒtƒ@ƒ`ƒƒƒ“ƒlƒ‹‚ª‚ ‚Á‚½‚ç<E2809A>AƒAƒ‹ƒtƒ@‚ð•t‰Á‚µ‚ăJƒ‰<C692>[‚©‚çƒAƒ‹ƒtƒ@‚̉e‹¿‚𔲂
|
||
if (!alpha.empty())
|
||
{
|
||
std::vector<cv::Mat> planes;
|
||
cv::split(process_image, planes);
|
||
process_image.release();
|
||
|
||
planes.push_back(alpha);
|
||
|
||
cv::Mat w2 = planes[3];
|
||
|
||
planes[0] = (planes[0]).mul(1.0 / w2);
|
||
planes[1] = (planes[1]).mul(1.0 / w2);
|
||
planes[2] = (planes[2]).mul(1.0 / w2);
|
||
|
||
cv::merge(planes, process_image);
|
||
}
|
||
|
||
const cv::Size_<int> ns(image_size.width * shrinkRatio, image_size.height * shrinkRatio);
|
||
if (image_size.width != ns.width || image_size.height != ns.height)
|
||
cv::resize(process_image, process_image, ns, 0.0, 0.0, cv::INTER_LINEAR);
|
||
|
||
cv::Mat write_iamge;
|
||
process_image.convertTo(write_iamge, CV_8U, 255.0);
|
||
process_image.release();
|
||
|
||
/*
|
||
ret = WriteMat(write_iamge, output_file);
|
||
if (ret != eWaifu2xError_OK)
|
||
return ret;
|
||
|
||
write_iamge.release();
|
||
*/
|
||
|
||
{
|
||
const auto width = write_iamge.size().width;
|
||
const auto stride = write_iamge.step1();
|
||
for (int i = 0; i < write_iamge.size().height; i++)
|
||
memcpy(dest + width * i, write_iamge.data + stride * i, stride);
|
||
}
|
||
|
||
return eWaifu2xError_OK;
|
||
}
|
||
|
||
const std::string& Waifu2x::used_process() const
|
||
{
|
||
return process;
|
||
}
|