スプライン補間のリサイズ処理
リサイズをするdll
スプライン補間で、ピクセルの間を補間するリサイズdllです。拡大のみです。
modnameのところはお好きな名前でどうぞ。
プログラム
code:c++
std::mutex mtx;
std::condition_variable cv;
int is_ready;
int is_ready_max;
struct Pixel_RGBA {
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char a;
};
unsigned char cf_M(double a, double b, double c, double d, double t) {
//double s= (3 * a * t + 2 * b) * t + c;
//return std::min(std::abs(s) + 0.5, 255.0);
double s = ((a * t + b) * t + c) * t + d;
return std::max(std::min(s + 0.5, 255.0), 0.0);
}
void SolvSpline_M(int n, std::vector<double>& a, std::vector<double>& b, std::vector<double>& c, std::vector<double>& d, std::vector<double>& w) {
int n1 = n - 1;
for (int i = 1; i < n1; i++) bi = 3 * (di - 1 - 2 * di + di + 1); for (int i = 1; i < n; i++) {
}
for (int i = n - 2; i >= 0; i--) bi = bi - bi + 1 * wi; for (int i = 0; i < n1; i++) {
}
}
int run(lua_State* L) {
Pixel_RGBA* data = reinterpret_cast<Pixel_RGBA*>(lua_touserdata(L, 1));
Pixel_RGBA* work = reinterpret_cast<Pixel_RGBA*>(lua_touserdata(L, 2));
int data_w = lua_tointeger(L, 3);
int data_h = lua_tointeger(L, 4);
int ow = lua_tointeger(L, 5);
int oh = lua_tointeger(L, 6);
auto th_func = =(int sx, int fx, int sy, int fy, int data_w, int data_h, int ow, int oh, Pixel_RGBA* data, Pixel_RGBA* work) {
std::vector<double> ra(data_w), rb(data_w), rc(data_w), rd(data_w), rw(data_w);
std::vector<double> ga(data_w), gb(data_w), gc(data_w), gd(data_w), gw(data_w);
std::vector<double> ba(data_w), bb(data_w), bc(data_w), bd(data_w), bw(data_w);
for (int y = sy; y < fy; y++) {
int yw = y * ow;
int index = yw;
for (int x = 0; x < data_w; x++) {
index++;
}
SolvSpline_M(data_w, ra, rb, rc, rd, rw);
SolvSpline_M(data_w, ga, gb, gc, gd, gw);
SolvSpline_M(data_w, ba, bb, bc, bd, bw);
index = yw;
for (int x = 0; x < ow; x++) {
double pd = (double)x * ((double)data_w / ow);
int pix = std::min((int)pd, data_w - 2);
pd = pd - pix;
index++;
}
}
{
std::unique_lock<std::mutex> uniq_lk(mtx);
is_ready += 1;
if (is_ready >= is_ready_max) cv.notify_all();
else cv.wait(uniq_lk, [] { return (is_ready >= is_ready_max) ? true : false; });
}
ra.resize(data_h); rb.resize(data_h); rc.resize(data_h); rd.resize(data_h); rw.resize(data_h);
ga.resize(data_h); gb.resize(data_h); gc.resize(data_h); gd.resize(data_h); gw.resize(data_h);
ba.resize(data_h); bb.resize(data_h); bc.resize(data_h); bd.resize(data_h); bw.resize(data_h);
for (int x = sx; x < fx; x++) {
int index = x;
for (int y = 0; y < data_h; y++) {
index += ow;
}
SolvSpline_M(data_h, ra, rb, rc, rd, rw);
SolvSpline_M(data_h, ga, gb, gc, gd, gw);
SolvSpline_M(data_h, ba, bb, bc, bd, bw);
index = x;
for (int y = 0; y < oh; y++) {
double pd = (double)y * ((double)data_h / oh);
int pix = std::min((int)pd, data_h - 2);
pd = pd - pix;
index += ow;
}
}
};
int N, Nw, ANw, Nh, ANh;
N = std::thread::hardware_concurrency();
if (N == 0) N++;
Nw = ow / N;
ANw = ow % N;
Nh = data_h / N;
ANh = data_h % N;
is_ready = 0;
is_ready_max = N;
std::vector<std::thread> th(N - 1);
for (int i = 0; i < N; ++i) {
int sx = Nw * i;
int fx = sx + Nw;
int sy = Nh * i;
int fy = sy + Nh;
if (i == N - 1) {
fx += ANw;
fy += ANh;
th_func(sx, fx, sy, fy, data_w, data_h, ow, oh, data, work);
}
else thi = std::thread(th_func, sx, fx, sy, fy, data_w, data_h, ow, oh, data, work); }
for (int i = 0; i < N - 1; i++) thi.join(); return 0;
}
static luaL_Reg functions[] = {
{"run",run},
{nullptr,nullptr}
};
extern "C" {
__declspec(dllexport) int luaopen_modname(lua_State* L) {
luaL_register(L, "modname", functions);
return 1;
}
}
使用例
code:lua
local k=100--100より大きい値
k=k/100-1
local w,h=obj.w,obj.h
obj.effect("領域拡張","下",math.floor(h*k),"右",math.floor(w*k))
local work,data,ow,oh=obj.getpixeldata"work",obj.getpixeldata()
local d=require("modname")
d.run(data,work,w,h,ow,oh)
obj.putpixeldata(data)
精度は…
拡張編集に最初からそなわっているリサイズと拡大率と比較してみましたが、パッと見ただけでは違いが分かりませんでした。スプライン補間を使ったからといって、精度が劇的に良くなるわけではなさそうです。
by metaphysical bard