Project1
标题: Bitmap模糊绘制blur_blt [打印本页]
作者: guoxiaomi 时间: 2022-3-12 20:27
标题: Bitmap模糊绘制blur_blt
本帖最后由 guoxiaomi 于 2022-3-13 00:23 编辑
不知道有没有人写过?相当于把一张bitmap,模糊的绘制到目标bitmap上,虽然用了高斯分布的公式,但不是高斯模糊,只是糊了点
下图是sigma=2.0时的模糊,也可以下载范例尝试:
20220312-blur.zip
(201.29 KB, 下载次数: 24)
,按左右键调整模糊程度,确认键退出
class Bitmap
def blur_blt(src_bitmap, sigma = 1.0)
blt(0, 0, src_bitmap, src_bitmap.rect)
return if sigma < 0.01
d = 4
sum = 0.0
for dx in -d..d
for dy in -d..d
sum += Math.exp(-0.5 * (dx * dx + dy * dy) / (sigma * sigma))
end
end
for dx in -d..d
for dy in -d..d
alpha = Math.exp(-0.5 * (dx * dx + dy * dy) / (sigma * sigma)) * 255.0 / sum
next if alpha < 1
blt(dx, dy, src_bitmap, src_bitmap.rect, alpha)
end
end
end
end
class Bitmap
def blur_blt(src_bitmap, sigma = 1.0)
blt(0, 0, src_bitmap, src_bitmap.rect)
return if sigma < 0.01
d = 4
sum = 0.0
for dx in -d..d
for dy in -d..d
sum += Math.exp(-0.5 * (dx * dx + dy * dy) / (sigma * sigma))
end
end
for dx in -d..d
for dy in -d..d
alpha = Math.exp(-0.5 * (dx * dx + dy * dy) / (sigma * sigma)) * 255.0 / sum
next if alpha < 1
blt(dx, dy, src_bitmap, src_bitmap.rect, alpha)
end
end
end
end
下面是测试代码:
b = RPG::Cache.battleback("001-grassland01")
s = Sprite.new
s.bitmap = b.clone
hint = Sprite.new
hint.y = 440
hint.bitmap = Bitmap.new(640, 32)
refresh = Proc.new { |sigma|
s.bitmap.clear
s.bitmap.blur_blt(b, sigma)
hint.bitmap.clear
hint.bitmap.draw_text(0, 0, 640, 32, "sigma = %.2f" % sigma, 1)
}
sigma = 1.0
refresh.call(sigma)
loop do
Graphics.update
Input.update
exit if Input.trigger?(Input::C)
if Input.press?(Input::RIGHT)
sigma += 0.05
refresh.call(sigma)
elsif Input.press?(Input::LEFT) && sigma > 0
sigma -= 0.05
refresh.call(sigma)
end
end
b = RPG::Cache.battleback("001-grassland01")
s = Sprite.new
s.bitmap = b.clone
hint = Sprite.new
hint.y = 440
hint.bitmap = Bitmap.new(640, 32)
refresh = Proc.new { |sigma|
s.bitmap.clear
s.bitmap.blur_blt(b, sigma)
hint.bitmap.clear
hint.bitmap.draw_text(0, 0, 640, 32, "sigma = %.2f" % sigma, 1)
}
sigma = 1.0
refresh.call(sigma)
loop do
Graphics.update
Input.update
exit if Input.trigger?(Input::C)
if Input.press?(Input::RIGHT)
sigma += 0.05
refresh.call(sigma)
elsif Input.press?(Input::LEFT) && sigma > 0
sigma -= 0.05
refresh.call(sigma)
end
end
作者: RPGzh500223 时间: 2022-3-12 23:25
我打开是 No such file to load -- main.rb……
以前好奇高斯模糊,见过类似的计算公式来计算kernel,但我基本没看懂……
效果和效率都不错,就是和PS的高斯模糊看起来有点不一样……
作者: guoxiaomi 时间: 2022-3-13 00:20
本帖最后由 guoxiaomi 于 2022-3-13 01:48 编辑
模糊就是将一个点像素变为某个分布。比如说,把这个点的颜色分配到周围几个点上,本来位置占0.5,上下左右各0.125,只要加起来是1就行。符合高斯分布的分配方式就是高斯模糊。操作起来就更简单了,直接将图片平移,然后按照分配比例计算透明度,叠加起来即可。我这段代码就是x: -4~4, y: -4~4总共81张图叠出来的。
我一开始按照高斯分布的公式写的,叠起来却非常的暗,所以我在叠之前先把原图绘制了一遍。可能RMXP的Bitmap叠加不是直接用的加法,或者有数值精度的问题,得再研究研究。
===
我怀疑我的权重算错了,真实权重应该是下面这个(论坛发不了公式):
计算结果
作者: fux2 时间: 2022-3-13 09:11
遇事不决抄MV……
作者: RPGzh500223 时间: 2022-3-13 11:08
本帖最后由 RPGzh500223 于 2022-3-13 11:32 编辑
- class Bitmap
- def blur_blt2(src_bitmap, sigma = 1.0)
- self.blt(0, 0, src_bitmap, src_bitmap.rect)
- return if sigma < 0.01
- d, sum, sigma_ratio = 4, 0.0, -0.5 / (sigma * sigma)
-
- 1.upto(d) do |dx|
- mul = dx * dx
- sum += Math.exp(mul * sigma_ratio) * 4
- 1.upto(d) do |dy|
- sum += Math.exp((mul + dy * dy) * sigma_ratio) * 4
- end
- end
- sum += 1
-
- var = 255.0 / sum
- d_max = (Math.log(1 / var) / sigma_ratio).ceil
-
- 1.upto(d) do |dx|
- 1.upto(d) do |dy|
- distance = dx * dx + dy * dy
- next if distance > d_max
- alpha = Math.exp(distance * sigma_ratio) * var
- self.blt( dx, dy, src_bitmap, src_bitmap.rect, alpha)
- self.blt( dx, -dy, src_bitmap, src_bitmap.rect, alpha)
- self.blt(-dx, dy, src_bitmap, src_bitmap.rect, alpha)
- self.blt(-dx, -dy, src_bitmap, src_bitmap.rect, alpha)
- end
- end
- end
- end
复制代码
分享的关于写脚本的小心得(无关于如何计算,其实如何算才是核心……)
for...in...在ruby里好像是效率最低的循环
多重赋值比多次赋值快
能合并的计算常量就先合并
尽可能减少循环次数,例如对称一次就基本少一半循环
其实Math里不少计算是很费效率的,尽可能避免
------------------------------------------------------------------------------------------
模糊效果,我一般就用SSE的pavgb写的均值模糊,高斯模糊的话就调GDI+实现
作者: soulsaga 时间: 2022-3-13 11:50
想问下精灵缩放可以二次立方缩放吗?
作者: 灯笼菜刀王 时间: 2022-3-13 16:23
R叔移植的半生烛光DLL就有模糊计算, 不过,不拆DLL看不到怎么写的
话说, 扭曲应该也可以这样做吧? 把扩散的计算换成正弦曲线重叠?
作者: guoxiaomi 时间: 2022-3-13 18:20
本帖最后由 guoxiaomi 于 2022-3-14 00:26 编辑
我觉得扭曲可能只能一行行的处理了,但是也许有算法只需要处理一个周期,因为每隔固定的周期,画面平移的模式就相同了。
===
想了下,可以把原来的图片拆成N份,每份做不同的平移,这样就能做出动态的扭曲效果了,这样也只需要一次逐行复制,并且在播放动画的时候是没有绘制的,纯粹操作sprite
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |