この記事はアドカレに参加しています。
luajitでボックスブラー
luajitでボックスブラーをやっていきます。
とはいえ、luajitもスクリプト言語。速度はあまり期待できないです。
ボックスブラーとは
ボックスブラーとはその名の通りボックス(箱)の形でぼかしていく画像処理です。任意ピクセルとその周囲の平均から色を求めていきます。
アルゴリズム
先人の方達が素晴らしいアルゴリズムを共有してくださっています。
今回はそれをそのまま使います。
言語不問で実装する高速な移動平均処理
フィルタ処理の高速化アルゴリズム(縦横に処理を分ける)
gaussian フィルタ
要点は二つあります。
1.二次元的な処理を一次元的な処理(縦と横の二回)に分ける。
2.移動平均処理で、計算回数を減らす。
コード
.anmとして使用できます。
--[[
blur.anm
ボックスブラーです。
]]
--track0:size,1,1000,100,1
local ffi=require"ffi"
pcall(ffi.cdef,[[
typedef struct Pixel_ {
uint8_t b,g,r,a;
} Pixel;
]])
local work,data,w,h=obj.getpixeldata"work",obj.getpixeldata()
local c=ffi.cast("Pixel*",data)
local r=ffi.cast("Pixel*",work)
local function f(a)
if(a<0)then return 0
elseif(a>255)then return 255
else return math.floor(a)
end
end
local ha=obj.track0--正の整数
local ha2=ha*2
--横方向にぼかしていく
for y=0,h-1 do
local to,ix={0,0,0,0},y*w
for i=0,ha-1 do
to[1]=to[1]+c[ix+i].r
to[2]=to[2]+c[ix+i].g
to[3]=to[3]+c[ix+i].b
to[4]=to[4]+c[ix+i].a
end
for x=0,w-1 do
if(x<w-ha)then
to[1]=to[1]+c[ix+ha].r
to[2]=to[2]+c[ix+ha].g
to[3]=to[3]+c[ix+ha].b
to[4]=to[4]+c[ix+ha].a
end
if(x>=ha)then
to[1]=to[1]-c[ix-ha].r
to[2]=to[2]-c[ix-ha].g
to[3]=to[3]-c[ix-ha].b
to[4]=to[4]-c[ix-ha].a
end
r[ix].r=f(to[1]/ha2)
r[ix].g=f(to[2]/ha2)
r[ix].b=f(to[3]/ha2)
r[ix].a=f(to[4]/ha2)
ix=ix+1
end
end
--縦方向にぼかしていく
local haw=ha*w
for x=0,w-1 do
local to,ix={0,0,0,0},x
for i=0,ha-1 do
to[1]=to[1]+r[ix+i*w].r
to[2]=to[2]+r[ix+i*w].g
to[3]=to[3]+r[ix+i*w].b
to[4]=to[4]+r[ix+i*w].a
end
for y=0,h-1 do
if(y<h-ha)then
to[1]=to[1]+r[ix+haw].r
to[2]=to[2]+r[ix+haw].g
to[3]=to[3]+r[ix+haw].b
to[4]=to[4]+r[ix+haw].a
end
if(y>=ha)then
to[1]=to[1]-r[ix-haw].r
to[2]=to[2]-r[ix-haw].g
to[3]=to[3]-r[ix-haw].b
to[4]=to[4]-r[ix-haw].a
end
c[ix].r=f(to[1]/ha2)
c[ix].g=f(to[2]/ha2)
c[ix].b=f(to[3]/ha2)
c[ix].a=f(to[4]/ha2)
ix=ix+w
end
end
obj.putpixeldata(data)
おわりに
luajitでボックスブラーをやりました。
実際に使用してみると分かりますが、とても重いです。実用性を考慮するならば素直にdllでマルチスレッドとかsimdとかしたほうがいいです。
ところで、gpuで高速化できるとか聞いたのですが、本当なんですかね…?
最近オンボの限界を感じます。