background

One recent weekend, a girl asked me to change the background of her photo id, and I didn’t have my computer with me. I’m too embarrassed to refuse. What should I do? The APP store downloaded an APP to change the background of the id photo, which was changed in an instant. When I was ready to save it, a payment box popped up. If you want to save it, you should pay 2 yuan. So I thought, this kind of skill, pay someone else, masturbate yourself. I am a full-time Android developer, so just use Android to masturbate.

Let’s take a look at the Android native API for image operation. There are generally two ways.

  1. One is to draw pictures with Canvas.
  2. One is to use Bitmap’s native API to take pixels for manipulation

I have written corresponding articles for both operations, which can be quickly reviewed

  • Android: Let your “goddess” reverse attack, code makeup (makeup)
  • Android: Code Wanpai makeup 2 (big eyes, thin face, big legs)

Today’s topic is to use OpenCv to manipulate images in Android, and achieve two different effects, change the id photo background and blot repair.

The code is already hosted on Github, with the same address as the last two articles, branching with-photo-changecolor

Github, if you like, welcome star thank you

Android OpenCv quick start

Environment set up

The native API is limited to the operation of pictures, and some color space conversion trouble, low efficiency, then we use a professional picture operation library to operate pictures, will become easier.

OpenCv has many language versions, of course, the bottom is C/C ++, it supports Android/IOS, Windows, Mac, etc., we directly choose the Android version. So to set up the environment, there are two steps

  • Download the OpenCv SDKaddressPackage the SDK into AN AAR and integrate it into the project. The AAR can be obtained quickly and directly from the package I madeGithubThe aar package is easy, use Android Studio to open the downloaded SDK, then go to its directory and run the./ Gradlew assembleRelease or use the auxiliary tools on the side
  • Integrate into the project you want to use OpenCv as follows

Image grayscale test

After the integration is complete, the OpenCV SDK access is successfully tested

private void initLoaderOpenCV(a) {
        boolean success = OpenCVLoader.initDebug();
        if(! success) { Log.d(TAG,"Initialization failed"); }}public void gray(View view) {
        Mat src = new Mat();
        Mat dst = new Mat();
        Utils.bitmapToMat(bitmap, src);
        Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGRA2GRAY);
        Bitmap resultBitmap = getResultBitmap();
        Utils.matToBitmap(dst, resultBitmap);
        src.release();
        dst.release();

        showCompare(resultBitmap);
}
Copy the code

If the access is ok, you can happily use OpenCV, is not very simple.

Change background of id photo (from blue to red)

Change documents according to the algorithm, directly used a c++ version of the algorithm, translated into Android. C++ article address

Main steps:

  1. Convert RGB images to HSV space
  2. Calculate the average hue and saturation of the blue background by taking a small piece of the background 20*20
  3. Set the threshold and replace the blue background with the red one
  4. Convert HSV images into RGB space
  5. Filter to remove edge effect

The Android code is as follows:

 private void startDetail(a) {
        Mat image = new Mat();
        Utils.bitmapToMat(bitmap, image);

        Mat hsvImg = new Mat();
        Imgproc.cvtColor(image, hsvImg, Imgproc.COLOR_BGR2HSV);
        List<Mat> list = new ArrayList<>();
        Core.split(hsvImg, list);

        Mat roiH = list.get(0).submat(new Rect(0.0.20.20));
        Mat roiS = list.get(1).submat(new Rect(0.0.20.20));

        Log.i(TAG,"start sum bg");
        int SumH = 0;
        int SumS = 0;
        byte[] h = new byte[1];
        byte[] s = new byte[1];
        // Take a blue background and calculate its average hue and average saturation
        for (int i = 0; i < 20; i++) {
            for (int j = 0; j < 20; j++) {
                roiH.get(j, i, h);
                roiS.get(j, i, s);

                SumH = h[0] + SumH;
                SumS = s[0] + SumS; }}int avgH, avgS;// The average hue and saturation of blue background
        avgH = SumH / 400;
        avgS = SumS / 400;
        
        Log.i(TAG,"depth="+list.get(0).depth());
        Log.i(TAG,"start sum detail all photo");
        // Walk through the image
        int nl = hsvImg.height();
        int nc = hsvImg.width();
// byte[] changeColor = new byte[]{127};

        byte[] hArray = new byte[nl * nc];
        byte[] sArray = new byte[nl * nc];
        byte[] vArray = new byte[nl * nc];

        list.get(0).get(0.0,hArray);
        list.get(1).get(0.0,sArray);
/ / list. Get (2). The get (0, 0, varrays);

        int row,index;
        for (int j = 0; j < nl; j++) {
            row = j * nc;
            for (int i = 0; i < nc; i++) {
                index = row + i;

                if(hArray[index] <= (avgH + 20) && hArray[index] >= (avgH - 20)
                        && sArray[index] <= (avgS + 150)
                        && sArray[index] >= (avgS -150)
                ){
                    hArray[index] = 127;
// sArray[index] = 0;
// vArray[index] = (byte) 255;
                }
            }
        }

        list.get(0).put(0.0,hArray);
        list.get(1).put(0.0,sArray);
/ / list. Get (2). The put (0, 0, varrays);


        Log.i(TAG,"merge photo");
        Core.merge(list,hsvImg);

        Imgproc.cvtColor(hsvImg,image, Imgproc.COLOR_HSV2BGR);

        Bitmap resultBitmap = getResultBitmap();
        Utils.matToBitmap(image,resultBitmap);
        Message obtain = Message.obtain();
        obtain.obj = resultBitmap;
        handler.sendMessage(obtain);
    }
Copy the code

Mat saves images in OpenCV, which is similar to Bitmap in Android. It and Bitmap should be converted by OpenCV Utils

The effect

Stain repair

Repair principle

First, let’s talk about the algorithm of stain repair, An ImageInpainting Technique Based On the Fast Marching Method mentioned in a paper.

It can be simply understood as p point is the area to be repaired, and ε is the radius of repair. The value of the value region of ε is calculated and used to repair P point until the entire ω region is repaired.

Details can be seen in the paper: Paper address

The actual repair

OpenCV has implemented this algorithm, the specific method is as follows:

//OpenCV Photo.java
 /**
     * Restores the selected region in an image using the region neighborhood.
     *
     * @param src Input 8-bit, 16-bit unsigned or 32-bit float 1-channel or 8-bit 3-channel image.
     * @param inpaintMask Inpainting mask, 8-bit 1-channel image. Non-zero pixels indicate the area that
     * needs to be inpainted.
     * @param dst Output image with the same size and type as src .
     * @param inpaintRadius Radius of a circular neighborhood of each point inpainted that is considered
     * by the algorithm.
     * @paramflags Inpainting method that could be cv::INPAINT_NS or cv::INPAINT_TELEA * * The function reconstructs the selected image area from the pixel near the area boundary. The * function may be used to remove dust and scratches from a scanned  photo, or to remove undesirable * objects from still images or video. See &lt; http://en.wikipedia.org/wiki/Inpainting&gt; for more details. * * <b>Note:</b> * <ul> * <li> * An example using the inpainting technique can be found at * opencv_source_code/samples/cpp/inpaint.cpp * </li> * <li> * (Python) An example using the inpainting technique can be found at * opencv_source_code/samples/python/inpaint.py * </li> * </ul> */
    public static void inpaint(Mat src, Mat inpaintMask, Mat dst, double inpaintRadius, int flags) {
        inpaint_0(src.nativeObj, inpaintMask.nativeObj, dst.nativeObj, inpaintRadius, flags);
    }
Copy the code

The principle algorithm mentioned above is INPAINT_TELEA.

Let’s fix this with an actual graph operation, as follows:

      private void startInpaint(a) {
        bitmap = BitmapUtils.getBitmapByAssetsNameRGB(this."test.png");
        Mat desc = new Mat(bitmap.getHeight(),bitmap.getWidth(),CvType.CV_8UC3);
        // Convert to mat object
        Utils.bitmapToMat(bitmap, desc,true);
        // Convert to a 3-channel image
        Mat src = new Mat();
        Imgproc.cvtColor(desc,src,Imgproc.COLOR_RGBA2RGB);
        // Grayscale image
        Mat srcGray = new Mat();
        Imgproc.cvtColor(src, srcGray, Imgproc.COLOR_RGB2GRAY);
        // Median filter
        Imgproc.medianBlur(srcGray,srcGray,3);
        // Get a binary image of the stain
        Mat srcThresh = new Mat();
        Imgproc.threshold(srcGray,srcThresh,242.255,Imgproc.THRESH_BINARY);

        Log.i("test"."srcThresh channels:"+srcThresh.channels() + ",type:"+ CvType.typeToString(CvType.depth(srcThresh.type())));
        Log.i("test"."src channels:"+src.channels() + ",type:"+ CvType.typeToString(CvType.depth(src.type())));
// Bitmap resultBitmap = getResultBitmap();
// Utils.matToBitmap(srcThresh, resultBitmap);
        
        // Fix the image
        Mat inpaintResult = new Mat();
        Photo.inpaint(src,srcThresh,inpaintResult,3,Photo.INPAINT_TELEA);
        // Convert the result into a bitmap for display
        Bitmap resultBitmap = getResultBitmap();
        Utils.matToBitmap(inpaintResult, resultBitmap);
        Message obtain = Message.obtain();
        obtain.obj = resultBitmap;
        handler.sendMessage(obtain);
    }
Copy the code

The effect

Photo: www.cnblogs.com/hellowooorl…

conclusion

This article mainly introduces how to use OpenCV quickly, and combined with two practical examples, to further illustrate the use of OpenCV API, can achieve a lot of good effects.

Article picture source network, if infringement, please contact the author, immediately delete!

The code address for the two examples in this article is Github, and if you like star, any subsequent actions on images will be updated there.

Recommended reading

Android: Make your “goddess” retrofit, code to create a Flutter PIP effect.