From a2b222ee12f17efa61a3649e75b4c0930c59f04c Mon Sep 17 00:00:00 2001 From: lltcggie Date: Wed, 3 Jun 2015 03:01:56 +0900 Subject: [PATCH] =?UTF-8?q?=E5=85=A8=E4=BD=93=E3=81=AE=E8=A8=AD=E8=A8=88?= =?UTF-8?q?=E3=82=92=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/waifu2x.cpp | 336 +++++++++++++++++------------------ common/waifu2x.h | 83 ++++++--- waifu2x-caffe-gui/Source.cpp | 269 ++++++++++++++++------------ waifu2x-caffe/Source.cpp | 93 +++++----- 4 files changed, 428 insertions(+), 353 deletions(-) diff --git a/common/waifu2x.cpp b/common/waifu2x.cpp index 3145f72..b650b69 100644 --- a/common/waifu2x.cpp +++ b/common/waifu2x.cpp @@ -11,6 +11,8 @@ #if defined(WIN32) || defined(WIN64) #include + +#undef LoadImage #endif #ifdef _MSC_VER @@ -42,12 +44,21 @@ const auto original_width_height = 128 + layer_num * 2; const int ConvertMode = CV_RGB2YUV; const int ConvertInverseMode = CV_YUV2RGB; -std::once_flag waifu2x_once_flag; -std::once_flag waifu2x_cudnn_once_flag; +static std::once_flag waifu2x_once_flag; +static std::once_flag waifu2x_cudnn_once_flag; +Waifu2x::Waifu2x() : is_inited(false) +{ +} + +Waifu2x::~Waifu2x() +{ + destroy(); +} + // cuDNNが使えるかチェック。現状Windowsのみ -bool can_use_cuDNN() +bool Waifu2x::can_use_cuDNN() { static bool cuDNNFlag = false; std::call_once(waifu2x_cudnn_once_flag, [&]() @@ -80,7 +91,7 @@ bool can_use_cuDNN() } // 画像を読み込んで値を0.0f〜1.0fの範囲に変換 -eWaifu2xError LoadImage(cv::Mat &float_image, const std::string &input_file) +Waifu2x::eWaifu2xError Waifu2x::LoadImage(cv::Mat &float_image, const std::string &input_file) { cv::Mat original_image = cv::imread(input_file, cv::IMREAD_UNCHANGED); if (original_image.empty()) @@ -115,7 +126,7 @@ eWaifu2xError LoadImage(cv::Mat &float_image, const std::string &input_file) } // 画像から輝度の画像を取り出す -eWaifu2xError CreateBrightnessImage(const cv::Mat &float_image, cv::Mat &im) +Waifu2x::eWaifu2xError Waifu2x::CreateBrightnessImage(const cv::Mat &float_image, cv::Mat &im) { cv::Mat converted_color; cv::cvtColor(float_image, converted_color, ConvertMode); @@ -131,7 +142,7 @@ eWaifu2xError CreateBrightnessImage(const cv::Mat &float_image, cv::Mat &im) // 入力画像の(Photoshopでいう)キャンバスサイズをoutput_sizeの倍数に変更 // 画像は左上配置、余白はcv::BORDER_REPLICATEで埋める -eWaifu2xError PaddingImage(const cv::Mat &input, cv::Mat &output) +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); @@ -148,7 +159,7 @@ eWaifu2xError PaddingImage(const cv::Mat &input, cv::Mat &output) } // 画像をcv::INTER_NEARESTで二倍に拡大して、PaddingImage()でパディングする -eWaifu2xError Zoom2xAndPaddingImage(const cv::Mat &input, cv::Mat &output, cv::Size_ &zoom_size) +Waifu2x::eWaifu2xError Waifu2x::Zoom2xAndPaddingImage(const cv::Mat &input, cv::Mat &output, cv::Size_ &zoom_size) { zoom_size = input.size(); zoom_size.width *= 2; @@ -161,7 +172,7 @@ eWaifu2xError Zoom2xAndPaddingImage(const cv::Mat &input, cv::Mat &output, cv::S } // 入力画像をzoom_sizeの大きさにcv::INTER_CUBICで拡大し、色情報のみを残す -eWaifu2xError CreateZoomColorImage(const cv::Mat &float_image, const cv::Size_ &zoom_size, std::vector &cubic_planes) +Waifu2x::eWaifu2xError Waifu2x::CreateZoomColorImage(const cv::Mat &float_image, const cv::Size_ &zoom_size, std::vector &cubic_planes) { cv::Mat zoom_cubic_image; cv::resize(float_image, zoom_cubic_image, zoom_size, 0.0, 0.0, cv::INTER_CUBIC); @@ -180,7 +191,7 @@ eWaifu2xError CreateZoomColorImage(const cv::Mat &float_image, const cv::Size_> net, const std::string ¶m_path) +Waifu2x::eWaifu2xError Waifu2x::LoadParameter(boost::shared_ptr> net, const std::string ¶m_path) { rapidjson::Document d; std::vector jsonBuf; @@ -295,7 +306,7 @@ eWaifu2xError LoadParameter(boost::shared_ptr> net, const std: // モデルファイルからネットワークを構築 // processでcudnnが指定されなかった場合はcuDNNが呼び出されないように変更する -eWaifu2xError ConstractNet(boost::shared_ptr> &net, const std::string &model_path, const std::string &process) +Waifu2x::eWaifu2xError Waifu2x::ConstractNet(boost::shared_ptr> &net, const std::string &model_path, const std::string &process) { caffe::NetParameter param; if (!caffe::ReadProtoFromTextFile(model_path, ¶m)) @@ -337,7 +348,7 @@ eWaifu2xError ConstractNet(boost::shared_ptr> &net, const std: } // ネットワークを使って画像を再構築する -eWaifu2xError ReconstructImage(boost::shared_ptr> net, cv::Mat &im, const waifu2xProgressFunc func) +Waifu2x::eWaifu2xError Waifu2x::ReconstructImage(boost::shared_ptr> net, cv::Mat &im) { const auto Height = im.size().height; const auto Width = im.size().width; @@ -464,18 +475,21 @@ eWaifu2xError ReconstructImage(boost::shared_ptr> net, cv::Mat return eWaifu2xError_OK; } -#include - -eWaifu2xError waifu2x(int argc, char** argv, const std::vector &file_paths, - const std::string &mode, const int noise_level, const double scale_ratio, const std::string &model_dir, const std::string &process, - std::vector &errors, const waifu2xCancelFunc cancel_func, const waifu2xProgressFunc progress_func, const waifu2xTimeFunc time_func) +Waifu2x::eWaifu2xError Waifu2x::init(int argc, char** argv, const std::string &Mode, const int NoiseLevel, const double ScaleRatio, const std::string &ModelDir, const std::string &Process) { - if (scale_ratio <= 0.0) + Waifu2x::eWaifu2xError ret; + + if (is_inited) + return eWaifu2xError_OK; + + if (ScaleRatio <= 0.0) return eWaifu2xError_InvalidParameter; - const auto StartTime = std::chrono::system_clock::now(); - - eWaifu2xError ret; + mode = Mode; + noise_level = NoiseLevel; + scale_ratio = ScaleRatio; + model_dir = ModelDir; + process = Process; std::call_once(waifu2x_once_flag, [argc, argv]() { @@ -490,12 +504,11 @@ eWaifu2xError waifu2x(int argc, char** argv, const std::vector> net_noise; - boost::shared_ptr> net_scale; - 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, process_fix); + ret = ConstractNet(net_noise, model_path, process); if (ret != eWaifu2xError_OK) return ret; @@ -543,7 +553,7 @@ eWaifu2xError waifu2x(int argc, char** argv, const std::vector image_size = im.size(); + + const boost::filesystem::path ip(input_file); + const boost::filesystem::path ipext(ip.extension()); + + const bool isJpeg = boost::iequals(ipext.string(), ".jpg") || boost::iequals(ipext.string(), ".jpeg"); + + const bool isReconstructNoise = mode == "noise" || mode == "noise_scale" || (mode == "auto_scale" && isJpeg); + const bool isReconstructScale = mode == "scale" || mode == "noise_scale"; + + if (isReconstructNoise) { - if (progress_func) - progress_func(file_paths.size(), fileCount); + PaddingImage(im, im); - if (cancel_func && cancel_func()) - return eWaifu2xError_Cancel; - - const auto &input_file = p.first; - const auto &output_file = p.second; - - cv::Mat float_image; - ret = LoadImage(float_image, input_file); + ret = ReconstructImage(net_noise, im); if (ret != eWaifu2xError_OK) + return ret; + + // パディングを取り払う + im = im(cv::Rect(offset, offset, image_size.width, image_size.height)); + } + + if (cancel_func && cancel_func()) + return eWaifu2xError_Cancel; + + const int scale2 = ceil(log2(scale_ratio)); + const double shrinkRatio = scale_ratio / std::pow(2.0, (double)scale2); + + if (isReconstructScale) + { + bool isError = false; + for (int i = 0; i < scale2; i++) { - errors.emplace_back(p, ret); - continue; - } + Zoom2xAndPaddingImage(im, im, image_size); - cv::Mat im; - CreateBrightnessImage(float_image, im); - - cv::Size_ image_size = im.size(); - - const boost::filesystem::path ip(input_file); - const boost::filesystem::path ipext(ip.extension()); - - const bool isJpeg = boost::iequals(ipext.string(), ".jpg") || boost::iequals(ipext.string(), ".jpeg"); - - const bool isReconstructNoise = mode == "noise" || mode == "noise_scale" || (mode == "auto_scale" && isJpeg); - const bool isReconstructScale = mode == "scale" || mode == "noise_scale"; - - if (isReconstructNoise) - { - PaddingImage(im, im); - - ret = ReconstructImage(net_noise, im, progress_func); + ret = ReconstructImage(net_scale, im); if (ret != eWaifu2xError_OK) - { - errors.emplace_back(p, ret); - continue; - } + return ret; // パディングを取り払う im = im(cv::Rect(offset, offset, image_size.width, image_size.height)); } - - if (cancel_func && cancel_func()) - return eWaifu2xError_Cancel; - - const int scale2 = ceil(log2(scale_ratio)); - const double shrinkRatio = scale_ratio / 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, progress_func); - if (ret != eWaifu2xError_OK) - { - errors.emplace_back(p, ret); - isError = true; - break; - } - - // パディングを取り払う - im = im(cv::Rect(offset, offset, image_size.width, image_size.height)); - } - - if (isError) - continue; - } - - if (cancel_func && cancel_func()) - return eWaifu2xError_Cancel; - - // 再構築した輝度画像とCreateZoomColorImage()で作成した色情報をマージして通常の画像に変換し、書き込む - - std::vector color_planes; - CreateZoomColorImage(float_image, image_size, color_planes); - - cv::Mat alpha; - if (float_image.channels() == 4) - { - std::vector planes; - cv::split(float_image, planes); - alpha = planes[3]; - - cv::resize(alpha, alpha, image_size, 0.0, 0.0, cv::INTER_CUBIC); - } - - float_image.release(); - - color_planes[0] = im; - im.release(); - - cv::Mat converted_image; - cv::merge(color_planes, converted_image); - color_planes.clear(); - - cv::Mat process_image; - cv::cvtColor(converted_image, process_image, ConvertInverseMode); - converted_image.release(); - - // アルファチャンネルがあったら、アルファを付加してカラーからアルファの影響を抜く - if (!alpha.empty()) - { - std::vector planes; - cv::split(process_image, planes); - process_image.release(); - - planes.push_back(alpha); - - cv::Mat w2 = planes[3]; - - planes[0] = (planes[0] - 1.0).mul(1.0 / w2) + 1.0; - planes[1] = (planes[1] - 1.0).mul(1.0 / w2) + 1.0; - planes[2] = (planes[2] - 1.0).mul(1.0 / w2) + 1.0; - - cv::merge(planes, process_image); - } - - const cv::Size_ 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(); - - if (!cv::imwrite(output_file, write_iamge)) - { - errors.emplace_back(p, eWaifu2xError_FailedOpenOutputFile); - continue; - } - - write_iamge.release(); - - fileCount++; } - if (progress_func) - progress_func(file_paths.size(), fileCount); + if (cancel_func && cancel_func()) + return eWaifu2xError_Cancel; - const auto ProcessEndTime = std::chrono::system_clock::now(); + // 再構築した輝度画像とCreateZoomColorImage()で作成した色情報をマージして通常の画像に変換し、書き込む - const auto cuDNNCheckTime = (cuDNNCheckEndTime - cuDNNCheckStartTime); - const auto InitTime = (InitEndTime - StartTime) - cuDNNCheckTime; - const auto ProcessTime = (ProcessEndTime - InitEndTime); - if (time_func) - time_func(std::chrono::duration_cast(InitTime).count() - , std::chrono::duration_cast(cuDNNCheckTime).count() - , std::chrono::duration_cast(ProcessTime).count(), process_fix); + std::vector color_planes; + CreateZoomColorImage(float_image, image_size, color_planes); + + cv::Mat alpha; + if (float_image.channels() == 4) + { + std::vector planes; + cv::split(float_image, planes); + alpha = planes[3]; + + cv::resize(alpha, alpha, image_size, 0.0, 0.0, cv::INTER_CUBIC); + } + + float_image.release(); + + color_planes[0] = im; + im.release(); + + cv::Mat converted_image; + cv::merge(color_planes, converted_image); + color_planes.clear(); + + cv::Mat process_image; + cv::cvtColor(converted_image, process_image, ConvertInverseMode); + converted_image.release(); + + // アルファチャンネルがあったら、アルファを付加してカラーからアルファの影響を抜く + if (!alpha.empty()) + { + std::vector planes; + cv::split(process_image, planes); + process_image.release(); + + planes.push_back(alpha); + + cv::Mat w2 = planes[3]; + + planes[0] = (planes[0] - 1.0).mul(1.0 / w2) + 1.0; + planes[1] = (planes[1] - 1.0).mul(1.0 / w2) + 1.0; + planes[2] = (planes[2] - 1.0).mul(1.0 / w2) + 1.0; + + cv::merge(planes, process_image); + } + + const cv::Size_ 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(); + + if (!cv::imwrite(output_file, write_iamge)) + return eWaifu2xError_FailedOpenOutputFile; + + write_iamge.release(); return eWaifu2xError_OK; } + +const std::string& Waifu2x::used_process() const +{ + return process; +} diff --git a/common/waifu2x.h b/common/waifu2x.h index 0f3d546..2116125 100644 --- a/common/waifu2x.h +++ b/common/waifu2x.h @@ -5,30 +5,71 @@ #include #include #include +#include +#include -enum eWaifu2xError + +namespace caffe { - eWaifu2xError_OK = 0, - eWaifu2xError_Cancel, - eWaifu2xError_InvalidParameter, - eWaifu2xError_FailedOpenInputFile, - eWaifu2xError_FailedOpenOutputFile, - eWaifu2xError_FailedOpenModelFile, - eWaifu2xError_FailedParseModelFile, - eWaifu2xError_FailedConstructModel, - eWaifu2xError_FailedProcessCaffe, + template + class Net; }; -typedef std::pair InputOutputPathPair; -typedef std::pair PathAndErrorPair; -typedef std::function waifu2xCancelFunc; -typedef std::function waifu2xProgressFunc; -typedef std::function waifu2xTimeFunc; +class Waifu2x +{ +public: + enum eWaifu2xError + { + eWaifu2xError_OK = 0, + eWaifu2xError_Cancel, + eWaifu2xError_NotInitialized, + eWaifu2xError_InvalidParameter, + eWaifu2xError_FailedOpenInputFile, + eWaifu2xError_FailedOpenOutputFile, + eWaifu2xError_FailedOpenModelFile, + eWaifu2xError_FailedParseModelFile, + eWaifu2xError_FailedConstructModel, + eWaifu2xError_FailedProcessCaffe, + }; -bool can_use_cuDNN(); + typedef std::function waifu2xCancelFunc; -// mode: noise or scale or noise_scale or auto_scale -// process: cpu or gpu or cudnn -eWaifu2xError waifu2x(int argc, char** argv, - const std::vector &file_paths, const std::string &mode, const int noise_level, const double scale_ratio, const std::string &model_dir, const std::string &process, - std::vector &errors, const waifu2xCancelFunc cancel_func = nullptr, const waifu2xProgressFunc progress_func = nullptr, const waifu2xTimeFunc time_func = nullptr); +private: + bool is_inited; + + std::string mode; + int noise_level; + double scale_ratio; + std::string model_dir; + std::string process; + + boost::shared_ptr> net_noise; + boost::shared_ptr> net_scale; + +private: + eWaifu2xError LoadImage(cv::Mat &float_image, const std::string &input_file); + eWaifu2xError CreateBrightnessImage(const cv::Mat &float_image, cv::Mat &im); + eWaifu2xError PaddingImage(const cv::Mat &input, cv::Mat &output); + eWaifu2xError Zoom2xAndPaddingImage(const cv::Mat &input, cv::Mat &output, cv::Size_ &zoom_size); + eWaifu2xError CreateZoomColorImage(const cv::Mat &float_image, const cv::Size_ &zoom_size, std::vector &cubic_planes); + eWaifu2xError LoadParameter(boost::shared_ptr> net, const std::string ¶m_path); + eWaifu2xError ConstractNet(boost::shared_ptr> &net, const std::string &model_path, const std::string &process); + eWaifu2xError ReconstructImage(boost::shared_ptr> net, cv::Mat &im); + +public: + Waifu2x(); + ~Waifu2x(); + + static bool can_use_cuDNN(); + + // mode: noise or scale or noise_scale or auto_scale + // process: cpu or gpu or cudnn + eWaifu2xError init(int argc, char** argv, const std::string &mode, const int noise_level, const double scale_ratio, const std::string &model_dir, const std::string &process); + + void destroy(); + + eWaifu2xError waifu2x(const std::string &input_file, const std::string &output_file, + const waifu2xCancelFunc cancel_func = nullptr); + + const std::string& used_process() const; +}; diff --git a/waifu2x-caffe-gui/Source.cpp b/waifu2x-caffe-gui/Source.cpp index b0cac48..5c9acba 100644 --- a/waifu2x-caffe-gui/Source.cpp +++ b/waifu2x-caffe-gui/Source.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -15,9 +16,8 @@ #include "CControl.h" #define WM_FAILD_CREATE_DIR (WM_APP + 5) -#define WM_END_WAIFU2X (WM_APP + 6) +#define WM_ON_WAIFU2X_ERROR (WM_APP + 6) #define WM_END_THREAD (WM_APP + 7) -#define WM_TIME_WAIFU2X (WM_APP + 8) const size_t AR_PATH_MAX(1024); @@ -83,13 +83,12 @@ private: std::string autoSetAddName; bool isLastError; - struct stWaifu2xTime - { - uint64_t InitTime; - uint64_t cuDNNCheckTime; - uint64_t ProcessTime; - std::string Process; - }; + std::string logMessage; + + std::string usedProcess; + std::chrono::system_clock::duration cuDNNCheckTime; + std::chrono::system_clock::duration InitTime; + std::chrono::system_clock::duration ProcessTime; private: std::string AddName() const @@ -184,7 +183,7 @@ private: { const boost::filesystem::path input_path(boost::filesystem::absolute(input_str)); - std::vector file_paths; + std::vector> file_paths; if (boost::filesystem::is_directory(input_path)) // input_pathがフォルダならそのディレクトリ以下の画像ファイルを一括変換 { boost::filesystem::path output_path(output_str); @@ -273,24 +272,46 @@ private: SendMessage(GetDlgItem(dh, IDC_PROGRESS), PBM_SETPOS, ProgressFileNow, 0); }; - const auto TimeFunc = [this](const uint64_t InitTime, const uint64_t cuDNNCheckTime, const uint64_t ProcessTime, const std::string &Process) + const auto cuDNNCheckStartTime = std::chrono::system_clock::now(); + + if (process == "gpu") + Waifu2x::can_use_cuDNN(); + + const auto cuDNNCheckEndTime = std::chrono::system_clock::now(); + + Waifu2x::eWaifu2xError ret; + + Waifu2x w; + ret = w.init(__argc, __argv, mode, noise_level, scale_ratio, "models", process); + if(ret != Waifu2x::eWaifu2xError_OK) + SendMessage(dh, WM_ON_WAIFU2X_ERROR, (WPARAM)&ret, 0); + else { - stWaifu2xTime t; - t.InitTime = InitTime; - t.cuDNNCheckTime = cuDNNCheckTime; - t.ProcessTime = ProcessTime; - t.Process = Process; + const auto InitEndTime = std::chrono::system_clock::now(); - SendMessage(dh, WM_TIME_WAIFU2X, (WPARAM)&t, 0); - }; + for (const auto &p : file_paths) + { + ret = w.waifu2x(p.first, p.second, [this]() + { + return cancelFlag; + }); - std::vector errors; - const eWaifu2xError ret = waifu2x(__argc, __argv, file_paths, mode, noise_level, scale_ratio, "models", process, errors, [this]() - { - return cancelFlag; - }, ProgessFunc, TimeFunc); + if (ret != Waifu2x::eWaifu2xError_OK) + { + SendMessage(dh, WM_ON_WAIFU2X_ERROR, (WPARAM)&ret, (LPARAM)&p); - SendMessage(dh, WM_END_WAIFU2X, (WPARAM)&ret, (LPARAM)&errors); + if (ret == Waifu2x::eWaifu2xError_Cancel) + break; + } + } + + const auto ProcessEndTime = std::chrono::system_clock::now(); + + cuDNNCheckTime = cuDNNCheckEndTime - cuDNNCheckStartTime; + InitTime = InitEndTime - cuDNNCheckEndTime; + ProcessTime = ProcessEndTime - InitEndTime; + usedProcess = w.used_process(); + } PostMessage(dh, WM_END_THREAD, 0, 0); } @@ -317,6 +338,64 @@ private: } } + void AddLogMessage(const char *msg) + { + if (logMessage.length() == 0) + logMessage += msg; + else + logMessage += std::string("\r\n") + msg; + + SetWindowTextA(GetDlgItem(dh, IDC_EDIT_LOG), logMessage.c_str()); + } + + void Waifu2xTime() + { + char msg[1024 * 2]; + char *ptr = msg; + + { + std::string p(usedProcess); + if (p == "cpu") + p = "CPU"; + else if (p == "gpu") + p = "GPU"; + else if (p == "cudnn") + p = "cuDNN"; + + ptr += sprintf(ptr, "使用プロセッサーモード: %s\r\n", p.c_str()); + } + + { + uint64_t t = std::chrono::duration_cast(ProcessTime).count(); + const int msec = t % 1000; t /= 1000; + const int sec = t % 60; t /= 60; + const int min = t % 60; t /= 60; + const int hour = (int)t; + ptr += sprintf(ptr, "処理時間: %02d:%02d:%02d.%d\r\n", hour, min, sec, msec); + } + + { + uint64_t t = std::chrono::duration_cast(InitTime).count(); + const int msec = t % 1000; t /= 1000; + const int sec = t % 60; t /= 60; + const int min = t % 60; t /= 60; + const int hour = (int)t; + ptr += sprintf(ptr, "初期化時間: %02d:%02d:%02d.%d\r\n", hour, min, sec, msec); + } + + if (process == "gpu" || process == "cudnn") + { + uint64_t t = std::chrono::duration_cast(cuDNNCheckTime).count(); + const int msec = t % 1000; t /= 1000; + const int sec = t % 60; t /= 60; + const int min = t % 60; t /= 60; + const int hour = (int)t; + ptr += sprintf(ptr, "cuDNNチェック時間: %02d:%02d:%02d.%d", hour, min, sec, msec); + } + + AddLogMessage(msg); + } + public: DialogEvent() : dh(nullptr), mode("noise_scale"), noise_level(1), scale_ratio(2.0), process("gpu"), outputExt("png"), inputFileExt("png:jpg:jpeg:tif:tiff:bmp"), isLastError(false) { @@ -357,6 +436,7 @@ public: EnableWindow(GetDlgItem(dh, IDC_BUTTON_EXEC), FALSE); SetWindowTextA(GetDlgItem(hWnd, IDC_EDIT_LOG), ""); + logMessage.clear(); } void WaitThreadExit(HWND hWnd, WPARAM wParam, LPARAM lParam, LPVOID lpData) @@ -366,57 +446,15 @@ public: EnableWindow(GetDlgItem(dh, IDC_BUTTON_EXEC), TRUE); if (!isLastError) + { + if (!cancelFlag) + AddLogMessage("変換に成功しました"); + + Waifu2xTime(); MessageBeep(MB_ICONASTERISK); - } - - void Waifu2xTime(HWND hWnd, WPARAM wParam, LPARAM lParam, LPVOID lpData) - { - const stWaifu2xTime *tp = (const stWaifu2xTime *)wParam; - - char msg[1024*2]; - char *ptr = msg; - - { - std::string p(tp->Process); - if (p == "cpu") - p = "CPU"; - else if (p == "gpu") - p = "GPU"; - else if (p == "cudnn") - p = "cuDNN"; - - ptr += sprintf(ptr, "使用プロセッサーモード: %s\r\n", p.c_str()); } - - { - uint64_t t = tp->ProcessTime; - const int msec = t % 1000; t /= 1000; - const int sec = t % 60; t /= 60; - const int min = t % 60; t /= 60; - const int hour = (int)t; - ptr += sprintf(ptr, "処理時間: %02d:%02d:%02d.%d\r\n", hour, min, sec, msec); - } - - { - uint64_t t = tp->InitTime; - const int msec = t % 1000; t /= 1000; - const int sec = t % 60; t /= 60; - const int min = t % 60; t /= 60; - const int hour = (int)t; - ptr += sprintf(ptr, "初期化時間: %02d:%02d:%02d.%d\r\n", hour, min, sec, msec); - } - - if (tp->Process == "gpu" || tp->Process == "cudnn") - { - uint64_t t = tp->cuDNNCheckTime; - const int msec = t % 1000; t /= 1000; - const int sec = t % 60; t /= 60; - const int min = t % 60; t /= 60; - const int hour = (int)t; - ptr += sprintf(ptr, "cuDNNチェック時間: %02d:%02d:%02d.%d", hour, min, sec, msec); - } - - SetWindowTextA(GetDlgItem(hWnd, IDC_EDIT_LOG), msg); + else + MessageBoxA(dh, "エラーが発生しました", "エラー", MB_OK | MB_ICONERROR); } void OnDialogEnd(HWND hWnd, WPARAM wParam, LPARAM lParam, LPVOID lpData) @@ -441,63 +479,63 @@ public: isLastError = true; } - void OnEndWaifu2x(HWND hWnd, WPARAM wParam, LPARAM lParam, LPVOID lpData) + void OnWaifu2xError(HWND hWnd, WPARAM wParam, LPARAM lParam, LPVOID lpData) { - const eWaifu2xError ret = *(const eWaifu2xError *)wParam; - const std::vector &errors = *(const std::vector *)lParam; + const Waifu2x::eWaifu2xError ret = *(const Waifu2x::eWaifu2xError *)wParam; - if ((ret != eWaifu2xError_OK) || errors.size() > 0) + if (ret != Waifu2x::eWaifu2xError_OK) { char msg[1024] = ""; - switch (ret) + if (lParam == 0) { - case eWaifu2xError_Cancel: - sprintf(msg, "キャンセルされました"); - break; - case eWaifu2xError_InvalidParameter: - sprintf(msg, "パラメータが不正です"); - break; - case eWaifu2xError_FailedOpenModelFile: - sprintf(msg, "モデルファイルが開けませんでした"); - break; - case eWaifu2xError_FailedParseModelFile: - sprintf(msg, "モデルファイルが壊れています"); - break; - case eWaifu2xError_FailedConstructModel: - sprintf(msg, "ネットワークの構築に失敗しました"); - break; - } - - if (ret == eWaifu2xError_OK) - { - // 全てのエラーを表示することは出来ないので最初の一つだけ表示 - - const auto &fp = errors[0].first; - - bool isBreak = false; - switch (errors[0].second) + switch (ret) { - case eWaifu2xError_InvalidParameter: + case Waifu2x::eWaifu2xError_Cancel: + sprintf(msg, "キャンセルされました"); + break; + case Waifu2x::eWaifu2xError_InvalidParameter: sprintf(msg, "パラメータが不正です"); break; - case eWaifu2xError_FailedOpenInputFile: - //sprintf(msg, "入力画像「%s」が開けませんでした", fp.first.c_str()); - sprintf(msg, "入力画像が開けませんでした"); + case Waifu2x::eWaifu2xError_FailedOpenModelFile: + sprintf(msg, "モデルファイルが開けませんでした"); break; - case eWaifu2xError_FailedOpenOutputFile: - //sprintf(msg, "出力画像「%s」が書き込めませんでした", fp.second.c_str()); - sprintf(msg, "出力画像が書き込めませんでした"); + case Waifu2x::eWaifu2xError_FailedParseModelFile: + sprintf(msg, "モデルファイルが壊れています"); break; - case eWaifu2xError_FailedProcessCaffe: + case Waifu2x::eWaifu2xError_FailedConstructModel: + sprintf(msg, "ネットワークの構築に失敗しました"); + break; + } + } + else + { + const auto &fp = *(const std::pair *)lParam; + + switch (ret) + { + case Waifu2x::eWaifu2xError_Cancel: + sprintf(msg, "キャンセルされました"); + break; + case Waifu2x::eWaifu2xError_InvalidParameter: + sprintf(msg, "パラメータが不正です"); + break; + case Waifu2x::eWaifu2xError_FailedOpenInputFile: + sprintf(msg, "入力画像「%s」が開けませんでした", fp.first.c_str()); + break; + case Waifu2x::eWaifu2xError_FailedOpenOutputFile: + sprintf(msg, "出力画像を「%s」に書き込めませんでした", fp.second.c_str()); + break; + case Waifu2x::eWaifu2xError_FailedProcessCaffe: sprintf(msg, "補間処理に失敗しました"); break; } } - MessageBoxA(dh, msg, "エラー", MB_OK | MB_ICONERROR); + AddLogMessage(msg); - isLastError = true; + if (ret != Waifu2x::eWaifu2xError_Cancel) + isLastError = true; } } @@ -530,7 +568,7 @@ public: void CheckCUDNN(HWND hWnd, WPARAM wParam, LPARAM lParam, LPVOID lpData) { - if (can_use_cuDNN()) + if (Waifu2x::can_use_cuDNN()) MessageBox(dh, TEXT("cuDNNが使えます"), TEXT("結果"), MB_OK | MB_ICONINFORMATION); else MessageBox(dh, TEXT("cuDNNは使えません"), TEXT("結果"), MB_OK | MB_ICONERROR); @@ -664,9 +702,8 @@ int WINAPI WinMain(HINSTANCE hInstance, cDialog.SetEventCallBack(SetClassFunc(DialogEvent::Create, &cDialogEvent), NULL, WM_INITDIALOG); cDialog.SetEventCallBack(SetClassFunc(DialogEvent::OnDialogEnd, &cDialogEvent), NULL, WM_CLOSE); cDialog.SetEventCallBack(SetClassFunc(DialogEvent::OnFaildCreateDir, &cDialogEvent), NULL, WM_FAILD_CREATE_DIR); - cDialog.SetEventCallBack(SetClassFunc(DialogEvent::OnEndWaifu2x, &cDialogEvent), NULL, WM_END_WAIFU2X); + cDialog.SetEventCallBack(SetClassFunc(DialogEvent::OnWaifu2xError, &cDialogEvent), NULL, WM_ON_WAIFU2X_ERROR); cDialog.SetEventCallBack(SetClassFunc(DialogEvent::WaitThreadExit, &cDialogEvent), NULL, WM_END_THREAD); - cDialog.SetEventCallBack(SetClassFunc(DialogEvent::Waifu2xTime, &cDialogEvent), NULL, WM_TIME_WAIFU2X); // ダイアログを表示 cDialog.DoModal(hInstance, IDD_DIALOG); diff --git a/waifu2x-caffe/Source.cpp b/waifu2x-caffe/Source.cpp index d8319d9..3391123 100644 --- a/waifu2x-caffe/Source.cpp +++ b/waifu2x-caffe/Source.cpp @@ -120,7 +120,7 @@ int main(int argc, char** argv) if (outputExt.length() > 0 && outputExt[0] != '.') outputExt = "." + outputExt; - std::vector file_paths; + std::vector> file_paths; if (boost::filesystem::is_directory(input_path)) // input_pathがフォルダならそのディレクトリ以下の画像ファイルを一括変換 { boost::filesystem::path output_path; @@ -227,51 +227,58 @@ int main(int argc, char** argv) file_paths.emplace_back(cmdInputFile.getValue(), outputFileName); } - std::vector errors; - - const eWaifu2xError ret = waifu2x(argc, argv, file_paths, cmdMode.getValue(), cmdNRLevel.getValue(), cmdScaleRatio.getValue(), cmdModelPath.getValue(), cmdProcess.getValue(), errors); - if (ret != eWaifu2xError_OK || errors.size() > 0) + Waifu2x::eWaifu2xError ret; + Waifu2x w; + ret = w.init(argc, argv, cmdMode.getValue(), cmdNRLevel.getValue(), cmdScaleRatio.getValue(), cmdModelPath.getValue(), cmdProcess.getValue()); + switch (ret) { - switch (ret) - { - case eWaifu2xError_InvalidParameter: - printf("エラー: パラメータが不正です\n"); - break; - case eWaifu2xError_FailedOpenModelFile: - printf("エラー: モデルファイルが開けませんでした\n"); - break; - case eWaifu2xError_FailedParseModelFile: - printf("エラー: モデルファイルが壊れています\n"); - break; - case eWaifu2xError_FailedConstructModel: - printf("エラー: ネットワークの構築に失敗しました\n"); - break; - } - - for (const auto &ep : errors) - { - const auto &fp = ep.first; - - switch (ep.second) - { - case eWaifu2xError_InvalidParameter: - printf("エラー: パラメータが不正です\n"); - break; - case eWaifu2xError_FailedOpenInputFile: - printf("エラー: 入力画像「%s」が開けませんでした\n", fp.first.c_str()); - break; - case eWaifu2xError_FailedOpenOutputFile: - printf("エラー: 出力画像「%s」が書き込めませんでした\n", fp.second.c_str()); - break; - case eWaifu2xError_FailedProcessCaffe: - printf("エラー: 補間処理に失敗しました\n"); - break; - } - } - - printf("変換に失敗しました\n"); + case Waifu2x::eWaifu2xError_InvalidParameter: + printf("エラー: パラメータが不正です\n"); + return 1; + case Waifu2x::eWaifu2xError_FailedOpenModelFile: + printf("エラー: モデルファイルが開けませんでした\n"); + return 1; + case Waifu2x::eWaifu2xError_FailedParseModelFile: + printf("エラー: モデルファイルが壊れています\n"); + return 1; + case Waifu2x::eWaifu2xError_FailedConstructModel: + printf("エラー: ネットワークの構築に失敗しました\n"); return 1; } + bool isError = false; + for (const auto &p : file_paths) + { + const Waifu2x::eWaifu2xError ret = w.waifu2x(p.first, p.second); + if (ret != Waifu2x::eWaifu2xError_OK) + { + switch (ret) + { + case Waifu2x::eWaifu2xError_InvalidParameter: + printf("エラー: パラメータが不正です\n"); + break; + case Waifu2x::eWaifu2xError_FailedOpenInputFile: + printf("エラー: 入力画像「%s」が開けませんでした\n", p.first.c_str()); + break; + case Waifu2x::eWaifu2xError_FailedOpenOutputFile: + printf("エラー: 出力画像「%s」が書き込めませんでした\n", p.second.c_str()); + break; + case Waifu2x::eWaifu2xError_FailedProcessCaffe: + printf("エラー: 補間処理に失敗しました\n"); + break; + } + + isError = true; + } + } + + if (isError) + { + printf("変換に失敗したファイルがあります\n"); + return 1; + } + + printf("変換に成功しました\n"); + return 0; }