我正在编写一个片段着色器,以便将9张图像放在一起。
我之前从未使用过GLSL,但它似乎是适合这项工作的工具,因为OpenCL在iOS上不可用,并且CPU上的中位数效率低下。 这是我到目前为止所做的:
uniform sampler2D frames[9];
uniform vec2 wh;
void main(void)
{
vec4 sortedFrameValues[9];
float sortedGrayScaleValues[9];
for (int i = 0; i < 9; i++)
{
sortedFrameValues[i] = texture2D(frames[i], -gl_FragCoord.xy / wh);
sortedGrayScaleValues[i] = dot(sortedFrameValues[i].xyz, vec3(0.299, 0.587, 0.114));
}
// TODO: Sort sortedGrayScaleValues
float gray = sortedGrayScaleValues[4];
gl_FragColor = vec4(gray, gray, gray, 0);
}
答案 0 :(得分:3)
有点晚了,但我发现的最快方式是插入排序。降低着色器的复杂性和分歧是关键。对于小数字,Bitonic和bubble也很好用。一旦你起步大约100,切换到合并排序。
由于你知道要排序的事物的数量(9),你最好的选择是排序网络。您可以使用this handy tool生成它...
There are 27 comparators in this network,
grouped into 11 parallel operations.
[[0,1],[2,3],[4,5],[7,8]]
[[0,2],[1,3],[6,8]]
[[1,2],[6,7],[5,8]]
[[4,7],[3,8]]
[[4,6],[5,7]]
[[5,6],[2,7]]
[[0,5],[1,6],[3,7]]
[[0,4],[1,5],[3,6]]
[[1,4],[2,5]]
[[2,4],[3,5]]
[[3,4]]
使用它的一种方便方法是声明一个比较和交换宏......
#define CMP(a, b) ...
#define SWAP(a, b) ...
#define CSWAP(a, b) if (CMP(a, b)) {SWAP(a, b);}
CSWAP(0, 1); CSWAP(2, 3); ...
结合这两种方法,一个快速排序小块数据的排序网络,如果你有很多块,则合并排序效果非常好,如Fast Sorting for Exact OIT of Complex Scenes中所述(免责声明:我是作者)。
展开循环(基本上创建排序网络)可能特别有益,允许在寄存器中进行排序。动态索引的数组放在本地内存中,速度很慢。要强制编译器不要这样做,您可以手动声明vec4 array0, array1 ...
。宏可以连接这里有用的文本#define CMP(a, b) (array##a < array##b)
。一个相当丑陋但又快速的例子是here。
答案 1 :(得分:1)
好吧,我最终实现了冒泡排序并使用中间值。
这就是我的解决方案:
uniform sampler2D frames[9];
uniform vec2 wh;
vec4 frameValues[9];
float arr[9];
void bubbleSort()
{
bool swapped = true;
int j = 0;
float tmp;
for (int c = 0; c < 3; c--)
{
if (!swapped)
break;
swapped = false;
j++;
for (int i = 0; i < 3; i++)
{
if (i >= 3 - j)
break;
if (arr[i] > arr[i + 1])
{
tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
swapped = true;
}
}
}
}
void main(void)
{
for (int i = 0; i < 9; i++)
{
frameValues[i] = texture2D(frames[i], -gl_FragCoord.xy / wh);
arr[i] = dot(frameValues[i].xyz, vec3(0.299, 0.587, 0.114));
}
bubbleSort();
float gray = arr[4];
gl_FragColor =vec4(gray, gray, gray, 0);
}
答案 2 :(得分:0)
这只是一个正常的排序问题,不是吗?我知道找到中位数的最快方法是Median of Medians方法。
在将值排序之前,不要将您的值放入“已排序”数组中可能更有意义。
您不需要将sortedFrameValues
变量作为数组,至少在此处使用它时 - 您再也不会使用任何存储的值。您只需将其作为单个变量。
答案 3 :(得分:0)
您可以在iOS应用中使用OpenGL ES来查找您选择的源像素邻域半径中的中值像素值;它看起来像这样:
kernel vec4 medianUnsharpKernel(sampler u) {
vec4 pixel = unpremultiply(sample(u, samplerCoord(u)));
vec2 xy = destCoord();
int radius = 3;
int bounds = (radius - 1) / 2;
vec4 sum = vec4(0.0);
for (int i = (0 - bounds); i <= bounds; i++)
{
for (int j = (0 - bounds); j <= bounds; j++ )
{
sum += unpremultiply(sample(u, samplerTransform(u, vec2(xy + vec2(i, j)))));
}
}
vec4 mean = vec4(sum / vec4(pow(float(radius), 2.0)));
float mean_avg = float(mean);
float comp_avg = 0.0;
vec4 comp = vec4(0.0);
vec4 median = mean;
for (int i = (0 - bounds); i <= bounds; i++)
{
for (int j = (0 - bounds); j <= bounds; j++ )
{
comp = unpremultiply(sample(u, samplerTransform(u, vec2(xy + vec2(i, j)))));
comp_avg = float(comp);
median = (comp_avg < mean_avg) ? max(median, comp) : median;
}
}
return premultiply(vec4(vec3(abs(pixel.rgb - median.rgb)), 1.0));
}
远没那么复杂,不需要分类。它只涉及两个步骤: 1.计算3x3邻域中源像素周围的像素值的平均值; 2.找到同一邻域中小于均值的所有像素的最大像素值。 3. [可选]从源像素值中减去中值像素值以进行边缘检测。
如果您使用中值进行边缘检测,有几种方法可以修改上述代码以获得更好的结果,即混合中值滤波和截断媒体滤波(替代品和更好的&#39) ;模式&#39;过滤)。如果您有兴趣,请询问。