【问题标题】:Android: dynamically create a maskAndroid:动态创建掩码
【发布时间】:2017-11-27 00:01:21
【问题描述】:

在我的 android 应用程序中,我有一辆汽车,用户可以从中单击并选择不同的面板。图像相对复杂(与此处粘贴的图像相反),因此很难将按钮覆盖在正确的位置。此外还有很多不同的图像。 我想尝试的解决方案:

(第一个图像代表用于确定单击哪个面板的颜色,第二个图像代表生成的蒙版,最后一个图像代表“结果”)。

我遇到的唯一问题是:我如何动态创建面具?我想过使用一种填充类型的方法来创建一个带有所选面板的“蒙版”的新画布​​。但是,我担心它可能计算量太大。有更简单的建议吗? [

更新:好的,所以我已经走了很远。正如预期的那样,蒙版的创建时间太长(小图像需要 2-4 秒)。但是,后来我发现了 RenderScripts!!我想我仍然可以让它工作。我现在唯一遇到的小问题是:如何传递已按下的颜色?

我当前的代码如下所示:

// create a bitmap for the mask.
ImageView img = (ImageView) findViewById (mask);
img.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(img.getDrawingCache());

// Create a tiny bitmap to store the colours of the panels that are 
//'selected'
Bitmap.Config conf = Bitmap.Config.ARGB_8888; // see other conf types
Bitmap myBitmap = Bitmap.createBitmap(pickedPanels.size(), 1, conf);
int [] myInts = new int[pickedPanels.size()];
for (int i = 0; i<pickedPanels.size(); i++){
    myInts[i] = pickedPanels.get(i).intValue();
}
myBitmap.setPixels(myInts, 0, myBitmap.getWidth(), 0, 0, 
myBitmap.getWidth(),0);

//Run thescript and set the output
final RenderScript rs = RenderScript.create(this);
final Allocation input = Allocation.createFromBitmap(rs, bitmap, 
Allocation.MipmapControl.MIPMAP_NONE,Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
        final ScriptC_singlesource script = new 
ScriptC_singlesource(rs);
script.set_image(Allocation.createFromBitmap(rs, myBitmap, 
Allocation.MipmapControl.MIPMAP_NONE,Allocation.USAGE_SCRIPT));
script.set_imgWidth(pickedPanels.size());
script.forEach_root(input, output);
output.copyTo(bitmap);
img.setImageBitmap(bitmap);

ImageView destim = (ImageView) findViewById (dest);
destim.setDrawingCacheEnabled(true);
destim.setImageBitmap(bitmap);

这是脚本:

#pragma version(1)
#pragma rs java_package_name(za.co.overtake)

rs_allocation image;
int imgWidth;

uchar4 RS_KERNEL root(uchar4 in, uint32_t x, uint32_t y) {

for(int col = 0; col < imgWidth; col++){
    const uchar4 colour = *(const uchar4*)rsGetElementAt(image, col,0);
     if (in.r == colour.r && in.g == colour.g && in.b == colour.b){
        in.r = 255;
        in.g = 0;
        in.b = 0;
        break;
    } else {
       in.r = 0;
       in.g = 255;
       in.b = 0;
       rsDebug("HELLLLLP>>", colour);
    }

}
return in;
}

但是,当我尝试从 myBitmap(或脚本中的图像)读取像素值时,RGB 始终为 0。

(抱歉命名不当等。我一直在疯狂地试图弄清楚这一点)

【问题讨论】:

    标签: java android image-processing renderscript android-renderscript


    【解决方案1】:

    好的,终于弄明白了。 在我的渲染脚本代码中,我有:

    #pragma version(1)
    #pragma rs java_package_name(za.co.overtake)
    
    int*reds;
    int*greens;    
    int*blues;
    int imgWidth;
    
    uchar4 RS_KERNEL root(uchar4 in, uint32_t x, uint32_t y) {
       bool colourme = false;
       for(int col = 0; col < imgWidth; col++){
    
            const int red = reds[col];
            const int green = greens[col];
            const int blue = blues[col];
    
             if (in.r == red && in.g == green && in.b == blue){
                colourme = true;
            } 
        }
         if (colourme) {
            in.r = 255;
            in.g = 0;
            in.b = 0;
            in.a = 50;
         } else {
             in.r = 0;
             in.g = 0;
             in.b = 0;
             in.a = 0;
         }
        return in;
    }
    

    然后在 Java 中

    public void showDamagedPanels(int dest, int mask) {
    
        int noOfColours = pickedPanels.size();
        if (noOfColours > 0) {
            ImageView img = (ImageView) findViewById (mask);
            img.setDrawingCacheEnabled(true);
            Bitmap bitmap = Bitmap.createBitmap(img.getDrawingCache());
            img.setDrawingCacheEnabled(false);
    
            int [] reds = new int[noOfColours];
            int [] greens = new int[noOfColours];
            int [] blues = new int[noOfColours];
    
            for (int i = 0; i< noOfColours; i++){
                int colour = pickedPanels.get(i);
                reds[i] = (colour >> 16) & 0xFF;
                greens[i] = (colour >> 8) & 0xFF;
                blues[i] = (colour >> 0) & 0xFF;
            }
    
            final RenderScript rs = RenderScript.create(this);
            final Allocation input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE,
                    Allocation.USAGE_SCRIPT);
            final Allocation output = Allocation.createTyped(rs, input.getType());
            final ScriptC_singlesource script = new ScriptC_singlesource(rs);
    
            Allocation red = Allocation.createSized(rs, Element.I32(rs), reds.length);
            red.copyFrom(reds);
            script.bind_reds(red);
    
            Allocation green = Allocation.createSized(rs, Element.I32(rs), greens.length);
            green.copyFrom(greens);
            script.bind_greens(green);
    
            Allocation blue = Allocation.createSized(rs, Element.I32(rs), blues.length);
            blue.copyFrom(blues);
            script.bind_blues(blue);
    
            script.set_imgWidth(pickedPanels.size());
            script.forEach_root(input, output);
            output.copyTo(bitmap);
    
            ImageView destim = (ImageView) findViewById (dest);
            destim.setDrawingCacheEnabled(true);
            destim.setImageBitmap(bitmap);
        } else {
            ImageView destim = (ImageView) findViewById (dest);
            destim.setImageBitmap(null);
        }
    
    
    }
    

    其中 dest 是叠加图像,图像中的掩码充当掩码。所以基本上,当一个面板被点击时 - 将它的颜色放在pickedPanels中。然后调用调用脚本的 showPanels 方法。该脚本检查颜色并将生成的图像设置为红色或透明。

    更新:对于任何尝试使用它但遇到一些问题的人:可以在没有渲染脚本代码的情况下执行此操作,但它运行速度确实有点慢 - 尽管在我的情况下对于小图像来说还可以。

    private Bitmap changeColor(Bitmap src, Set<Integer> pickedPanelsList) {
            int fine = getResources().getColor(R.color.colorAccent);
    
            int width = src.getWidth();
            int height = src.getHeight();
            int[] pixels = new int[width * height];
            // get pixel array from source
            src.getPixels(pixels, 0, width, 0, 0, width, height);
    
            Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
    
            int AGood = 100, RGood = Color.red(fine), GGood = Color.green(fine), BGood = Color.blue(fine);
            int ABad = 100, RBad = Color.red(Color.RED), GBad = Color.green(Color.RED), BBad = Color.blue(Color.RED);
            int pixel;
    
            // iteration through pixels
            for (int y = 0; y < height; ++y) {
                for (int x = 0; x < width; ++x) {
                    // get current index in 2D-matrix
                    int index = y * width + x;
                    pixel = pixels[index];
                    if(pickedPanelsList.contains(pixel)){
                        pixels[index] = Color.argb(ABad, RBad, GBad, BBad);
                    } else if (Color.alpha(pixel) > 0){
                        pixels[index] = Color.argb(AGood, RGood, GGood, BGood);
                    }
                }
            }
            bmOut.setPixels(pixels, 0, width, 0, 0, width, height);
            return bmOut;
        }
    

    在这里,选择的面板集是所有应该涂成红色(或选择)的颜色,位图是蒙版(如果我没记错的话,我前一阵子做过)。我还发现,对结果进行轻微模糊会使图像看起来更好 - 因为它显然会减少锯齿状。

    【讨论】:

    • 绑定已弃用。使用 rs_allocation 全局和 rsGetElementAt_* 函数。
    猜你喜欢
    • 1970-01-01
    • 2015-09-12
    • 2017-06-24
    • 2021-07-05
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    相关资源
    最近更新 更多