"In the long run we are all dead."

引言

  这学期开了数字图像处理,然而是用Matlab。正好实验室有树莓派,又正好最近我在树莓派上装了OpenCV,又为什么不用OpenCV写个图像处理呢。显然我不是 A.东湖校区图书馆原住民 B.海大全科免修特招生 C.海南数模双冠王 中的任何一个,只能来写一点今天课上刚学的东西罢。

Roberts算子

  最简单的一阶微分算子,2X2卷积核模板,具有良好的边缘提取能力。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import cv2
import numpy as np
img = cv2.imread('C:/Users/R8314/Desktop/gz.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)

img_roberts_x = cv2.filter2D(img_gray, cv2.CV_16S, kernelx)
img_roberts_y = cv2.filter2D(img_gray, cv2.CV_16S, kernely)

img_roberts_x = cv2.convertScaleAbs(img_roberts_x)
img_roberts_y = cv2.convertScaleAbs(img_roberts_y)
img_roberts = cv2.addWeighted(img_roberts_x, 0.5, img_roberts_y, 0.5, 0)

cv2.imshow('img', img_roberts)
cv2.waitKey(0)

python实现

Prewitt算子

  Prewitt算子是构造了一种3X3的卷积核模板,其中在垂直方向上对第一和第三列,在水平方向上对第一和第三行分别进行差分运算,最后再进行图像卷积。学过高数的我们都知道这种一阶差分运算是对一阶偏导的近似,这种算子也都可以看做是一种非加权的微分算子运算。
  两种卷积核模板

在Python中可以使用NumPy来构造任意卷积核,所以很方便就可以实现Prewitt算子的运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import cv2
import numpy as np
img = cv2.imread('C:/Users/R8314/Desktop/tieo.bmp')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

kernelx = np.array([[-1,-1,-1],[0,0,0],[1,1,1]],dtype=int)
kernely = np.array([[1,0,-1],[1,0,-1],[1,0,-1]],dtype=int)

img_prewittx = cv2.filter2D(img_gray, cv2.CV_16S, kernelx)
img_prewitty = cv2.filter2D(img_gray, cv2.CV_16S, kernely)

img_prewittx = cv2.convertScaleAbs(img_prewittx)
img_prewitty = cv2.convertScaleAbs(img_prewitty)

img_prewitt = cv2.addWeighted(img_prewittx, 0.5, img_prewitty, 0.5, 0)


cv2.imshow('image',img_prewitt)
cv2.waitKey(0)

使用C++复现嘿呀之前忘记有溢出了捏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc.hpp>
using namespace cv;
int main();
int Prewitt(Mat indImg, int x, int y);
int main()
{
Mat img = imread("C:\\Users\\R8314\\Desktop\\tieo.bmp");
Mat img_gray;
cvtColor(img, img_gray, COLOR_RGB2GRAY);
int maxOne = img_gray.rows > img_gray.cols ? img_gray.rows : img_gray.cols;
Mat img_new = Mat::zeros(img_gray.rows, img_gray.cols, CV_8U);
Mat img_regray = Mat::zeros(maxOne, maxOne, CV_8U);
Rect img_area = Rect(0, 0, img_gray.cols, img_gray.rows);
img_gray.copyTo(img_regray(img_area));
for (int i = 1; i < img_gray.cols - 1; i++) {
for (int j = 1; j < img_gray.rows - 1; j++) {
img_new.at<uchar>(j, i) = Prewitt(img_regray, j, i);
}
}
imshow("image", img_new);
waitKey(0);
}
int Prewitt(Mat indImg, int x, int y) {
int Prewitt_x = (indImg.at<uchar>(x + 1, y - 1) + indImg.at<uchar>(x + 1, y) + indImg.at<uchar>(x + 1, y + 1)) - (indImg.at<uchar>(x - 1, y - 1) + indImg.at<uchar>(x - 1, y) + indImg.at<uchar>(x - 1, y + 1));
int Prewitt_y = (indImg.at<uchar>(x - 1, y + 1) + indImg.at<uchar>(x , y + 1) + indImg.at<uchar>(x + 1, y + 1)) - (indImg.at<uchar>(x - 1, y - 1) + indImg.at<uchar>(x, y - 1) + indImg.at<uchar>(x + 1, y - 1));
int Prewitt_res = 0.5 * abs(Prewitt_x) + 0.5 * abs(Prewitt_y);
if (Prewitt_res > 255) {
Prewitt_res = 255;
}
return Prewitt_res;
}

使用两种方式实现的普威特算子的图像边缘检测效果
原图python实现c++实现

Sobel算子

  索贝尔算子是一种离散差分算子,计算方式与普威特算子相似,但索贝尔算子在普威特算子的基础上对像素位置的影响因数做了加权,可以降低图像边缘的模糊程度。
索贝尔算子3X3卷积核模板

opencv中专用的索贝尔算子构造函数,可以直接调用

1
2
3
4
5
6
7
8
9
10
11
import cv2

img = cv2.imread('C:/Users/R8314/Desktop/gz.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
sobel_x = cv2.Sobel(img_gray, cv2.CV_16S, 1, 0)
sobel_y = cv2.Sobel(img_gray, cv2.CV_16S, 0, 1)
sobel_x = cv2.convertScaleAbs(sobel_x)
sobel_y = cv2.convertScaleAbs(sobel_y)
sobel = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)
cv2.imshow('sobel', sobel)
cv2.waitKey(0)

c++实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc.hpp>
using namespace cv;
int main();
int Sobel(Mat indImg, int x, int y);
int main()
{
Mat img = imread("D:\\素材\\gz.png");
Mat img_gray;
cvtColor(img, img_gray, COLOR_RGB2GRAY);
int maxOne = img_gray.rows > img_gray.cols ? img_gray.rows : img_gray.cols;
Mat img_new = Mat::zeros(img_gray.rows, img_gray.cols, CV_8U);
Mat img_regray = Mat::zeros(maxOne, maxOne, CV_8U);
Rect img_area = Rect(0, 0, img_gray.cols, img_gray.rows);
img_gray.copyTo(img_regray(img_area));
for (int i = 1; i < img_gray.cols - 1; i++) {
for (int j = 1; j < img_gray.rows - 1; j++) {
img_new.at<uchar>(j, i) = Sobel(img_regray, j, i);
}
}
imshow("image", img_new);
waitKey(0);
}
int Sobel(Mat indImg, int x, int y) {
int Sobel_x = (indImg.at<uchar>(x + 1, y - 1) + 2 * indImg.at<uchar>(x + 1, y) + indImg.at<uchar>(x + 1, y + 1)) - (indImg.at<uchar>(x - 1, y - 1) + 2 * indImg.at<uchar>(x - 1, y) + indImg.at<uchar>(x - 1, y + 1));
int Sobel_y = (indImg.at<uchar>(x - 1, y + 1) + 2 * indImg.at<uchar>(x, y + 1) + indImg.at<uchar>(x + 1, y + 1)) - (indImg.at<uchar>(x - 1, y - 1) + 2 * indImg.at<uchar>(x, y - 1) + indImg.at<uchar>(x + 1, y - 1));
int Sobel_res = 0.5 * abs(Sobel_x) + 0.5 * abs(Sobel_y);
if (Sobel_res > 255) {
Sobel_res = 255;
}
return Sobel_res;
}

python实现c++实现

Isotropic-Sobel算子

加权平均后的索贝尔算子,3X3卷积核模板:

对视频进行边缘提取

  有点原画的感觉