Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Python OpenCV 365 day learning plan, enter the graphics realm with eraser. This blog is the 47th in the series.

Learned in the previous

In Canny edge extraction related knowledge learning, image processing 32nd blog this blog, we have carried on the basic study of Canny edge detection, today this article is mainly used to supplement it, of course, the knowledge is not difficult, can learn in 1 hour.

Canny edge detection process

Refer to the most published process on the Internet

  1. Gaussian fuzzy denoising;
  2. To calculate the amplitude and direction of image gradient, Sobel operator is generally used here.
  3. Non-maximum suppression, simply understood as “thin edge”;
  4. Double threshold detection, also known as lag threshold.

Follow the above steps to translate, you can write a Simple Case of Canny

import cv2 as cv
import numpy as np

src = cv.imread("./t7.jpg".0)
# Gaussian blur
gaussian = cv.GaussianBlur(src, (3.3), 0)
ret, thresh = cv.threshold(gaussian, 0.255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# Calculate the amplitude and direction of image gradient, Sobel operator is generally used here;
sobel_x = cv.Sobel(thresh, cv.CV_16SC1, 1.0)
sobel_y = cv.Sobel(thresh, cv.CV_16SC1, 0.1)
sobel_x = cv.convertScaleAbs(sobel_x)
sobel_y = cv.convertScaleAbs(sobel_y)
sobel_xy = cv.addWeighted(sobel_x, 0.5, sobel_y, 0.5.0)

canny1 = cv.Canny(sobel_xy, 50.150)

image = np.hstack((thresh, canny1))
cv.imshow('img', image)
cv.waitKey(0)
cv.destroyAllWindows()
Copy the code

Some points to note in the code, double threshold detection uses high and low threshold detection, and high threshold is usedmaxVal, low threshold usageminValThere are the following conclusions.

  1. Gradient value > maxVal, boundary retained;
  2. MinVal < gradient value < maxVal, if the pixel gradient value is on the boundary, keep, otherwise, discard;
  3. The gradient value < minVal is discarded.

The plain English of the above three points is very easy to remember. If you want more boundaries, turn the minVal value down, otherwise turn it up.

In practice, we also try to find a problem. If the binarization operation is carried out before edge extraction, the image obtained is less affected by the above parameters. For example, in the following code, different values of the double threshold are set, and the results obtained are basically unchanged.

import cv2 as cv
import numpy as np

src = cv.imread("./t77.jpg".0)
# Gaussian blur
gaussian = cv.GaussianBlur(src, (3.3), 0)
ret, thresh = cv.threshold(gaussian, 0.255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# Calculate the amplitude and direction of image gradient, Sobel operator is generally used here;
sobel_x = cv.Sobel(thresh, cv.CV_16SC1, 1.0)
sobel_y = cv.Sobel(thresh, cv.CV_16SC1, 0.1)
sobel_x = cv.convertScaleAbs(sobel_x)
sobel_y = cv.convertScaleAbs(sobel_y)
sobel_xy = cv.addWeighted(sobel_x, 0.5, sobel_y, 0.5.0)

canny1 = cv.Canny(sobel_xy, 10.30)
canny2 = cv.Canny(sobel_xy, 30.90)
canny3 = cv.Canny(sobel_xy, 50.150)
image = np.hstack((canny1, canny2,canny3))
cv.imshow('img', image)
cv.waitKey(0)
cv.destroyAllWindows()

Copy the code

If the binarization is removed, there is a significant difference between the image edges. Now I understand why there is no binarization step in explaining the Canny edge extraction step just now, which seems to be superfluous.

# Gaussian blur
gaussian = cv.GaussianBlur(src, (3.3), 0)
# ret, thresh = cv.threshold(gaussian, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
# Calculate the amplitude and direction of image gradient, Sobel operator is generally used here;
Copy the code

There is also a small problem, when testing, using the following two pieces of code to get the edge is inconsistent, as follows, you can test separately. The difference lies in that method 1 calculates the gradient of x direction and y direction respectively through Sobel operator, and uses the merged image to detect Canny edge, and the edge obtained is double line. Method 2 has better and ideal effect.

Method # 1
import cv2 as cv
import numpy as np

src = cv.imread("./t77.jpg".0)
# Gaussian blur
gaussian = cv.GaussianBlur(src, (3.3), 0)

# Calculate the amplitude and direction of image gradient, Sobel operator is generally used here;
sobel_x = cv.Sobel(gaussian, cv.CV_16SC1, 1.0)
sobel_y = cv.Sobel(gaussian, cv.CV_16SC1, 0.1)
sobel_x = cv.convertScaleAbs(sobel_x)
sobel_y = cv.convertScaleAbs(sobel_y)
sobel_xy = cv.addWeighted(sobel_x, 0.5, sobel_y, 0.5.0)


canny1 = cv.Canny(sobel_xy, 50.150)
# canny2 = cv.Canny(sobel_x,sobel_y, 50, 150)
image = np.hstack((gaussian, canny1))
cv.imshow('img', image)
cv.waitKey(0)
cv.destroyAllWindows()


### 方法2
import cv2 as cv
import numpy as np

src = cv.imread("./t77.jpg".0)
# Gaussian blur
gaussian = cv.GaussianBlur(src, (3.3), 0)

# Calculate the amplitude and direction of image gradient, Sobel operator is generally used here;
sobel_x = cv.Sobel(gaussian, cv.CV_16SC1, 1.0)
sobel_y = cv.Sobel(gaussian, cv.CV_16SC1, 0.1)

canny2 = cv.Canny(sobel_x, sobel_y, 50.150)
image = np.hstack((gaussian, canny2))
cv.imshow('img', image)
cv.waitKey(0)
cv.destroyAllWindows()
Copy the code

It is a pity that non-maximum inhibits the learning of relevant knowledge, which needs to be postponed for a while. The current knowledge reserve is not enough, so it is difficult to learn. We will see you later.

Eraser section

I hope you learned something from today’s hour, and I’ll see you in the next blog