2016-07-03 13:37:26 +09:00
|
|
|
|
#include "stImage.h"
|
|
|
|
|
#include <boost/iostreams/stream.hpp>
|
|
|
|
|
#include <boost/iostreams/device/file_descriptor.hpp>
|
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
|
#include <opencv2/core.hpp>
|
|
|
|
|
#include <opencv2/imgproc.hpp>
|
|
|
|
|
#include <opencv2/imgcodecs.hpp>
|
|
|
|
|
|
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
|
|
|
#include <stb_image.h>
|
|
|
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
|
|
|
#include <stb_image_write.h>
|
|
|
|
|
|
|
|
|
|
const int YToRGBConvertMode = CV_GRAY2RGB;
|
|
|
|
|
const int YToRGBConverInversetMode = CV_RGB2GRAY;
|
|
|
|
|
const int BGRToYConvertMode = CV_BGR2YUV;
|
|
|
|
|
const int BGRToConvertInverseMode = CV_YUV2BGR;
|
|
|
|
|
|
|
|
|
|
// float<61>ȉ摜<C889><E6919C>uint8_t<5F>ȉ摜<C889>ɕϊ<C995><CF8A><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۂ̎l<CC8E>̌ܓ<CC8C><DC93>Ɏg<C98E><67><EFBFBD>l
|
|
|
|
|
// https://github.com/nagadomi/waifu2x/commit/797b45ae23665a1c5e3c481c018e48e6f0d0e383
|
|
|
|
|
const double clip_eps8 = (1.0 / 255.0) * 0.5 - (1.0e-7 * (1.0 / 255.0) * 0.5);
|
|
|
|
|
const double clip_eps16 = (1.0 / 65535.0) * 0.5 - (1.0e-7 * (1.0 / 65535.0) * 0.5);
|
|
|
|
|
const double clip_eps32 = 1.0 * 0.5 - (1.0e-7 * 0.5);
|
|
|
|
|
|
|
|
|
|
const std::vector<stImage::stOutputExtentionElement> stImage::OutputExtentionList =
|
|
|
|
|
{
|
|
|
|
|
{L".png",{8, 16}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".bmp",{8}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".jpg",{8}, 0, 100, 95, cv::IMWRITE_JPEG_QUALITY},
|
|
|
|
|
{L".jp2",{8, 16}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".sr",{8}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".tif",{8, 16, 32}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".hdr",{8, 16, 32}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".exr",{8, 16, 32}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".ppm",{8, 16}, boost::optional<int>(), boost::optional<int>(), boost::optional<int>(), boost::optional<int>()},
|
|
|
|
|
{L".webp",{8}, 1, 100, 100, cv::IMWRITE_WEBP_QUALITY},
|
|
|
|
|
{L".tga",{8}, 0, 1, 0, 0},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<typename BufType>
|
|
|
|
|
static bool readFile(boost::iostreams::stream<boost::iostreams::file_descriptor_source> &is, std::vector<BufType> &buf)
|
|
|
|
|
{
|
|
|
|
|
if (!is)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const auto size = is.seekg(0, std::ios::end).tellg();
|
|
|
|
|
is.seekg(0, std::ios::beg);
|
|
|
|
|
|
|
|
|
|
buf.resize((size / sizeof(BufType)) + (size % sizeof(BufType)));
|
|
|
|
|
is.read(buf.data(), size);
|
|
|
|
|
if (is.gcount() != size)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename BufType>
|
|
|
|
|
static bool readFile(const boost::filesystem::path &path, std::vector<BufType> &buf)
|
|
|
|
|
{
|
|
|
|
|
boost::iostreams::stream<boost::iostreams::file_descriptor_source> is;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
is.open(path, std::ios_base::in | std::ios_base::binary);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return readFile(is, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename BufType>
|
|
|
|
|
static bool writeFile(boost::iostreams::stream<boost::iostreams::file_descriptor> &os, const std::vector<BufType> &buf)
|
|
|
|
|
{
|
|
|
|
|
if (!os)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const auto WriteSize = sizeof(BufType) * buf.size();
|
|
|
|
|
os.write((const char *)buf.data(), WriteSize);
|
|
|
|
|
if (os.fail())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename BufType>
|
|
|
|
|
static bool writeFile(const boost::filesystem::path &path, std::vector<BufType> &buf)
|
|
|
|
|
{
|
|
|
|
|
boost::iostreams::stream<boost::iostreams::file_descriptor> os;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
os.open(path, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return writeFile(os, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Waifu2x_stbi_write_func(void *context, void *data, int size)
|
|
|
|
|
{
|
|
|
|
|
boost::iostreams::stream<boost::iostreams::file_descriptor> *osp = (boost::iostreams::stream<boost::iostreams::file_descriptor> *)context;
|
|
|
|
|
osp->write((const char *)data, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int stImage::DepthBitToCVDepth(const int depth_bit)
|
|
|
|
|
{
|
|
|
|
|
switch (depth_bit)
|
|
|
|
|
{
|
|
|
|
|
case 8:
|
|
|
|
|
return CV_8U;
|
|
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
|
return CV_16U;
|
|
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
|
return CV_32F;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǂƂ肠<C682><E882A0><EFBFBD><EFBFBD>CV_8U<38><55><EFBFBD>Ԃ<EFBFBD><D482>Ă<EFBFBD><C482><EFBFBD>
|
|
|
|
|
return CV_8U;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double stImage::GetValumeMaxFromCVDepth(const int cv_depth)
|
|
|
|
|
{
|
|
|
|
|
switch (cv_depth)
|
|
|
|
|
{
|
|
|
|
|
case CV_8U:
|
|
|
|
|
return 255.0;
|
|
|
|
|
|
|
|
|
|
case CV_16U:
|
|
|
|
|
return 65535.0;
|
|
|
|
|
|
|
|
|
|
case CV_32F:
|
|
|
|
|
return 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǂƂ肠<C682><E882A0><EFBFBD><EFBFBD>255.0<EFBFBD><EFBFBD><EFBFBD>Ԃ<EFBFBD><EFBFBD>Ă<EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
return 255.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double stImage::GetEPS(const int cv_depth)
|
|
|
|
|
{
|
|
|
|
|
switch (cv_depth)
|
|
|
|
|
{
|
|
|
|
|
case CV_8U:
|
|
|
|
|
return clip_eps8;
|
|
|
|
|
|
|
|
|
|
case CV_16U:
|
|
|
|
|
return clip_eps16;
|
|
|
|
|
|
|
|
|
|
case CV_32F:
|
|
|
|
|
return clip_eps32;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǂƂ肠<C682><E882A0><EFBFBD><EFBFBD>clip_eps8<73>Ԃ<EFBFBD><D482>Ă<EFBFBD><C482><EFBFBD>
|
|
|
|
|
return clip_eps8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::AlphaMakeBorder(std::vector<cv::Mat> &planes, const cv::Mat &alpha, const int offset)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD>̃J<CC83>[<5B>l<EFBFBD><6C><EFBFBD>Ɖ摜<C689>݂̏<F48D9E82><DD82>s<EFBFBD><73><EFBFBD>ƁA(x, y)<29>𒆐S<F0928690>Ƃ<EFBFBD><C682><EFBFBD>3<EFBFBD>~3<>̈<EFBFBD><CC88>̍<EFBFBD><CC8D>v<EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD>܂<EFBFBD>
|
|
|
|
|
const static cv::Mat sum2d_kernel = (cv::Mat_<double>(3, 3) <<
|
|
|
|
|
1., 1., 1.,
|
|
|
|
|
1., 1., 1.,
|
|
|
|
|
1., 1., 1.);
|
|
|
|
|
|
|
|
|
|
cv::Mat mask;
|
|
|
|
|
cv::threshold(alpha, mask, 0.0, 1.0, cv::THRESH_BINARY); // <20>A<EFBFBD><41><EFBFBD>t<EFBFBD>@<40>`<60><><EFBFBD><EFBFBD><EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD>ă}<7D>X<EFBFBD>N<EFBFBD>Ƃ<EFBFBD><C682>Ĉ<EFBFBD><C488><EFBFBD>
|
|
|
|
|
|
|
|
|
|
cv::Mat mask_nega;
|
|
|
|
|
cv::threshold(mask, mask_nega, 0.0, 1.0, cv::THRESH_BINARY_INV); // <20><><EFBFBD>]<5D><><EFBFBD><EFBFBD><EFBFBD>}<7D>X<EFBFBD>N<EFBFBD>i<EFBFBD>l<EFBFBD><6C>1<EFBFBD>̉ӏ<CC89><D38F>͊<EFBFBD><CD8A>S<EFBFBD><53><EFBFBD><EFBFBD><EFBFBD>łȂ<C582><C882>L<EFBFBD><4C><EFBFBD>ȉ<EFBFBD><C889>f<EFBFBD>ƂȂ<C682><C882>j
|
|
|
|
|
|
|
|
|
|
for (auto &p : planes) // <20><><EFBFBD>S<EFBFBD>ɓ<EFBFBD><C993><EFBFBD><EFBFBD>ȃs<C883>N<EFBFBD>Z<EFBFBD><5A><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD>S<EFBFBD>~<7E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
{
|
|
|
|
|
p = p.mul(mask);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < offset; i++)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat mask_weight;
|
|
|
|
|
cv::filter2D(mask, mask_weight, -1, sum2d_kernel, cv::Point(-1, -1), 0, cv::BORDER_DEFAULT); // <20>}<7D>X<EFBFBD>N<EFBFBD><4E>3<EFBFBD>~3<>̈<EFBFBD><CC88>̍<EFBFBD><CC8D>v<EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD>߂<EFBFBD>
|
|
|
|
|
|
|
|
|
|
cv::Mat mask_nega_u8;
|
|
|
|
|
mask_nega.convertTo(mask_nega_u8, CV_8U, 255.0, clip_eps8); // mask_nega<67><61>CV_U8<55>ŁiOpenCV<43><56>API<50><49><EFBFBD>K<EFBFBD>v<EFBFBD>ɂȂ<C982><C882>j
|
|
|
|
|
|
|
|
|
|
for (auto &p : planes) // 1<>`<60><><EFBFBD><EFBFBD><EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><C28F><EFBFBD>
|
|
|
|
|
{
|
|
|
|
|
// <20>`<60><><EFBFBD><EFBFBD><EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD>3<EFBFBD>~3<>̈<EFBFBD><CC88><EFBFBD><EFBFBD>̗L<CC97><4C><EFBFBD><EFBFBD><EFBFBD>f<EFBFBD>̕<EFBFBD><CC95>ϒl<CF92><6C><EFBFBD><EFBFBD><EFBFBD>߂<EFBFBD>
|
|
|
|
|
cv::Mat border;
|
|
|
|
|
cv::filter2D(p, border, -1, sum2d_kernel, cv::Point(-1, -1), 0, cv::BORDER_DEFAULT);
|
|
|
|
|
border /= mask_weight;
|
|
|
|
|
|
|
|
|
|
// <20>`<60><><EFBFBD><EFBFBD><EFBFBD>l<EFBFBD><6C><EFBFBD>̗L<CC97><4C><EFBFBD>ȉ<EFBFBD><C889>f<EFBFBD>̕<EFBFBD><CC95><EFBFBD><EFBFBD>ɁA<C981>v<EFBFBD>Z<EFBFBD><5A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϒl<CF92><6C><EFBFBD>R<EFBFBD>s<EFBFBD>[
|
|
|
|
|
border.copyTo(p, mask_nega_u8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>}<7D>X<EFBFBD>N<EFBFBD><4E>1<EFBFBD><31><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82>V<EFBFBD><56><EFBFBD><EFBFBD><EFBFBD>}<7D>X<EFBFBD>N<EFBFBD>Ƃ<EFBFBD><C682><EFBFBD>(<28>}<7D>X<EFBFBD>N<EFBFBD><4E>3<EFBFBD>~3<>̈<EFBFBD><CC88>̍<EFBFBD><CC8D>v<EFBFBD>l<EFBFBD><6C><EFBFBD><EFBFBD><EFBFBD>߂<EFBFBD><DF82><EFBFBD><EFBFBD>̂̔<CC82>0<EFBFBD>̈<EFBFBD><CC88>́A<CD81>}<7D>X<EFBFBD>N<EFBFBD><4E>1<EFBFBD><31><EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̗̂̈<CC97><CC88>ɓ<EFBFBD><C993><EFBFBD><EFBFBD><EFBFBD>)
|
|
|
|
|
cv::threshold(mask_weight, mask, 0.0, 1.0, cv::THRESH_BINARY);
|
|
|
|
|
// <20>V<EFBFBD><56><EFBFBD><EFBFBD><EFBFBD>}<7D>X<EFBFBD>N<EFBFBD>̔<EFBFBD><CC94>]<5D><><EFBFBD><EFBFBD><EFBFBD>}<7D>X<EFBFBD>N<EFBFBD><4E><EFBFBD>v<EFBFBD>Z
|
|
|
|
|
cv::threshold(mask, mask_nega, 0.0, 1.0, cv::THRESH_BINARY_INV);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>f<EFBFBD><66>0<EFBFBD><30><EFBFBD><EFBFBD>1<EFBFBD>ɃN<C983><4E><EFBFBD>b<EFBFBD>s<EFBFBD><73><EFBFBD>O
|
|
|
|
|
for (auto &p : planes)
|
|
|
|
|
{
|
|
|
|
|
cv::threshold(p, p, 1.0, 1.0, cv::THRESH_TRUNC);
|
|
|
|
|
cv::threshold(p, p, 0.0, 0.0, cv::THRESH_TOZERO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>摜<EFBFBD><E6919C><EFBFBD>ǂݍ<C782><DD8D><EFBFBD><EFBFBD>Œl<C592><6C>0.0f<EFBFBD>`1.0f<EFBFBD>͈̔͂ɕϊ<EFBFBD>
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::LoadMat(cv::Mat &im, const boost::filesystem::path &input_file)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat original_image;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::vector<char> img_data;
|
|
|
|
|
if (!readFile(input_file, img_data))
|
|
|
|
|
return Waifu2x::eWaifu2xError_FailedOpenInputFile;
|
|
|
|
|
|
|
|
|
|
cv::Mat im(img_data.size(), 1, CV_8U, img_data.data());
|
|
|
|
|
original_image = cv::imdecode(im, cv::IMREAD_UNCHANGED);
|
|
|
|
|
|
|
|
|
|
if (original_image.empty())
|
|
|
|
|
{
|
|
|
|
|
const Waifu2x::eWaifu2xError ret = LoadMatBySTBI(original_image, img_data);
|
|
|
|
|
if (ret != Waifu2x::eWaifu2xError_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
im = original_image;
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::LoadMatBySTBI(cv::Mat &im, const std::vector<char> &img_data)
|
|
|
|
|
{
|
|
|
|
|
int x, y, comp;
|
|
|
|
|
stbi_uc *data = stbi_load_from_memory((const stbi_uc *)img_data.data(), img_data.size(), &x, &y, &comp, 0);
|
|
|
|
|
if (!data)
|
|
|
|
|
return Waifu2x::eWaifu2xError_FailedOpenInputFile;
|
|
|
|
|
|
|
|
|
|
int type = 0;
|
|
|
|
|
switch (comp)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
case 3:
|
|
|
|
|
case 4:
|
|
|
|
|
type = CV_MAKETYPE(CV_8U, comp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return Waifu2x::eWaifu2xError_FailedOpenInputFile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
im = cv::Mat(cv::Size(x, y), type);
|
|
|
|
|
|
|
|
|
|
const auto LinePixel = im.step1() / im.channels();
|
|
|
|
|
const auto Channel = im.channels();
|
|
|
|
|
const auto Width = im.size().width;
|
|
|
|
|
const auto Height = im.size().height;
|
|
|
|
|
|
|
|
|
|
assert(x == Width);
|
|
|
|
|
assert(y == Height);
|
|
|
|
|
assert(Channel == comp);
|
|
|
|
|
|
|
|
|
|
auto ptr = im.data;
|
|
|
|
|
for (int i = 0; i < y; i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < x; j++)
|
|
|
|
|
{
|
|
|
|
|
for (int ch = 0; ch < Channel; ch++)
|
|
|
|
|
ptr[(i * LinePixel + j) * comp + ch] = data[(i * x + j) * comp + ch];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stbi_image_free(data);
|
|
|
|
|
|
|
|
|
|
if (comp >= 3)
|
|
|
|
|
{
|
|
|
|
|
// RGB<47><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>BGR<47>ɕϊ<C995>
|
|
|
|
|
for (int i = 0; i < y; i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < x; j++)
|
|
|
|
|
std::swap(ptr[(i * LinePixel + j) * comp + 0], ptr[(i * LinePixel + j) * comp + 2]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::Mat stImage::ConvertToFloat(const cv::Mat &im)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat convert;
|
|
|
|
|
switch (im.depth())
|
|
|
|
|
{
|
|
|
|
|
case CV_8U:
|
|
|
|
|
im.convertTo(convert, CV_32F, 1.0 / GetValumeMaxFromCVDepth(CV_8U));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CV_16U:
|
|
|
|
|
im.convertTo(convert, CV_32F, 1.0 / GetValumeMaxFromCVDepth(CV_16U));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CV_32F:
|
|
|
|
|
convert = im; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0.0<EFBFBD>`1.0<EFBFBD>̂͂<EFBFBD><EFBFBD>Ȃ̂ŕϊ<EFBFBD><EFBFBD>͕K<EFBFBD>v<EFBFBD>Ȃ<EFBFBD>
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return convert;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stImage::stImage() : mIsRequestDenoise(false), pad_w1(0), pad_h1(0), pad_w2(0), pad_h2(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stImage::~stImage()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::Clear()
|
|
|
|
|
{
|
|
|
|
|
mOrgFloatImage.release();
|
|
|
|
|
mTmpImageRGB.release();
|
|
|
|
|
mTmpImageA.release();
|
|
|
|
|
mEndImage.release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::Load(const boost::filesystem::path &input_file)
|
|
|
|
|
{
|
|
|
|
|
Clear();
|
|
|
|
|
|
|
|
|
|
Waifu2x::eWaifu2xError ret;
|
|
|
|
|
|
|
|
|
|
cv::Mat im;
|
|
|
|
|
ret = LoadMat(im, input_file);
|
|
|
|
|
if (ret != Waifu2x::eWaifu2xError_OK)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
mOrgFloatImage = im;
|
|
|
|
|
mOrgChannel = im.channels();
|
|
|
|
|
mOrgSize = 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");
|
|
|
|
|
|
|
|
|
|
mIsRequestDenoise = isJpeg;
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::Load(const void* source, const int width, const int height, const int channel, const int stride)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat original_image(cv::Size(width, height), CV_MAKETYPE(CV_8U, channel), (void *)source, stride);
|
|
|
|
|
|
|
|
|
|
if (original_image.channels() >= 3) // RGB<47>Ȃ̂<C882>BGR<47>ɂ<EFBFBD><C982><EFBFBD>
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> planes;
|
|
|
|
|
cv::split(original_image, planes);
|
|
|
|
|
|
|
|
|
|
std::swap(planes[0], planes[2]);
|
|
|
|
|
|
|
|
|
|
cv::merge(planes, original_image);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mOrgFloatImage = original_image;
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-03 21:55:20 +09:00
|
|
|
|
double stImage::GetScaleFromWidth(const int width) const
|
|
|
|
|
{
|
|
|
|
|
return (double)width / (double)mOrgSize.width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double stImage::GetScaleFromHeight(const int height) const
|
|
|
|
|
{
|
|
|
|
|
return (double)height / (double)mOrgSize.height;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-03 13:37:26 +09:00
|
|
|
|
bool stImage::RequestDenoise() const
|
|
|
|
|
{
|
|
|
|
|
return mIsRequestDenoise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::Preprocess(const int input_plane, const int net_offset)
|
|
|
|
|
{
|
|
|
|
|
mOrgFloatImage = ConvertToFloat(mOrgFloatImage);
|
|
|
|
|
|
|
|
|
|
ConvertToNetFormat(input_plane, net_offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::ConvertToNetFormat(const int input_plane, const int alpha_offset)
|
|
|
|
|
{
|
|
|
|
|
if (input_plane == 1) // Y<><59><EFBFBD>f<EFBFBD><66>
|
|
|
|
|
{
|
|
|
|
|
if (mOrgFloatImage.channels() == 1) // 1ch<63><68><EFBFBD><EFBFBD><EFBFBD>Ȃ̂ł<CC82><C582>̂܂<CC82>
|
|
|
|
|
mTmpImageRGB = mOrgFloatImage;
|
|
|
|
|
else // BGR<47>Ȃ̂ŕϊ<C595>
|
|
|
|
|
{
|
|
|
|
|
mTmpImageRGB = mOrgFloatImage;
|
|
|
|
|
|
|
|
|
|
if (mTmpImageRGB.channels() == 4) // BGRA<52>Ȃ̂<C882>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD><6F>
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> planes;
|
|
|
|
|
cv::split(mTmpImageRGB, planes);
|
|
|
|
|
|
|
|
|
|
mTmpImageA = planes[3];
|
|
|
|
|
planes.resize(3);
|
|
|
|
|
|
|
|
|
|
AlphaMakeBorder(planes, mTmpImageA, alpha_offset); // <20><><EFBFBD><EFBFBD><EFBFBD>ȃs<C883>N<EFBFBD>Z<EFBFBD><5A><EFBFBD>ƕs<C695><73><EFBFBD><EFBFBD><EFBFBD>ȃs<C883>N<EFBFBD>Z<EFBFBD><5A><EFBFBD>̋<EFBFBD><CC8B>E<EFBFBD><45><EFBFBD><EFBFBD><EFBFBD>̐F<CC90><46><EFBFBD>L<EFBFBD><4C><EFBFBD><EFBFBD>
|
|
|
|
|
|
2016-07-03 21:31:10 +09:00
|
|
|
|
// CreateBrightnessImage()<29><>BGR<47><52><EFBFBD><EFBFBD>Y<EFBFBD>ɕϊ<C995><CF8A><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂œ<CC82><C593><EFBFBD>RGB<47>ɕς<C995><CF82><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͂<EFBFBD><CD82>Ȃ<EFBFBD>
|
2016-07-03 13:37:26 +09:00
|
|
|
|
cv::merge(planes, mTmpImageRGB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CreateBrightnessImage(mTmpImageRGB, mTmpImageRGB);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // RGB<47><42><EFBFBD>f<EFBFBD><66>
|
|
|
|
|
{
|
|
|
|
|
if (mOrgFloatImage.channels() == 1) // 1ch<63><68><EFBFBD><EFBFBD><EFBFBD>Ȃ̂<C882>RGB<47>ɕϊ<C995>
|
|
|
|
|
{
|
|
|
|
|
cv::cvtColor(mOrgFloatImage, mTmpImageRGB, YToRGBConvertMode);
|
|
|
|
|
mOrgFloatImage.release();
|
|
|
|
|
}
|
|
|
|
|
else // BGR<47><52><EFBFBD><EFBFBD>RGB<47>ɕϊ<C995>(A<><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD><6F>)
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> planes;
|
|
|
|
|
cv::split(mOrgFloatImage, planes);
|
|
|
|
|
mOrgFloatImage.release();
|
|
|
|
|
|
|
|
|
|
if (planes.size() == 4) // BGRA<52>Ȃ̂<C882>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD><6F>
|
|
|
|
|
{
|
|
|
|
|
mTmpImageA = planes[3];
|
|
|
|
|
planes.resize(3);
|
|
|
|
|
|
|
|
|
|
AlphaMakeBorder(planes, mTmpImageA, alpha_offset); // <20><><EFBFBD><EFBFBD><EFBFBD>ȃs<C883>N<EFBFBD>Z<EFBFBD><5A><EFBFBD>ƕs<C695><73><EFBFBD><EFBFBD><EFBFBD>ȃs<C883>N<EFBFBD>Z<EFBFBD><5A><EFBFBD>̋<EFBFBD><CC8B>E<EFBFBD><45><EFBFBD><EFBFBD><EFBFBD>̐F<CC90><46><EFBFBD>L<EFBFBD><4C><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>g<EFBFBD><67><EFBFBD>p<EFBFBD><70>RGB<47>ɕϊ<C995>
|
|
|
|
|
cv::cvtColor(mTmpImageA, mTmpImageA, CV_GRAY2RGB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BGR<47><52><EFBFBD><EFBFBD>RGB<47>ɂ<EFBFBD><C982><EFBFBD>
|
|
|
|
|
std::swap(planes[0], planes[2]);
|
|
|
|
|
|
|
|
|
|
cv::merge(planes, mTmpImageRGB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mOrgFloatImage.release();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>摜<EFBFBD><E6919C><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>x<EFBFBD>̉摜<CC89><E6919C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD><6F>
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::CreateBrightnessImage(const cv::Mat &float_image, cv::Mat &im)
|
|
|
|
|
{
|
|
|
|
|
if (float_image.channels() > 1)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat converted_color;
|
|
|
|
|
cv::cvtColor(float_image, converted_color, BGRToYConvertMode);
|
|
|
|
|
|
|
|
|
|
std::vector<cv::Mat> planes;
|
|
|
|
|
cv::split(converted_color, planes);
|
|
|
|
|
|
|
|
|
|
im = planes[0];
|
|
|
|
|
planes.clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
im = float_image;
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool stImage::HasAlpha() const
|
|
|
|
|
{
|
|
|
|
|
return !mTmpImageA.empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::GetScalePaddingedRGB(cv::Mat &im, cv::Size_<int> &size, const int net_offset, const int outer_padding,
|
|
|
|
|
const int crop_w, const int crop_h, const int scale)
|
|
|
|
|
{
|
|
|
|
|
GetScalePaddingedImage(mTmpImageRGB, im, size, net_offset, outer_padding, crop_w, crop_h, scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::SetReconstructedRGB(cv::Mat &im, const cv::Size_<int> &size, const int inner_scale)
|
|
|
|
|
{
|
|
|
|
|
SetReconstructedImage(mTmpImageRGB, im, size, inner_scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::GetScalePaddingedA(cv::Mat &im, cv::Size_<int> &size, const int net_offset, const int outer_padding,
|
|
|
|
|
const int crop_w, const int crop_h, const int scale)
|
|
|
|
|
{
|
|
|
|
|
GetScalePaddingedImage(mTmpImageA, im, size, net_offset, outer_padding, crop_w, crop_h, scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::SetReconstructedA(cv::Mat &im, const cv::Size_<int> &size, const int inner_scale)
|
|
|
|
|
{
|
|
|
|
|
SetReconstructedImage(mTmpImageA, im, size, inner_scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::GetScalePaddingedImage(cv::Mat &in, cv::Mat &out, cv::Size_<int> &size, const int net_offset, const int outer_padding,
|
|
|
|
|
const int crop_w, const int crop_h, const int scale)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat ret;
|
|
|
|
|
|
|
|
|
|
if (scale > 1)
|
|
|
|
|
{
|
|
|
|
|
cv::Size_<int> zoom_size = in.size();
|
|
|
|
|
zoom_size.width *= scale;
|
|
|
|
|
zoom_size.height *= scale;
|
|
|
|
|
|
|
|
|
|
cv::resize(in, ret, zoom_size, 0.0, 0.0, cv::INTER_NEAREST);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ret = in;
|
|
|
|
|
|
|
|
|
|
in.release();
|
|
|
|
|
|
|
|
|
|
size = ret.size();
|
|
|
|
|
|
|
|
|
|
PaddingImage(ret, net_offset, outer_padding, crop_w, crop_h, ret);
|
|
|
|
|
|
|
|
|
|
out = ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>͉摜<CD89><E6919C>(Photoshop<6F>ł<EFBFBD><C582><EFBFBD>)<29>L<EFBFBD><4C><EFBFBD><EFBFBD><EFBFBD>o<EFBFBD>X<EFBFBD>T<EFBFBD>C<EFBFBD>Y<EFBFBD><59>output_size<7A>̔{<7B><><EFBFBD>ɕύX
|
|
|
|
|
// <20>摜<EFBFBD>͍<EFBFBD><CD8D><EFBFBD><EFBFBD>z<EFBFBD>u<EFBFBD>A<EFBFBD>]<5D><><EFBFBD><EFBFBD>cv::BORDER_REPLICATE<54>Ŗ<EFBFBD><C596>߂<EFBFBD>
|
|
|
|
|
void stImage::PaddingImage(const cv::Mat &input, const int net_offset, const int outer_padding,
|
|
|
|
|
const int crop_w, const int crop_h, cv::Mat &output)
|
|
|
|
|
{
|
|
|
|
|
const auto pad_w1 = net_offset + outer_padding;
|
|
|
|
|
const auto pad_h1 = net_offset + outer_padding;
|
|
|
|
|
const auto pad_w2 = (int)ceil((double)input.size().width / (double)crop_w) * crop_w - input.size().width + net_offset + outer_padding;
|
|
|
|
|
const auto pad_h2 = (int)ceil((double)input.size().height / (double)crop_h) * crop_h - input.size().height + net_offset + outer_padding;
|
|
|
|
|
|
|
|
|
|
cv::copyMakeBorder(input, output, pad_h1, pad_h2, pad_w1, pad_w2, cv::BORDER_REPLICATE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>g<EFBFBD><67><EFBFBD>A<EFBFBD>p<EFBFBD>f<EFBFBD>B<EFBFBD><42><EFBFBD>O<EFBFBD><4F><EFBFBD>ꂽ<EFBFBD>摜<EFBFBD><E6919C><EFBFBD>ݒ<EFBFBD>
|
|
|
|
|
void stImage::SetReconstructedImage(cv::Mat &dst, cv::Mat &src, const cv::Size_<int> &size, const int inner_scale)
|
|
|
|
|
{
|
|
|
|
|
const cv::Size_<int> s(size * inner_scale);
|
|
|
|
|
|
|
|
|
|
// <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>T<EFBFBD>C<EFBFBD>Y<EFBFBD>p<EFBFBD>̃p<CC83>f<EFBFBD>B<EFBFBD><42><EFBFBD>O<EFBFBD><4F><EFBFBD><EFBFBD><EFBFBD>蕥<EFBFBD><E895A5>(outer_padding<6E>͍č\<5C>z<EFBFBD>̉ߒ<CC89><DF92>Ŏ<EFBFBD><C58E>菜<EFBFBD><E88F9C><EFBFBD><EFBFBD><EFBFBD>Ă<EFBFBD><C482><EFBFBD>)
|
|
|
|
|
dst = src(cv::Rect(0, 0, s.width, s.height));
|
|
|
|
|
|
|
|
|
|
src.release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::Postprocess(const int input_plane, const double scale, const int depth)
|
|
|
|
|
{
|
|
|
|
|
DeconvertFromNetFormat(input_plane);
|
|
|
|
|
ShrinkImage(scale);
|
|
|
|
|
|
|
|
|
|
// <20>l<EFBFBD><6C>0<EFBFBD>`1<>ɃN<C983><4E><EFBFBD>b<EFBFBD>s<EFBFBD><73><EFBFBD>O
|
|
|
|
|
cv::threshold(mEndImage, mEndImage, 1.0, 1.0, cv::THRESH_TRUNC);
|
|
|
|
|
cv::threshold(mEndImage, mEndImage, 0.0, 0.0, cv::THRESH_TOZERO);
|
|
|
|
|
|
|
|
|
|
mEndImage = DeconvertFromFloat(mEndImage, depth);
|
|
|
|
|
|
|
|
|
|
AlphaCleanImage(mEndImage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::DeconvertFromNetFormat(const int input_plane)
|
|
|
|
|
{
|
|
|
|
|
if (input_plane == 1) // Y<><59><EFBFBD>f<EFBFBD><66>
|
|
|
|
|
{
|
|
|
|
|
if (mOrgChannel == 1) // <20><><EFBFBD>Ƃ<EFBFBD><C682><EFBFBD>1ch<63><68><EFBFBD><EFBFBD><EFBFBD>Ȃ̂ł<CC82><C582>̂܂<CC82>
|
|
|
|
|
{
|
|
|
|
|
mEndImage = mTmpImageRGB;
|
|
|
|
|
mTmpImageRGB.release();
|
|
|
|
|
mOrgFloatImage.release();
|
|
|
|
|
}
|
|
|
|
|
else // <20><><EFBFBD>Ƃ<EFBFBD><C682><EFBFBD>BGR<47>Ȃ̂Ŋ<CC82><C58A><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD>S<EFBFBD><53><EFBFBD>Y<EFBFBD><59><EFBFBD>Ŋg<C58A>債<EFBFBD><E582B5>UV<55>Ɋg<C98A>債<EFBFBD><E582B5>Y<EFBFBD><59><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82>Ė߂<C496>
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> color_planes;
|
|
|
|
|
CreateZoomColorImage(mOrgFloatImage, mTmpImageRGB.size(), color_planes);
|
|
|
|
|
mOrgFloatImage.release();
|
|
|
|
|
|
|
|
|
|
color_planes[0] = mTmpImageRGB;
|
|
|
|
|
mTmpImageRGB.release();
|
|
|
|
|
|
|
|
|
|
cv::Mat converted_image;
|
|
|
|
|
cv::merge(color_planes, converted_image);
|
|
|
|
|
color_planes.clear();
|
|
|
|
|
|
|
|
|
|
cv::cvtColor(converted_image, mEndImage, BGRToConvertInverseMode);
|
|
|
|
|
converted_image.release();
|
2016-07-03 21:31:10 +09:00
|
|
|
|
|
|
|
|
|
if (!mTmpImageA.empty()) // A<><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂ō<CC82><C58D><EFBFBD>
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> planes;
|
|
|
|
|
cv::split(mEndImage, planes);
|
|
|
|
|
|
|
|
|
|
planes.push_back(mTmpImageA);
|
|
|
|
|
mTmpImageA.release();
|
|
|
|
|
|
|
|
|
|
cv::merge(planes, mEndImage);
|
|
|
|
|
}
|
2016-07-03 13:37:26 +09:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // RGB<47><42><EFBFBD>f<EFBFBD><66>
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>̒n<CC92>_<EFBFBD><5F>mOrgFloatImage<67>͋<EFBFBD>
|
|
|
|
|
|
|
|
|
|
if (mOrgChannel == 1) // <20><><EFBFBD>Ƃ<EFBFBD><C682><EFBFBD>1ch<63><68><EFBFBD><EFBFBD><EFBFBD>Ȃ̂Ŗ߂<C596>
|
|
|
|
|
{
|
|
|
|
|
cv::cvtColor(mTmpImageRGB, mEndImage, YToRGBConverInversetMode);
|
|
|
|
|
mTmpImageRGB.release();
|
|
|
|
|
}
|
|
|
|
|
else // <20><><EFBFBD>Ƃ<EFBFBD><C682><EFBFBD>BGR<47>Ȃ̂<C882>RGB<47><42><EFBFBD><EFBFBD><EFBFBD>߂<EFBFBD>(A<><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>̂<EFBFBD><CC82>Ė߂<C496>)
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> planes;
|
|
|
|
|
cv::split(mTmpImageRGB, planes);
|
|
|
|
|
mTmpImageRGB.release();
|
|
|
|
|
|
|
|
|
|
if (!mTmpImageA.empty()) // A<><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂ō<CC82><C58D><EFBFBD>
|
|
|
|
|
{
|
|
|
|
|
// RGB<47><42><EFBFBD><EFBFBD>1ch<63>ɖ߂<C996>
|
|
|
|
|
cv::cvtColor(mTmpImageA, mTmpImageA, CV_RGB2GRAY);
|
|
|
|
|
|
|
|
|
|
planes.push_back(mTmpImageA);
|
|
|
|
|
mTmpImageA.release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RGB<47><42><EFBFBD><EFBFBD>BGR<47>ɂ<EFBFBD><C982><EFBFBD>
|
|
|
|
|
std::swap(planes[0], planes[2]);
|
|
|
|
|
|
|
|
|
|
cv::merge(planes, mEndImage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::ShrinkImage(const double scale)
|
|
|
|
|
{
|
|
|
|
|
// TODO: scale = 1.0 <20>ł<EFBFBD><C582><EFBFBD><EFBFBD>e<EFBFBD><65><EFBFBD><EFBFBD><EFBFBD>y<EFBFBD>ڂ<EFBFBD><DA82>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ׂ<EFBFBD>
|
|
|
|
|
|
|
|
|
|
const int scaleBase = 2; // TODO: <20><><EFBFBD>f<EFBFBD><66><EFBFBD>̊g<CC8A>嗦<EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD>ĉςł<CF82><C582><EFBFBD><EFBFBD>悤<EFBFBD>ɂ<EFBFBD><C982><EFBFBD>
|
|
|
|
|
|
|
|
|
|
const int scaleNum = ceil(log(scale) / log(scaleBase));
|
|
|
|
|
const double shrinkRatio = scale >= 1.0 ? scale / std::pow(scaleBase, scaleNum) : scale;
|
|
|
|
|
|
|
|
|
|
const cv::Size_<int> ns(mOrgSize.width * scale, mOrgSize.height * scale);
|
2016-07-03 17:13:02 +09:00
|
|
|
|
if (mEndImage.size().width != ns.width || mEndImage.size().height != ns.height)
|
|
|
|
|
{
|
|
|
|
|
int argo = cv::INTER_CUBIC;
|
|
|
|
|
if (scale < 0.5)
|
|
|
|
|
argo = cv::INTER_AREA;
|
|
|
|
|
|
|
|
|
|
cv::resize(mEndImage, mEndImage, ns, 0.0, 0.0, argo);
|
|
|
|
|
}
|
2016-07-03 13:37:26 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::Mat stImage::DeconvertFromFloat(const cv::Mat &im, const int depth)
|
|
|
|
|
{
|
|
|
|
|
const int cv_depth = DepthBitToCVDepth(depth);
|
|
|
|
|
const double max_val = GetValumeMaxFromCVDepth(cv_depth);
|
|
|
|
|
const double eps = GetEPS(cv_depth);
|
|
|
|
|
|
|
|
|
|
cv::Mat ret;
|
|
|
|
|
if (depth == 32) // <20>o<EFBFBD>͂<EFBFBD>float<61>`<60><><EFBFBD>Ȃ<EFBFBD><C882>ϊ<EFBFBD><CF8A><EFBFBD><EFBFBD>Ȃ<EFBFBD>
|
|
|
|
|
ret = im;
|
|
|
|
|
else
|
|
|
|
|
im.convertTo(ret, cv_depth, max_val, eps);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
template<typename T>
|
|
|
|
|
void AlphaZeroToZero(std::vector<cv::Mat> &planes)
|
|
|
|
|
{
|
|
|
|
|
cv::Mat alpha(planes[3]);
|
|
|
|
|
|
|
|
|
|
const T *aptr = (const T *)alpha.data;
|
|
|
|
|
|
|
|
|
|
T *ptr0 = (T *)planes[0].data;
|
|
|
|
|
T *ptr1 = (T *)planes[1].data;
|
|
|
|
|
T *ptr2 = (T *)planes[2].data;
|
|
|
|
|
|
|
|
|
|
const size_t Line = alpha.step1();
|
|
|
|
|
const size_t Width = alpha.size().width;
|
|
|
|
|
const size_t Height = alpha.size().height;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < Height; i++)
|
|
|
|
|
{
|
|
|
|
|
for (size_t j = 0; j < Width; j++)
|
|
|
|
|
{
|
|
|
|
|
const size_t pos = Line * i + j;
|
|
|
|
|
|
|
|
|
|
if (aptr[pos] == (T)0)
|
|
|
|
|
ptr0[pos] = ptr1[pos] = ptr2[pos] = (T)0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void stImage::AlphaCleanImage(cv::Mat &im)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD>S<EFBFBD><53><EFBFBD><EFBFBD><EFBFBD>̃s<CC83>N<EFBFBD>Z<EFBFBD><5A><EFBFBD>̐F<CC90><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD>̓s<CC93><73><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD>S<EFBFBD><53><EFBFBD><EFBFBD><EFBFBD>̃s<CC83>N<EFBFBD>Z<EFBFBD><5A><EFBFBD>ɂ<EFBFBD><C982>F<EFBFBD><46><EFBFBD>t<EFBFBD><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
|
|
|
// <20><><EFBFBD>f<EFBFBD><66><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD>Ă͉摜<CD89>S<EFBFBD><53><EFBFBD>̊<EFBFBD><CC8A>S<EFBFBD><53><EFBFBD><EFBFBD><EFBFBD>̏ꏊ<CC8F>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>l<EFBFBD>̃A<CC83><41><EFBFBD>t<EFBFBD>@<40><><EFBFBD>L<EFBFBD><4C><EFBFBD>邱<EFBFBD>Ƃ<EFBFBD><C682><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߂<EFBFBD>cv_depth<74>֕ϊ<D695><CF8A><EFBFBD><EFBFBD>Ă<EFBFBD><C482>炱<EFBFBD>̏<EFBFBD><CC8F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD>Ƃɂ<C682><C982><EFBFBD>
|
|
|
|
|
// (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>cv_depth<74><68>32<33>̏ꍇ<CC8F><EA8D87><EFBFBD>ƈӖ<C688><D396>͖<EFBFBD><CD96><EFBFBD><EFBFBD><EFBFBD>)
|
|
|
|
|
// TODO: <20><><EFBFBD>f<EFBFBD><66>(<28>Ⴆ<EFBFBD><E182A6>Photo)<29>ɂ<EFBFBD><C982><EFBFBD><EFBFBD>Ă<EFBFBD>0<EFBFBD><30><EFBFBD><EFBFBD><EFBFBD>Ȃ<EFBFBD><C882>摜<EFBFBD><E6919C><EFBFBD>ϊ<EFBFBD><CF8A><EFBFBD><EFBFBD>Ă<EFBFBD>0.000114856390<EFBFBD>Ƃ<EFBFBD><EFBFBD>ɂȂ<EFBFBD><EFBFBD>̂ŁA<EFBFBD>K<EFBFBD>Ȓl<EFBFBD>̃N<EFBFBD><EFBFBD><EFBFBD>b<EFBFBD>s<EFBFBD><EFBFBD><EFBFBD>O<EFBFBD><EFBFBD><EFBFBD>s<EFBFBD><EFBFBD><EFBFBD>H
|
|
|
|
|
if (im.channels() > 3)
|
|
|
|
|
{
|
|
|
|
|
std::vector<cv::Mat> planes;
|
|
|
|
|
cv::split(im, planes);
|
|
|
|
|
im.release();
|
|
|
|
|
|
|
|
|
|
const auto depth = planes[0].depth();
|
|
|
|
|
switch (depth)
|
|
|
|
|
{
|
|
|
|
|
case CV_8U:
|
|
|
|
|
AlphaZeroToZero<uint8_t>(planes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CV_16U:
|
|
|
|
|
AlphaZeroToZero<uint16_t>(planes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CV_32F:
|
|
|
|
|
AlphaZeroToZero<float>(planes);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CV_64F:
|
|
|
|
|
AlphaZeroToZero<double>(planes);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::merge(planes, im);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>͉摜<CD89><E6919C>zoom_size<7A>̑傫<CC91><E582AB><EFBFBD><EFBFBD>cv::INTER_CUBIC<49>Ŋg<C58A>債<EFBFBD>A<EFBFBD>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD>݂̂<CC82><DD82>c<EFBFBD><63>
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::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, BGRToYConvertMode);
|
|
|
|
|
zoom_cubic_image.release();
|
|
|
|
|
|
|
|
|
|
cv::split(converted_cubic_image, cubic_planes);
|
|
|
|
|
converted_cubic_image.release();
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>Y<EFBFBD><59><EFBFBD><EFBFBD><EFBFBD>͎g<CD8E><67><EFBFBD>Ȃ<EFBFBD><C882>̂ʼn<CC82><C589><EFBFBD>
|
|
|
|
|
cubic_planes[0].release();
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cv::Mat stImage::GetEndImage() const
|
|
|
|
|
{
|
|
|
|
|
return mEndImage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::Save(const boost::filesystem::path &output_file, const boost::optional<int> &output_quality)
|
|
|
|
|
{
|
|
|
|
|
return WriteMat(mEndImage, output_file, output_quality);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Waifu2x::eWaifu2xError stImage::WriteMat(const cv::Mat &im, const boost::filesystem::path &output_file, const boost::optional<int> &output_quality)
|
|
|
|
|
{
|
|
|
|
|
const boost::filesystem::path ip(output_file);
|
|
|
|
|
const std::string ext = ip.extension().string();
|
|
|
|
|
|
|
|
|
|
if (boost::iequals(ext, ".tga"))
|
|
|
|
|
{
|
|
|
|
|
unsigned char *data = im.data;
|
|
|
|
|
|
|
|
|
|
std::vector<unsigned char> rgbimg;
|
|
|
|
|
if (im.channels() >= 3 || im.step1() != im.size().width * im.channels()) // RGB<47>p<EFBFBD>o<EFBFBD>b<EFBFBD>t<EFBFBD>@<40>ɃR<C983>s<EFBFBD>[(<28><><EFBFBD>邢<EFBFBD>̓p<CD83>f<EFBFBD>B<EFBFBD><42><EFBFBD>O<EFBFBD><4F><EFBFBD>Ƃ<EFBFBD>)
|
|
|
|
|
{
|
|
|
|
|
const auto Line = im.step1();
|
|
|
|
|
const auto Channel = im.channels();
|
|
|
|
|
const auto Width = im.size().width;
|
|
|
|
|
const auto Height = im.size().height;
|
|
|
|
|
|
|
|
|
|
rgbimg.resize(Width * Height * Channel);
|
|
|
|
|
|
|
|
|
|
const auto Stride = Width * Channel;
|
|
|
|
|
for (int i = 0; i < Height; i++)
|
|
|
|
|
memcpy(rgbimg.data() + Stride * i, im.data + Line * i, Stride);
|
|
|
|
|
|
|
|
|
|
data = rgbimg.data();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (im.channels() >= 3) // BGR<47><52>RGB<47>ɕ<EFBFBD><C995>ёւ<D191>
|
|
|
|
|
{
|
|
|
|
|
const auto Line = im.step1();
|
|
|
|
|
const auto Channel = im.channels();
|
|
|
|
|
const auto Width = im.size().width;
|
|
|
|
|
const auto Height = im.size().height;
|
|
|
|
|
|
|
|
|
|
auto ptr = rgbimg.data();
|
|
|
|
|
for (int i = 0; i < Height; i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < Width; j++)
|
|
|
|
|
std::swap(ptr[(i * Width + j) * Channel + 0], ptr[(i * Width + j) * Channel + 2]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boost::iostreams::stream<boost::iostreams::file_descriptor> os;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
os.open(output_file, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
return Waifu2x::eWaifu2xError_FailedOpenOutputFile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!os)
|
|
|
|
|
return Waifu2x::eWaifu2xError_FailedOpenOutputFile;
|
|
|
|
|
|
|
|
|
|
// RLE<4C><45><EFBFBD>k<EFBFBD>̐ݒ<CC90>
|
|
|
|
|
bool isSet = false;
|
|
|
|
|
const auto &OutputExtentionList = stImage::OutputExtentionList;
|
|
|
|
|
for (const auto &elm : OutputExtentionList)
|
|
|
|
|
{
|
|
|
|
|
if (elm.ext == L".tga")
|
|
|
|
|
{
|
|
|
|
|
if (elm.imageQualitySettingVolume && output_quality)
|
|
|
|
|
{
|
|
|
|
|
stbi_write_tga_with_rle = *output_quality;
|
|
|
|
|
isSet = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>ݒ肳<DD92><E882B3><EFBFBD>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂Ńf<C583>t<EFBFBD>H<EFBFBD><48><EFBFBD>g<EFBFBD>ɂ<EFBFBD><C982><EFBFBD>
|
|
|
|
|
if (!isSet)
|
|
|
|
|
stbi_write_tga_with_rle = 1;
|
|
|
|
|
|
|
|
|
|
if (!stbi_write_tga_to_func(Waifu2x_stbi_write_func, &os, im.size().width, im.size().height, im.channels(), data))
|
|
|
|
|
return Waifu2x::eWaifu2xError_FailedOpenOutputFile;
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
const boost::filesystem::path op(output_file);
|
|
|
|
|
const boost::filesystem::path opext(op.extension());
|
|
|
|
|
|
|
|
|
|
std::vector<int> params;
|
|
|
|
|
|
|
|
|
|
const auto &OutputExtentionList = stImage::OutputExtentionList;
|
|
|
|
|
for (const auto &elm : OutputExtentionList)
|
|
|
|
|
{
|
|
|
|
|
if (elm.ext == opext)
|
|
|
|
|
{
|
|
|
|
|
if (elm.imageQualitySettingVolume && output_quality)
|
|
|
|
|
{
|
|
|
|
|
params.push_back(*elm.imageQualitySettingVolume);
|
|
|
|
|
params.push_back(*output_quality);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<uchar> buf;
|
|
|
|
|
cv::imencode(ext, im, buf, params);
|
|
|
|
|
|
|
|
|
|
if (writeFile(output_file, buf))
|
|
|
|
|
return Waifu2x::eWaifu2xError_OK;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Waifu2x::eWaifu2xError_FailedOpenOutputFile;
|
|
|
|
|
}
|