我正在尝试对传入的预览相机帧应用2D傅里叶变换。
所以这是我在每个onSurfaceTextureUpdated
上执行的renderScript代码:
#pragma version(1)
#pragma rs java_package_name(foo.camerarealtimefilters)
rs_allocation inPixels;
int height;
int width;
void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
float3 fourierPixel;
for(int k=0; k<=width; k++){
for(int l=0; l<=height; l++){
float3 pixel = convert_float4(rsGetElementAt_uchar4(inPixels, k, l)).rgb;
float greyOrigPixel = (pixel.r + pixel.g + pixel.b)/3;
float angle = 2 * M_PI * ( ((x * k) / width) + ((y * l) / height) );
fourierPixel.rgb = greyOrigPixel*cos(angle);
};
};
out->xyz = convert_uchar3(fourierPixel);
}
inPixels由此方法设置,
public void setInAllocation(Bitmap bmp) {
inAllocation = Allocation.createFromBitmap(rs, bmp);
fourierScript.set_inPixels(inAllocation);
};
现在我的代码背后的数学?基本上应用欧拉公式,忽略相位项,因为我不能用虚数做多少,只绘制幅度,即真实(余弦)部分。我当然可以看到灰度图像。
以下是我的资源:
1)http://homepages.inf.ed.ac.uk/rbf/HIPR2/fourier.htm “... 在图像处理中,通常只显示傅里叶变换的幅度,因为它包含空间域图像几何结构的大部分信息 ..”
2)http://www.nayuki.io/page/how-to-implement-the-discrete-fourier-transform 我在哪里获得了Euler公式,以及我如何应用它。
我的问题是,当我启动我的应用程序时,它会给我原始图像,无论相机看到什么,仅此而已。它也会在2到3秒后冻结。
我的代码出了什么问题?处理太多了吗?我问的是可能的(我在三星Galaxy S4 Mini上运行)?我只是想在相机框架上应用实时简单的DFT。
答案 0 :(得分:2)
很难说为什么你的图像在没有看到Java代码的情况下不会显示更新。但是,您可以尝试以下几种方法。
如果您可以处理较低的精确度,请使用float
代替double
,因为这样可以提高效果
如果您可以处理较低的精确度,请使用#pragma rs_fp_relaxed
来帮助提高性能
您可以重新构建RS以具有设置功能,该功能应在首次运行之前调用。用它来设置宽度/高度并预先计算FFT方程的固定部分
看起来像这样:
rs_allocation angles;
uint32_t width;
uint32_t height;
uint32_t total;
void setupPreCalc(uint32_t w, uint32_t h) {
uint32_t x;
uint32_t y;
float curAngle;
width = w;
height = h;
total = w * h;
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
curAngle = 2 * M_PI * (y * width + x);
rsSetElementAt_float(angles, curAngle, x, y);
}
}
}
Allocation
元素以及正在操作的x
和y
坐标: void __attribute__((kernel))doFft(uchar4 out, uint32_t x, uint32_t y)
在每个帧之前,设置类似于您所做的输入分配,然后重新构造循环以使用预先计算的角度部分。
以前,内核循环遍历输入中的所有坐标,计算灰度像素值,通过类似于您找到的等式运行它,然后将其设置为新的像素值,并在完成后保存从循环的最后一次迭代得到的值是输出值。这并不是你想要的。 RS已经在输出 Allocation
中为您提供了一个特定位置,因此您需要对与该特定输出点相关的所有输入点进行求和。
使用预计算Allocation
和内核的新形式,它可能如下所示:
void __attribute__((kernel)) doFft(uchar4 out, uint32_t x, uint32_t y) {
// Loop over all input allocation points
uint32_t inX;
uint32_t inY;
float curAngle;
float4 curPixel;
float4 curSum = 0.0;
for (inX = 0; inX < width; inX++) {
for (inY = 0; inY < height; inY++) {
curPixel = convert_float4(rsGetElementAt_uchar4(inPixels, x, y));
curPixel.rgb = (curPixel.r + curPixel.g + curPixel.b) / 3;
curAngle = rsGetElementAt_float(angles, inX, inY);
curAngle = curAngle * ((x + (y * width)) / total);
curSum += curPixel * cos(curAngle);
}
}
out = convert_uchar4(curSum);
}