Android Renderscript,从位图中删除白色/白色背景

Android Renderscript,从位图中删除白色/白色背景,android,image,image-processing,bitmap,renderscript,Android,Image,Image Processing,Bitmap,Renderscript,我正在开发一个基于图片的应用程序,但由于Renderscript出现问题而被阻止 理论上我的目的很简单,我想从用户加载的图像中删除白色背景,在另一张我设置为背景的图像上显示它们。更具体地说,我想模拟的是在纸画布(也是图片)上打印用户上传的图形的效果,具有逼真的效果 我不能假设用户能够通过alpha通道上传漂亮的PNG,其中一个要求是使用JPG操作 我一直在尝试用RenderScripts解决这个问题,用类似这样的东西将alpha 0设置为R、G和B都等于或大于240的任何值: #pragma v

我正在开发一个基于图片的应用程序,但由于Renderscript出现问题而被阻止

理论上我的目的很简单,我想从用户加载的图像中删除白色背景,在另一张我设置为背景的图像上显示它们。更具体地说,我想模拟的是在纸画布(也是图片)上打印用户上传的图形的效果,具有逼真的效果

我不能假设用户能够通过alpha通道上传漂亮的PNG,其中一个要求是使用JPG操作

我一直在尝试用RenderScripts解决这个问题,用类似这样的东西将alpha 0设置为R、G和B都等于或大于240的任何值:

#pragma version(1)
#pragma rs java_package_name(mypackagename)
rs_allocation gIn;
rs_allocation gOut;
rs_script gScript;

const static float th = 239.f/256.f;


void root(const uchar4 v_in, uchar4 v_out, const void* usrData, uint32_t x,uint32_t y){
float4 f4 = rsUnpackColor8888(*v_in);


if(f4.r > th  && f4.g > th && f4.b > th)
{
    f4.a = 0;
}


   *v_out =  rsPackColorTo8888(f4);

}

void filter() {
    rsForEach(gScript, gIn, gOut);
}
但结果并不令人满意,主要有两个原因:

  • 如果照片的背景上没有白色渐变,脚本会产生难看的噪音效果
  • 阴影靠近边缘的图像会在靠近边缘处获得噪波效果
我知道从alpha 0传递到alpha 1太极端了,我尝试了不同的解决方案,当R、G、B分量的和减少时,线性增加alpha,但我周围仍然有噪声像素和块

使用纯白色或常规背景(例如谷歌主页的快照),它可以完美地工作,但对于照片来说,这是远远不能接受的

我认为,如果我能够处理一行像素或一块像素,而不是单个像素,那么检测平坦背景和避免出现渐变可能会更容易,但我对渲染脚本的了解还不够。

谁能给我指出正确的方向吗

PS


我不能使用PorterDuff和multiply,因为背景和前景有不同的维度,而且我需要能够在应用效果后在背景画布上拖动上传的图像。如果我将图像与背景区域相乘,移动结果图像将导致背景部分也随之移动。

如果我没有弄错,您需要根据相邻像素的线条/块确定当前像素是否可以是白色背景

你可以试试这个用法。例如,要处理原始代码中的一行,请执行以下操作:

#pragma version(1)
#pragma rs java_package_name(mypackagename)
rs_allocation gIn;
rs_allocation gOut;
rs_script gScript;

const static float th = 239.f/256.f;

void root(const uchar4 v_in, uchar4 v_out, const void* usrData, uint32_t x,uint32_t y){
    float4 f4 = rsUnpackColor8888(*v_in);
    uint32_t width = rsAllocationGetDimX(gIn);
    // E.g: Processing a line from x to x+5.
    bool isBackground = true;
    for (uint32_t i=0; i<=5 && x+i<width; i++) {
        uchar4 nPixel_u4 = rsGetElementAt_uchar4(gIn, x+i, y);
        float4 nPixel_f4 = rsUnpackColor8888(nPixel_u4);

        if(nPixel_f4.r <= th  || nPixel_f4.g <= th || nPixel_f4.b <= th) {
            isBackground = false;
            break;
        }
    }
    if (isBackground) {
        f4.a = 0.0f;
        *v_out =  rsPackColorTo8888(f4);
    }
}

void filter() {
    rsForEach(gScript, gIn, gOut);
}
布拉格语版本(1) #pragma rs java_包名称(mypackagename) 卢比; rs_分配痛风; rs_脚本gScript; 常量静态浮点th=239.f/256.f; 空根(常数uchar4 v_in,常数uchar4 v_out,常数void*usrData,uint32_t x,uint32_t y){ 浮动4 f4=RS8888(*v_英寸); uint32_t宽度=RSAllocatingETDIMX(gIn); //例如:处理从x到x+5的一行。 bool isBackground=true;
对于(Unt32),i=0;谢谢苗,它看起来很有前途。我正在尝试,我接受你的答案。我已经暂时赞成了:)你也可以考虑通过可调用(即Fiter())来调用它,而使用反射的java前缀()。您还可以将函数更改为按值传递,因为您根本不使用指针和/或usrData。