画像の微分を計算するdll
画像の微分
画像の微分というものを計算する方法としては、ラプシアンフィルタとかよく挙げられると思います。周囲のピクセルとの差をとるタイプのやつですね。あれって、近似的に求めているだけなのでなんだかもやもやします。
そこで、スプライン補間です。画像をスプライン補間すると、三次関数が分かります。その三次関数を微分してやればいいのです。というのが、このdllです。
プログラム
code:M_ImageGradient_Module.cpp
/*
M_ImageGradient_Module.cpp
*/
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 average_M(unsigned char a, unsigned char b) {
return std::max(std::min(((float)a + b) * 0.5 + 0.5, 255.0), 0.0);
}
unsigned char cf_M(double a, double b, double c, double d, double t) {
double s = ((a * t + b) * t + c) * t + d;
return std::max(std::min(s + 0.5, 255.0), 0.0);
}
unsigned char dcf_M(double a, double b, double c, double t, double k) {
double s = (3 * a * t + 2 * b) * t + c;
s *= k;
return std::min(std::abs(s) + 0.5, 255.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);
int scale_ = lua_tonumber(L, 7);
auto th_func = =(int i, int N, int data_w, int data_h, int ow, int oh, Pixel_RGBA* data, Pixel_RGBA* work) {
int Nw, ANw, Nh, ANh, sx, fx, sy, fy;
Nw = ow / N; ANw = ow % N;
Nh = data_h / N; ANh = data_h % N;
sx = Nw * i; fx = sx + Nw;
sy = Nh * i; fy = sy + Nh;
if (i == N - 1) { fx += ANw; fy += ANh; }
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++;
}
}
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);
{
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; });
}
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;
}
}
Nw = data_w / N; ANw = data_w % N;
Nh = oh / N; ANh = oh % N;
sx = Nw * i; fx = sx + Nw;
sy = Nh * i; fy = sy + Nh;
if (i == N - 1) { fx += ANw; fy += ANh; }
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;
}
}
ra.resize(data_w); rb.resize(data_w); rc.resize(data_w); rd.resize(data_w); rw.resize(data_w);
ga.resize(data_w); gb.resize(data_w); gc.resize(data_w); gd.resize(data_w); gw.resize(data_w);
ba.resize(data_w); bb.resize(data_w); bc.resize(data_w); bd.resize(data_w); bw.resize(data_w);
{
std::unique_lock<std::mutex> uniq_lk(mtx);
is_ready += 1;
if (is_ready >= 2 * is_ready_max) cv.notify_all();
else cv.wait(uniq_lk, [] { return (is_ready >= 2 * is_ready_max) ? true : false; });
}
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++;
}
}
};
int N = std::thread::hardware_concurrency();
if (N == 0) N++;
is_ready = 0;
is_ready_max = N;
std::vector<std::thread> th(N - 1);
for (int i = 0; i < N; ++i) {
if (i == N - 1) th_func(i, N, data_w, data_h, ow, oh, data, work);
else thi = std::thread(th_func, i, N, 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_M_ImageGradient_Module(lua_State* L) {
luaL_register(L, "M_ImageGradient_Module", functions);
return 1;
}
}
使用例
code:lua
local k=100*obj.time+100--100より大きい値
local scale=1--明るくする(1~
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("M_ImageGradient_Module")
d.run(data,work,w,h,ow,oh,scale)
obj.putpixeldata(data)
二次微分だと…
微分は、周囲とのRGB差と考えることができます。
では、二次微分だと、RGB差の勢いということになります。
更に、三次微分だと、RGB差の勢いの勢いということになります。
基本的に一次微分だけで充分だと思うのですが、画像の二次微分を使用することってあるんですかね?
by metaphysical bard