【问题标题】:How to make white part of the image transparent by using Android opencv如何使用Android opencv使图像的白色部分透明
【发布时间】:2016-06-23 12:22:54
【问题描述】:

我不能链接超过 2 个的 url,所以我将我的图片发布到这个博客。 请在这里查看我的问题。 http://blog.naver.com/mail1001/220650041897

我想知道如何使用Android opencv使图像的白色部分,即白纸,透明。

我研究过url(我写在博客上),它使黑色背景透明,我认为“阿尔法通道”与它有关。

我认为它会在我制作 Alpha 通道时起作用,方法是让我想要制作透明黑色的部分和另一部分为白色,并将此 Alpha 通道合并到原始 RGB 通道。

所以我做了两个实验。

1) 我将纸张部分设为黑色,将书写部分设为白色以制作 Alpha 通道。并将其合并到 RGB 通道中。

(请看博客。实验一的alpha通道图片)

我以为字迹应该一样,背景应该是透明的,但是背景只变成了白色,有点透明。

(请看博客。实验一的结果图)

2) 这一次,纸的部分是白色的,书写的部分是黑色的。但这一次只有文字变成了透明。

(请看博客。实验2的alpha通道图片和结果图片)

在第二个实验中,我的意思是让透明变成透明,但在第一个实验中效果不一样。

我做错了哪一部分?有什么概念我理解错了吗?

这是我测试的来源。

Bitmap test(Bitmap image) {
// convert image to matrix
Mat src = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(image, src);

// init new matrices
Mat dst = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);
Mat tmp = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);
Mat alpha = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);

// convert image to grayscale
Imgproc.cvtColor(src, tmp, Imgproc.COLOR_BGR2GRAY);

// threshold the image to create alpha channel with complete transparency in black background region and zero transparency in foreground object region.
Imgproc.threshold(tmp, alpha, 100, 255, Imgproc.THRESH_BINARY_INV);
//Imgproc.threshold(tmp, alpha, 100, 255, Imgproc.THRESH_BINARY);

// split the original image into three single channel.
List<Mat> rgb = new ArrayList<Mat>(3);
Core.split(src, rgb);

// Create the final result by merging three single channel and alpha(BGRA order)
List<Mat> rgba = new ArrayList<Mat>(4);
rgba.add(rgb.get(0));
rgba.add(rgb.get(1));
rgba.add(rgb.get(2));
rgba.add(alpha);
Core.merge(rgba, dst);

// convert matrix to output bitmap
Bitmap output = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dst, output);
//Utils.matToBitmap(alpha, output);
return output;
}

感谢您的好意回答。

我试过了,但它与实验 1 的结果图片相同。 T_T

编辑代码

Bitmap makeBackgroundWhite(Bitmap image) {
    // convert image to matrix
    Mat src = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);
    Utils.bitmapToMat(image, src);

    // init new matrices
    Mat dst = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);
    Mat tmp = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8U);
    Mat alpha = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8U);

    // convert image to grayscale
    Imgproc.cvtColor(src, tmp, Imgproc.COLOR_BGR2GRAY);

    // threshold the image to create alpha channel with complete transparency in black background region and zero transparency in foreground object region.
    Imgproc.threshold(tmp, alpha, 100, 255, Imgproc.THRESH_BINARY_INV);

    // split the original image into three single channel.
    List<Mat> bgra = new ArrayList<Mat>(4);
    Core.split(src, bgra);

    // Create the final result by merging three single channel and alpha(BGRA order)
    bgra.remove(3);
    bgra.add(alpha);
    Core.merge(bgra, dst);

    // convert matrix to output bitmap
    Bitmap output = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(dst, output);

    return output;
}

【问题讨论】:

    标签: android image opencv


    【解决方案1】:

    您的代码中有几个问题。
    我猜这两种情况都出错了,但第二种情况只是幸运地假装成功。
    第二种情况似乎可以正常工作的原因是字体大多是黑色的。
    仔细查看心脏(红色)图像,您会发现第二种情况也失败了。
    (您可能不走运,如果两种情况都失败了,您可能会立即注意到问题:))

    1.您在 CV_8UC4 中使用 tmp(gray) 和 alpha Mat。
    灰色和 alpha 通道每个像素只需要 1 个字节,因此将它们更改为 CV_8U。

    Mat tmp = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8U);
    Mat alpha = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8U);
    


    2.颜色类型混乱
    src Mat 和 tmp Mat 使用 CV_8UC4 初始化,您正在使用转换代码将 src 转换为 tmp:COLOR_BGR2GRAY。
    即使实际颜色类型与转换代码不匹配,OpenCV 也会转换矩阵,因此您必须同步它们才能有意义。

    // suppose you've already changed the type of tmp to CV_8U
    Imgproc.cvtColor(src, tmp, Imgproc.COLOR_BGRA2GRAY);
    


    3.拆分与合并
    您的 src 是 4 通道,您将其拆分为 3。
    我不知道 OpenCV 在这种情况下是如何工作的,但我强烈建议您匹配频道。

    ArrayList<Mat> bgra = new ArrayList<Mat>(4);
    Core.split(src, bgra);
    bgra.remove(3);
    bgra.add(alpha);  // suppose your alpha channel is already CV_8U
    Core.merge(bgra, dst);
    



    添加:C++ 版本源代码
    希望这可以帮助。

    // 1. Loading
    Mat src = imread("yourImagePath/yourOriginalImage.jpg");  // This code will automatically loads image to Mat with 3-channel(BGR) format
    
    // 2. Grayscaling
    Mat gray;
    cvtColor(src, gray, CV_BGR2GRAY);   // This will convert BGR src to GRAY
    
    // 3. Thresholding
    Mat mask;
    threshold(gray, mask, 100, 255, CV_THRES_BINARY); // Or use CV_THRES_BINARY_INV for inverting result
    
    // 4. Splitting & adding Alpha
    vector<Mat> channels;   // C++ version of ArrayList<Mat>
    split(src, channels);   // Automatically splits channels and adds them to channels. The size of channels = 3
    channels.push_back(mask);   // Adds mask(alpha) channel. The size of channels = 4
    
    // 5. Merging
    Mat dst;
    merge(channels, dst);   // dst is created with 4-channel(BGRA).
    // Note that OpenCV applies BGRA by default if your array size is 4,
    // even if actual order is different. In this case this makes sense.
    
    // 6. Saving
    imwrite("yourImagePath/yourDstImage.png", dst);   // Used PNG format for preserving ALPHA channel
    

    【讨论】:

    • 感谢您的好意回答!我试过但失败了。 T_T 我在我的问题中编写了编辑代码。我昨天看到一些博客如何使用 Photoshop 的 alpha 通道。有人说当他们用 alpha 通道保存图像时,背景变成白色不透明。有人说当用户保存图像 *.tga 格式时会发生这种情况。所以我想,Android Bitmap 对象可能有类似的问题。您如何看待这种方法?
    • @beginner 我不知道你是怎么从 Bitmap 转换到 Mat 的,可能有一些格式转换问题。我认为您删除了 RED 频道而不是 ALPHA 频道。您是否在从位图解析后检查了原始位图?试试 bgra.remove(0); bgra.add(alpha, 0);
    • @beginner 另外,灰度转换代码没有改变。将 Imgproc.COLOR_BGR2GRAY 替换为 Imgproc.COLOR_BGRA2GRAY
    • @beginner 实际上我只将 OpenCV 用于 C++。我将在我的答案中添加 C++ 版本代码。
    • 我改成 COLOR_BGRA2GRAY 但还是一样。但我想通了一件事。在我将 ImageView 设置为输出位图之前,我像您一样将位图保存到文件(*.png)。并且文件图像的背景是透明的!所以也许这不是opencv的问题,而是android的问题。
    猜你喜欢
    • 2018-07-18
    • 2018-07-26
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-02
    • 2016-04-09
    相关资源
    最近更新 更多