The journal addresses

  1. IOS implements string animation
  2. Ios-opencv CAI Xukun teaches you how to play border painting

preface

I’ve already written the second article in this series, so this series will turn into a series, and I’ll update it whenever I discover something new.

Demo address: github.com/chouheiwa/O…

The body of the

Now a lot of interesting examples of OpenCV are in Python.

The whole idea of this article comes from zhihu Maker Bi’s article: CAI Xukun teaches you how to use OpenCV to achieve sketch effect

In the last article we talked about image storage and related information. This article will not be repeated, if not very clear readers can look at the first article.

This article is a sketch, in fact, and broad sketch gap is very large, accurately said should be called frame painting.

Let’s start with the effect picture.

Doesn’t that look like fun

Steps and Principles

So again, we’re going to go through the process, and I’m going to show you the original picture

1. Transform the given picture to grayscale image

Converted to grayscale image process is to eliminate other factors (this step is also a lot of image processing | the first step in character recognition, etc).

I’m going to take the picture from three dimensions down to one.


- (UIImage *)grayImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat gray;
    // Convert the image to grayscale display
    cv::cvtColor(cvImage, gray, CV_RGB2GRAY);

    cvImage.release();
    // Convert grayscale image to UIImage
    UIImage *nImage = MatToUIImage(gray);

    gray.release();

    return nImage;
}
Copy the code

After processing, we can see the original Teacher CAI turned grey.

2. Gaussian blur the grayscale image

First of all, how do you do a simple blur

As we discussed in the last article, an image is really just a two-dimensional array.

So every pixel on the picture has a pixel value.

We can take an n by n matrix centered on the current pixel.

Here, it is assumed that we select a pixel with a central gray value of 190, and its surrounding pixels have a 3*3 pixel matrix with a gray value of 100(255 is pure white)

The simple form of fuzzy processing is to average, that is, to average the gray values of the pixels in the middle point and the surrounding 8 pixels. So 100 times 8 plus 190 divided by 9 is 110

Simple fuzzy processing is to do so, but gaussian blur is through the Gaussian function to carry out the corresponding calculation, here I found a quite good article: Gaussian blur

- (UIImage *)gaussianblurImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat blur;
    // Select a 5 * 5 core for blur
    cv::GaussianBlur(cvImage, blur, cv::Size(5.5), 0);
    cvImage.release();
    UIImage *blurImage = MatToUIImage(blur);
    blur.release();

    return blurImage;
}
Copy the code

There is a vague Teacher CAI appeared

3. Perform adaptive binarization processing on the image

This step is really about binarization, and it’s a very simple concept. We compare the gray value of a pixel point on the grayscale map with a given value. The gray value less than the given value is set as 0(black), and the gray value greater than 255(white). The comparison values we give are called thresholds

Of course, this kind of binary transformation is too solidified and rigid. Because the real photo may be blocked by shadows, it will lead to our global binarization, resulting in a lot of errors, as shown in the upper right corner of the figure below:

Therefore, we need to adopt adaptive binarization. Here, we choose adaptive Gaussian binarization (the effect is shown in the lower right corner of the figure above).

- (UIImage *)adaptiveThresholdImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat outImage;

    cv::adaptiveThreshold(cvImage, outImage,
                          255,
                          cv::ADAPTIVE_THRESH_GAUSSIAN_C, // Here we use Gaussian adaptive blur
                          cv::THRESH_BINARY, / / binarization
                          5.2);

    cvImage.release();

    UIImage *adaImage = MatToUIImage(outImage);

    outImage.release();

    return adaImage;
}
Copy the code

The line of Teacher CAI appears

4. Binary image blur again

Now teacher CAI’s clothes have become lines, the basic stroke effect has been achieved. But we can see that in the image, for example, on the ground, there are some black dots (we call these noises) that we don’t want. And Ms CAI’s lines are still a little thin, so we need to make Ms CAI’s lines thicker.

Apply gaussian blur to the image above again.

Teacher CAI becomes blurred

5. Binarize the blurred image again

Here we do the binarization again, because the image is now relatively clean and free of shadows and other distractions. We can directly use global binarization to deepen borders (fast calculation).

- (UIImage *)thresholdImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);

    cv::Mat outImage;
    // Since the image is already clean and there is no shadow, choose normal binarization and assign 255(white) to gray > 200 (this value can be adjusted, I think 220 works better)
    cv::threshold(cvImage, outImage, 200.255, cv::THRESH_BINARY);

    cvImage.release();

    UIImage *threImage = MatToUIImage(outImage);

    outImage.release();

    return threImage;
}
Copy the code

6. Remove the noise of the picture

Now we need to remove the small noise in the image, we need to do a series of operations

We have a term for these operations in image processing:

Corrosion and expansion

corrosion:

Corrosion, in popular terms, is to reduce the original image according to a given core (a shape we define ourselves, generally n* N square, n is odd).

We only retain the value of the current core if all points around the corresponding core have values on the original image.

inflation:

Dilation is the opposite, we zoom in on a given picture with a given nucleus.

When we scan the core for a value at any point, the current core point will be assigned a value

Corrosion and expansion are key to this process.

The combination between them is what we call open and closed operations

Open operation

We do the corrosion operation on the picture first, then we do the expansion operation

The end result will look like the result in the lower left corner of the image above

Let’s compare it to the original image.

The open operation removes burrs, Bridges and isolated dots (which disappear directly in the corrosion operation). Eventually the total position and shape will remain the same (the expansion operation will be restored)

Close your operation

I’m not going to go over closed operations because we’re not going to use them.

Contrary to the process of open operation, the original image is expanded first and then corroded.

Our purpose is to deal with some noise in the picture, so we use the operation algorithm to deal with.

- (UIImage *)morphologyImage:(UIImage *)image {
    cv::Mat cvImage;

    UIImageToMat(image, cvImage);
    // Invert the image, the original black to white, the original white to black
    cv::bitwise_not(cvImage, cvImage);

    cv::Mat outImage;
    // get a 3*3 core
    cv::Mat ken = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3.3));
    /// Perform the open operation on the image (the open operation needs to shrink the areas with values, so we need to reverse the color of the image, that is, most of the images have values, and some do not, to achieve the effect)
    cv::morphologyEx(cvImage, outImage, cv::MORPH_OPEN, ken);

    ken.release();

    cvImage.release();

    cv::bitwise_not(outImage, outImage);

    UIImage *morphologyImage = MatToUIImage(outImage);

    outImage.release();

    return morphologyImage;
}
Copy the code

The picture is much cleaner

7. Perform a final Gaussian blur

We finally did a Gaussian blur to make our image look better.

other

Video conversion, I won’t write more here (in the process of research…)

The corresponding demo of this article please click on the website, if you think it is good, please feel free to hit me with your star.

At the end

The graphics are very interesting and high end at the same time.

If you have any questions or questions, please follow my official account and ask questions. As long as you see the first reply, you can also directly on Github to mention the issue.

My blog site