图像上的原子移动平均线
Atomic moving average on image
我正在尝试计算图像上的原子移动平均值,但是平均值是错误的,当我多次使用相同的数据运行它时,平均值每次都不同。 我有一个 RGBA8 纹理,但我将其绑定为 R32UI,因为我需要原子操作和纹理过滤。
我为平均制作了一个测试应用程序,因为实际应用程序非常复杂。在测试应用程序中,我在单个纹素上的片段着色器中进行平均,因此我有一个 1x1 RGBA8 纹理,绑定为 R32UI。我正在渲染一个大小为 500x500 的四边形,每个片段着色器调用都会在纹素中的平均值中添加一个蓝色或红色值,具体取决于片段坐标。
片段着色器:
#version 450 core
layout (binding = 0, r32ui) volatile uniform uimage2D img;
layout (location = 0) uniform int width;
vec4 convRGBA8ToVec4( uint val)
{
return vec4(float((val & 0x000000FF)), float((val & 0x0000FF00) >> 8U),
float((val & 0x00FF0000) >> 16U), float((val & 0xFF000000) >> 24U));
}
uint convVec4ToRGBA8( vec4 val)
{
return (uint(val.w) & 0x000000FF) << 24U | (uint(val.z) & 0x000000FF) << 16U |
(uint(val.y) & 0x000000FF) << 8U | (uint(val.x) & 0x000000FF);
}
void imageAtomicRGBA8Avg(layout (r32ui) volatile uimage2D imgUI, ivec2 coords , vec4 val)
{
val.rgb *= 255.0f;
uint newVal = convVec4ToRGBA8(val);
uint prevStoredVal = 0;
uint curStoredVal;
// Loop as long as destination value gets changed by other threads
while((curStoredVal = imageAtomicCompSwap(imgUI, coords, prevStoredVal, newVal))
!= prevStoredVal)
{
prevStoredVal = curStoredVal;
vec4 unpacked = convRGBA8ToVec4(curStoredVal);
vec3 x = unpacked.xyz;
float n = unpacked.w;
vec4 curValF = vec4(vec3(((n * x) + val.xyz) / n), n + 1);
newVal = convVec4ToRGBA8(curValF);
}
}
void main()
{
int idx = int(gl_FragCoord.y * width) + int(gl_FragCoord.x);
if(idx % 2 == 0)
{
// Add red
imageAtomicRGBA8Avg(img, ivec2(0, 0), vec4(1.0f, 0.0f, 0.0f, 1.0f));
}
else
{
// Add blue
imageAtomicRGBA8Avg(img, ivec2(0, 0), vec4(0.0f, 0.0f, 1.0f, 1.0f));
}
}
平均颜色介于红色和蓝色之间,有时甚至是纯红色或蓝色。我想知道为什么会发生这种情况,我在一篇论文中找到了平均函数,所以它实际上应该工作。
这是初始化代码:
glCreateTextures(GL_TEXTURE_2D, 1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
glBindTextureUnit(0, texture);
glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
和渲染代码:
glUseProgram(atomic_avg_prog);
glUniform1i(0, window_width);
glDrawArrays(GL_TRIANGLES, 0, 6);
glUseProgram(read_prog);
glDrawArrays(GL_TRIANGLES, 0, 6);
读取程序只是在四边形上绘制纹素
我通过将convRGBA8ToVec4
和convVec4ToRGBA8
替换为packUnorm4x8
和unpackUnorm4x8
解决了这个问题,这要归功于这篇文章:https://rauwendaal.net/2013/02/07/glslrunningaverage/
该解决方案不允许平均超过 255 个值,因为计数器仅以 8 位存储在 alpha 中,但就我而言,这就足够了
void imageAtomicAvgRGBA8(layout (r32ui) volatile uimage2D imgUI, ivec2 coords , vec4 val)
{
uint newVal = packUnorm4x8(vec4(val.xyz, 1.0f / 255.0f));
uint prevStoredVal = 0;
uint curStoredVal;
// Loop as long as destination value gets changed by other threads
while((curStoredVal = imageAtomicCompSwap(imgUI, coords, prevStoredVal, newVal))
!= prevStoredVal)
{
prevStoredVal = curStoredVal;
vec4 unpacked = unpackUnorm4x8(curStoredVal);
vec3 x = unpacked.xyz;
float n = unpacked.w * 255.0f;
x = (x * n + val.xyz) / (n + 1);
newVal = packUnorm4x8(vec4(x, (n + 1) / 255.0f));
}
}
相关文章:
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 将对象移动到std::shared_ptr
- 何时在引用或唯一指针上使用移动语义
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- OpenCV EqualizeHist()从彩色图像创建黑白图像
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 如何从具有移动语义的类对象中生成共享指针
- 如何将图像数据从搜索窗口中移动到本地存储器OpenCL
- 如何在移动滑块时串联加载和显示多个图像?
- 图像上的原子移动平均线
- 如何使用SFML鼠标移动分别移动多个图像
- OpenCV:相对于参考图像移动/对齐面图像(图像配准)
- SDL2:如何沿正方形路径移动图像
- 将我的阵列移动到 Mat 并使用打开的 CV 显示图像
- 如何在 SDL C++中将图像移动到点
- 基于图像的计数算法,用于对移动输送机上的物体进行计数
- 在OpenCV中移动图像内容
- opencvc++在阈值图像中查找移动
- 使用OpenCV工具从连续的图像差异中检测国际象棋的移动
- 移除移动物体,从多个图像中获取背景模型