Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make white part of the image transparent by using Android opencv

I can't link url more than 2 so I post my pictures to this blog. please see my problems here. http://blog.naver.com/mail1001/220650041897

I want to know how to make white part of the image, which is white paper with writing on it, transparent by using Android opencv.

I have studied through url(I wrote it on blog) which makes the black background transparent, and I think "Alpha Channel" has something to do with it.

I think it will work as I make Alpha Channel by making the part I want to make transparent black and the other part white, and merge this Alpha Channel to the original RGB Channel.

So I made two experiments.

1) I made the papaer part black and the writing part white to make the Alpha Channel. And merged it to RGB Channel.

(Please see blog. Experiment 1's alpha channel picture)

I thought the writing should be the same and the background should be transparent, but the background only turned to white and little transparent.

(Please see blog. Experiment 1's result picture)

2) This time, the paper part is white and the writing part is black. But this time only writing turned to transparent.

(Please see blog. Experiment 2's alpha channel picture and result picture)

In the second experiment, what I meant to make transparent turned transparent but it did not work the same in the first experiment.

Which part am I doing wrong? Is there any concept I understand wrongly?

This is source what I tested.

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;
}

Thank you for your kindness answer.

I tried it but it was same Experiment 1's result picture. T_T

Edit code

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;
}
like image 450
beginner Avatar asked Sep 25 '22 03:09

beginner


1 Answers

There are several problems in your code.
I guess both case went wrong but second case was just lucky to pretend success.
The reason why the second case seems to work fine is that the fonts are mostly black.
Have a close look at the heart(red) image, and you can find that second case has failed, too.
(It might not been lucky to you, if both case failed you could immediately notice the problem :))

1.You're using tmp(gray) and alpha Mat with CV_8UC4.
gray and alpha channel only needs 1 byte per pixel, so change them to 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.Color types are confusing
src Mat and tmp Mat are initialized with CV_8UC4 and you're converting src to tmp with conversion code: COLOR_BGR2GRAY.
OpenCV converts the matrix even though actual color type doesn't match with conversion code, so you MUST sync them in order to make sense.

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


3.Splitting and Merging
your src is 4-channel and you split it into 3.
I don't know how OpenCV works in such a situation, but I strongly suggest you to match channels.

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);



ADDED : C++ version Source Code
Hope this helps.

// 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
like image 149
Suhyeon Lee Avatar answered Nov 26 '22 23:11

Suhyeon Lee