简体   繁体   English

如何制作位图的透明背景?

[英]How can I make transparent background of a Bitmap?

I am working on a module in which I have to make background of bitmap image transparent. 我正在开发一个模块,其中必须使位图图像的背景透明。 Actually, I am making an app like "Stick it" through which we can make sticker out of any image. 实际上,我正在制作一个像“ Stick it”这样的应用程序,通过它我们可以在任何图像上制作贴纸。 I don't know from where to begin. 我不知道从哪里开始。 Can someone give me a link or a hint for it? 有人可以给我链接或提示吗?

Original Image- 原始图片- 在此处输入图片说明

After making background transparent- 使背景透明后

在此处输入图片说明

This is what I want. 这就是我要的。

I can only provide some hints on how to approach your problem. 我只能提供一些有关如何解决您的问题的提示。 You need to do a Image Segmenation . 您需要执行图像分割 This can be achived via the k-means algotithm or similar clustering algorithms. 这可以通过k均值算法或类似的聚类算法来实现。 See this for algorithms on image segmantation via clustering and this for a Java Code example. 对通过聚类图像segmantation算法 对于一个Java代码示例。 The computation of the clustering can be very time consumeing on a mobile device. 聚类的计算在移动设备上可能非常耗时。 Once you have the clustering you can use this approach to distinguish between the background and the foreground. 一旦有了群集,就可以使用这种方法来区分背景和前景。 In general all you picture should have a bachground color which differs strongly from the foreground otherwise it is not possible for the clustering to distunguish between them. 通常,所有图片应具有与前景强烈不同的背景色,否则,群集之间就不会混淆。 It can also happen that a pixel inside of you foreground is assigned to the cluster of the background beacuase it has a similar color like your background. 也有可能发生,因为您的前景内部的像素与背景具有相似的颜色,因此将其分配给背景的群集。 To prevent this from happening you could use this approach or a region grwoth algorithm . 为了防止这种情况的发生,您可以使用这种方法区域增长算法 Afterward you can let you user select the clusters via touch and remove them. 之后,您可以让用户通过触摸选择集群并将其删除。 I also had the same problems with my Android App. 我的Android应用程序也有同样的问题。 This will give you a good start and once you have implemented the custering you just need to tewak the k parameter of the clustering to get good results. 这将为您提供一个良好的开始,并且一旦实施了诱捕程序,您需要调整聚类的k参数即可获得良好的结果。

Seems like a daunting task. 似乎是一项艰巨的任务。 If you are talking about image processing if I may understand then you can try https://developers.google.com/appengine/docs/java/images/ Also if you want to mask the entire background ( I have not tried Stick it) the application needs to understand the background image map. 如果您说的是我可能理解的图像处理,那么可以尝试https://developers.google.com/appengine/docs/java/images/另外,如果您想遮盖整个背景(我还没有尝试过粘贴)应用程序需要了解背景图像图。 Please provide some examples so that I can come up with more definitive answers 请提供一些示例,以便我得出更明确的答案

if you are working in Android you might need a Buffer to get the pixels from the image - it's a intBuffer and it reduces the memory usage enormously... to get data from and stor data into the Buffer you have three methods (you can skip that part if you don't have 'large' images): 如果您在Android上工作,则可能需要一个Buffer来从图像中获取像素-这是一个intBuffer,它极大地减少了内存使用...要从Buffer中获取数据或将数据存储到Buffer中,您可以使用以下三种方法(您可以跳过如果您没有“大”图像,则该部分):

private IntBuffer buffer;
public void copyImageIntoBuffer(File imgSource) {
    final Bitmap temp = BitmapFactory.decodeFile(imgSource
            .getAbsolutePath());
    buffer.rewind();
    temp.copyPixelsToBuffer(buffer);
}

protected void copyBufferIntoImage(File tempFile) throws IOException {
    buffer.rewind();
    Bitmap temp = Bitmap.createBitmap(imgWidth, imgHeight,
            Config.ARGB_8888);
    temp.copyPixelsFromBuffer(buffer);

    FileOutputStream out = new FileOutputStream(tempFile);
    temp.compress(Bitmap.CompressFormat.JPEG, 90, out);
    out.flush();
    out.close();
}

public void mapBuffer(final File tempFile, long size) throws IOException {

    RandomAccessFile aFile = new RandomAccessFile(tempFile, "rw");
    aFile.setLength(4 * size); // 4 byte pro int
    FileChannel fc = aFile.getChannel();
    buffer = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size())
            .asIntBuffer();

}

now you can use the Buffer to get the pixels and modify them as desired... (i've copyied a code snipped that used a Progress bar on my UI and therefore needed a Handler/ProgressBar... when i did this i was working on bigger images and implemented a imageFilter (Gauss-Filter,Grey-Filter, etc.... just delete what is not needed) 现在您可以使用Buffer来获取像素并根据需要对其进行修改...(我已经复制了一段代码,该代码使用了UI上的进度条,因此需要Handler / ProgressBar ...当我这样做时,处理更大的图像并实现了imageFilter(高斯滤镜,灰色滤镜等...只需删除不需要的内容)

public void run(final ProgressBar bar, IntBuffer buffer, Handler mHandler, int imgWidth, int imgHeight, int transparentColor ) {
     for (int dy = 0; dy < imgHeight; dy ++){

        final int progress = (dy*100)/imgHeight;

        for (int dx = 0; dx < imgWidth; dx ++ ){

            int px = buffer.get();
            //int a = (0xFF000000 & px);
            //int r = (0x00FF0000 & px) >> 16;
            //int g = (0x0000FF00 & px) >> 8;
            //int b = (0x000000FF & px);

            //this makes the color transparent
            if (px == transparentColor) {
                px = px | 0xFF000000;
            }


            //r = mid << 16;
            //g = mid << 8;
            //b = mid;
            //int col = a | r | g | b;

            int pos = buffer.position();
            buffer.put(pos-1, px);
        }

        // Update the progress bar
        mHandler.post(new Runnable() {                      
            public void run() {
                bar.setProgress(progress);                          
            }
        });

    }
}

if you really have small images, you can get the pixels directly during onCreate() or even better create a Buffer (maybe a HashMap or a List) before you start the Activity... 如果您确实有小图像,则可以在onCreate()期间直接获取像素,甚至更好地在开始Activity之前创建一个Buffer(可能是HashMap或List)。

One possibility would be to utilize the floodfill operation in the openCV library. 一种可能性是利用openCV库中的Floodfill操作。 There are lots of examples and tutorials on how to do similar stuff to what you want and OpenCV has been ported to Android. 关于如何做与您想要的东西类似的事情,有很多示例和教程,并且OpenCV已移植到Android。 The relevant terms to Google are of course "openCV" and "floodfill". Google的相关术语当然是“ openCV”和“ floodfill”。

For this kind of task(and app) you'll have to use openGL. 对于此类任务(和应用程序),您必须使用openGL。 Usually when working on openGL you based your fragment shader on modules you build in Matlab. 通常,在使用openGL时,您的片段着色器基于在Matlab中构建的模块。 Once you have the fragment shader it's quite easy to apply it on image. 一旦有了片段着色器,就可以很容易地将其应用于图像。 check this guide how to do it. 检查指南的操作方法。

Here's a link to remove background from image in MatLab 这是在MatLab中从图像中删除背景链接

I'm not fully familiar with matlab and if it can generate GLSL code by itself(the fragment shader). 我对matlab以及它是否可以自己生成GLSL代码(片段着色器)并不完全熟悉。 But even if it doesn't - you might want to learn GLSL yourself because frankly - you are trying to build a graphics app and Android SDK is somehow short when using it for images manipulation, and most important is that without a strong hardware-acceleration engine behind it - I cannot see it works smooth enough. 但是,即使不是这样-坦率地说,您可能想自己学习GLSL-您正在尝试构建图形应用,而使用Android SDK进行图像处理时,它在某种程度上还是很短的,最重要的是,没有强大的硬件加速它背后的引擎-我看不到它工作得足够流畅。

Once you'll have the figure image - you can apply it on transparent background easily like this: 获得图形图像后,您可以轻松地将其应用于透明背景,如下所示:

Canvas canvas = new Canvas(canvasBitmap);
canvas.drawColor(Color.TRANSPARENT);   
BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(R.drawable.loading);    
Bitmap yourBitmap = bd.getBitmap();    
Paint paint = new Paint();    
canvas.drawBitmap(yourBitmap, 0, 0, paint);
Bitmap newBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(),image.getConfig());
Canvas canvas = new Canvas(newBitmap);
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(image, 0, 0, null);

OR See this 看到这个

hope this wll helps you 希望这会帮助你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM